Merge lp:~nuclearbob/utah/consolidate-scripts into lp:utah

Proposed by Max Brustkern
Status: Merged
Approved by: Javier Collado
Approved revision: 922
Merged at revision: 881
Proposed branch: lp:~nuclearbob/utah/consolidate-scripts
Merge into: lp:utah
Prerequisite: lp:~nuclearbob/utah/cleanup-cleanup
Diff against target: 1559 lines (+257/-849) (has conflicts)
19 files modified
debian/changelog (+11/-0)
debian/utah.manpages (+0/-3)
docs/source/conf.py (+1/-9)
docs/source/man/run_install_test.py.rst (+0/-26)
docs/source/man/run_test_cobbler.py.rst (+0/-26)
docs/source/man/run_test_vm.py.rst (+0/-26)
examples/run_install_test.py (+0/-114)
examples/run_test_bamboo_feeder.py (+0/-119)
examples/run_test_cobbler.py (+0/-127)
examples/run_test_vm.py (+0/-115)
examples/run_utah_tests.py (+146/-57)
tests/test_run.py (+4/-3)
utah/config.py (+28/-9)
utah/provisioning/baremetal/bamboofeeder.py (+7/-10)
utah/provisioning/baremetal/cobbler.py (+2/-2)
utah/provisioning/baremetal/power.py (+3/-3)
utah/provisioning/provisioning.py (+24/-46)
utah/provisioning/vm/vm.py (+14/-31)
utah/run.py (+17/-123)
Text conflict in debian/changelog
To merge this branch: bzr merge lp:~nuclearbob/utah/consolidate-scripts
Reviewer Review Type Date Requested Status
Javier Collado (community) Approve
Max Brustkern (community) Needs Resubmitting
Review via email: mp+160963@code.launchpad.net

This proposal supersedes a proposal from 2013-04-19.

Description of the change

This branch removes the scripts other than run_utah_tests.py and consolidates their functionality into run_utah_tests.py

It relies on the cleanup-cleanup branch to ensure that explicit destruction calls for machines are not necessary.

Principally, it moves command line handling back in run_utah_tests.py. The script is responsible for parsing the command line options and getting a Machine object (from an Inventory in all cases except --skip-provisioning) and then it hands that off to functions of run.py to run the tests and returns results.

Some try/catch stuff is simplified as well, since the number of possible paths should be reduced. I also cleaned up the handling of command line options/config options/defaults in a few cases, and moved some things around between the different types of Machine classes so that the arguments passed to the different Machine constructors could be more straightforward.

To post a comment you must log in.
Revision history for this message
Javier Collado (javier.collado) wrote : Posted in a previous version of this proposal

Documentation needs to be updated. In particular, the part in
`docs/source/conf.py` that takes care of the manpage generation of the scripts
that are now gone.

Aside from that, I think it would be a good idea to refactor the code in the
big if/elif/else to still have a function for each different provisioning case.

review: Needs Fixing
Revision history for this message
Andy Doan (doanac) wrote : Posted in a previous version of this proposal

should we keep the original scripts and just print an error, so people don't think dpkg failed or something?

Revision history for this message
Andy Doan (doanac) wrote : Posted in a previous version of this proposal

i agree about breaking out the if/else stuff.

Also it might be worth using context managers for the machine/inventory API's now that its in one spot. It could get rid of the destroy/del stuff?

Revision history for this message
Max Brustkern (nuclearbob) wrote : Posted in a previous version of this proposal

I'd like to see different provisioning methods, whether those are functions or not, that basically only consist of getting the inventory and machine objects. Everything else I'd like to see handled the same way, either in run_utah_test.py or run.py. I'll work on cleaning up the documentation, and I think if we can land this proposal:
https://code.launchpad.net/~doanac/utah/run-cleanups/+merge/159879
That'll put me in better shape to make the changes we've talked about in this branch.

Revision history for this message
Max Brustkern (nuclearbob) wrote : Posted in a previous version of this proposal

The documentation should be updated now. I'm pondering the best place for machine getting functions. Right now, each machine type only works with a single inventory type. Would it make sense to provide functions at the level of a Machine subclass or at an Inventory level that would parse some arguments and request a machine? Or maybe we should be pulling the Machine-specific stuff out of args to pass that in? I'm not sure.

Revision history for this message
Javier Collado (javier.collado) wrote : Posted in a previous version of this proposal

There still a few .rst files under docs/source/man that should be removed.

If you try to build the documentation you'll see some error messages because
those .rst files include the .txt file that was generated from the script help
output to generate the man page.

Regarding what should be the way to get a machine, I think a function or a
class method in the inventory module would be a good fit with how the code
works now.

review: Needs Fixing
Revision history for this message
Andy Doan (doanac) wrote :
Download full text (4.8 KiB)

On 04/25/2013 12:32 PM, Max Brustkern wrote:

> https://code.launchpad.net/~nuclearbob/utah/consolidate-scripts/+merge/160963

> === modified file 'examples/run_utah_tests.py'

> def get_parser():

looking these two snippets
1)
> + parser.add_argument('-a', '--arch', metavar='ARCH',
> + choices=('i386', 'amd64', 'arm'),
> + help=('Architecture to use for VM creation '
> + '(%(choices)s)'))

2)
> + if args.arch:
> + arch = args.arch
> + else:
> + arch = config.arch

You could just set the default value in argparse to config.arch and save
4 lines of code.

> + if args.machinetype:
> + machinetype = args.machinetype
> + else:
> machinetype = config.machinetype
> - else:
> - machinetype = args.machinetype

you could probably do the same with this as well by assigning the
default in the argparse.

> + else:
> + kw = {'clean': (not args.no_destroy),
> + 'new': True,
> + }
> + for arg in ['arch',
> + 'boot',
> + 'debug',
> + 'image',
> + 'initrd',
> + 'kernel',
> + 'name',
> + 'preseed',
> + 'rewrite',
> + 'series',
> + ]:
> + kw[arg] = getattr(args, arg)

this can be done explicityline and save two lines of code doing
something like:

  kw['arch'] = args.arch

and i think it might look more readable.

> + kw['installtype'] = args.type
> + if machinetype == 'physical':
> + if arch and 'arm' in arch:
> + inventory = ManualBaremetalSQLiteInventory(
> + db=os.path.join('~', '.utah-bamboofeeder-inventory'),
> + lockfile=os.path.join('~', '.utah-bamboofeeder-lock'))
> + kw['machinetype'] = BambooFeederMachine
> + else:
> + inventory = ManualBaremetalSQLiteInventory()
> + kw['machinetype'] = CobblerMachine
> + else:
> + inventory = TinySQLiteInventory()
> + for arg in ['diskbus', 'emulator', 'xml']:
> + kw[arg] = getattr(args, arg)
> + kw['disksizes'] = args.gigabytes
> + machine = inventory.request(**kw)

also - i think I'd break the whole block of "if args.skip_provisioning"
to here. into a utility function called something like:

  def _get_machine(args)

> if __name__ == '__main__':
> try:
> - try:
> - if isinstance(config.jobtimeout, int):
> - timeout(config.jobtimeout, run_utah_tests)
> - else:
> - run_utah_tests()
> - except AttributeError:
> - run_utah_tests()
> - finally:
> - cleanup.run()
> + exitstatus = timeout(getattr(config, 'jobtimeout', None),
> + run_utah_tests)

why the "getattr" - can't we ensure this will always be available by
providing a default in config.py?

> === modified file 'utah/provisioning/provisioning.py'

> - self...

Read more...

Revision history for this message
Max Brustkern (nuclearbob) wrote :
Download full text (6.4 KiB)

> On 04/25/2013 12:32 PM, Max Brustkern wrote:
>
> > https://code.launchpad.net/~nuclearbob/utah/consolidate-
> scripts/+merge/160963
>
> > === modified file 'examples/run_utah_tests.py'
>
> > def get_parser():
>
> looking these two snippets
> 1)
> > + parser.add_argument('-a', '--arch', metavar='ARCH',
> > + choices=('i386', 'amd64', 'arm'),
> > + help=('Architecture to use for VM creation '
> > + '(%(choices)s)'))
>
> 2)
> > + if args.arch:
> > + arch = args.arch
> > + else:
> > + arch = config.arch
>
> You could just set the default value in argparse to config.arch and save
> 4 lines of code.
>
There used to be some reason that didn't work, but I can't think of why now, so I'll try it.
> > + if args.machinetype:
> > + machinetype = args.machinetype
> > + else:
> > machinetype = config.machinetype
> > - else:
> > - machinetype = args.machinetype
>
> you could probably do the same with this as well by assigning the
> default in the argparse.
>
Ditto.
> > + else:
> > + kw = {'clean': (not args.no_destroy),
> > + 'new': True,
> > + }
> > + for arg in ['arch',
> > + 'boot',
> > + 'debug',
> > + 'image',
> > + 'initrd',
> > + 'kernel',
> > + 'name',
> > + 'preseed',
> > + 'rewrite',
> > + 'series',
> > + ]:
> > + kw[arg] = getattr(args, arg)
>
> this can be done explicityline and save two lines of code doing
> something like:
>
> kw['arch'] = args.arch
>
> and i think it might look more readable.
>
I'm interested in what everybody else thinks of this, since I find the repetition very unpleasant to look at. Every time I see it, I think "we could just do that to a whole list of things and then add things to the list and I'll never make an error copying and pasting the code."
> > + kw['installtype'] = args.type
> > + if machinetype == 'physical':
> > + if arch and 'arm' in arch:
> > + inventory = ManualBaremetalSQLiteInventory(
> > + db=os.path.join('~', '.utah-bamboofeeder-inventory'),
> > + lockfile=os.path.join('~', '.utah-bamboofeeder-lock'))
> > + kw['machinetype'] = BambooFeederMachine
> > + else:
> > + inventory = ManualBaremetalSQLiteInventory()
> > + kw['machinetype'] = CobblerMachine
> > + else:
> > + inventory = TinySQLiteInventory()
> > + for arg in ['diskbus', 'emulator', 'xml']:
> > + kw[arg] = getattr(args, arg)
> > + kw['disksizes'] = args.gigabytes
> > + machine = inventory.request(**kw)
>
> also - i think I'd break the whole block of "if args.skip_provisioning"
> to here. into a utility function called something like:
>
> def _get_machine(args)
>
That seems reasonable. I didn't do that initially because I didn't think we'd be using that function a...

Read more...

Revision history for this message
Andy Doan (doanac) wrote :

On 04/25/2013 05:39 PM, Max Brustkern wrote:
>>> + else:
>>> > >+ kw = {'clean': (not args.no_destroy),
>>> > >+ 'new': True,
>>> > >+ }
>>> > >+ for arg in ['arch',
>>> > >+ 'boot',
>>> > >+ 'debug',
>>> > >+ 'image',
>>> > >+ 'initrd',
>>> > >+ 'kernel',
>>> > >+ 'name',
>>> > >+ 'preseed',
>>> > >+ 'rewrite',
>>> > >+ 'series',
>>> > >+ ]:
>>> > >+ kw[arg] = getattr(args, arg)
>> >
>> >this can be done explicityline and save two lines of code doing
>> >something like:
>> >
>> > kw['arch'] = args.arch
>> >
>> >and i think it might look more readable.
>> >
> I'm interested in what everybody else thinks of this, since I find the repetition very unpleasant to look at. Every time I see it, I think "we could just do that to a whole list of things and then add things to the list and I'll never make an error copying and pasting the code."

Two things:

1) fair enough - this is mostly subjective so we should decide as a team

2) I think this is actually more of a symptom of a larger problem.
Having a constructor that takes in 18 parameters is a bit extreme. Its
possible what I'm going to say is beyond the scope of this MP, but think
about the two cases we are using the "attr" hacks:

a) to set parameters in the call to the constructor
b) to take the parameters from the constructor and make them member
variables.

Now also remember the fact that we default things not provided to args
with a value from config.py.

I can't help but wonder if we shouldn't just pass "args" to the
constructor instead. I don't really like the idea of using "args", but
it feels cleaner than insane constructors.

Doing that would clean up my complain about run_utah_tests.py. You could
go extreme and then just assign self.args = args in Machine.__init__.
That feels a little crazy - and would probably turn into a fairly
big/error-prone refactor.

Revision history for this message
Andy Doan (doanac) wrote :

On 04/25/2013 05:39 PM, Max Brustkern wrote:
>>> === modified file 'utah/run.py'
>> >
>>> > >- try:
>>> > >- shutil.copyfile(machine.finalpreseed, p)
>>> > >- except (IOError, shutil.Error) as err:
>>> > >- logging.warning('Failed to copy preseed file: %s', err)
>>> > >+ if machine.hasattr('finalpreseed'):
>> >
>> >do we really need hasattr instead of just doing machine.finalpreseed?
> I don't like explicitly checking for ProvisionedMachine, which is what we did before. I don't think run.py should know or care about what Machine subclass it's using. We could just do a try and catch the AttributeError, but that seems like it could open us up to other problems.

I didn't like the ProvisionedMachine check either and I see your point
now. I say keep it as is.

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

> On 04/25/2013 05:39 PM, Max Brustkern wrote:
> ...
> Two things:
>
> 1) fair enough - this is mostly subjective so we should decide as a team
>
Looks like your idea is preferred, so I implemented that.
> 2) I think this is actually more of a symptom of a larger problem.
> Having a constructor that takes in 18 parameters is a bit extreme. Its
> possible what I'm going to say is beyond the scope of this MP, but think
> about the two cases we are using the "attr" hacks:
>
> a) to set parameters in the call to the constructor
> b) to take the parameters from the constructor and make them member
> variables.
>
> Now also remember the fact that we default things not provided to args
> with a value from config.py.
>
> I can't help but wonder if we shouldn't just pass "args" to the
> constructor instead. I don't really like the idea of using "args", but
> it feels cleaner than insane constructors.
>
> Doing that would clean up my complain about run_utah_tests.py. You could
> go extreme and then just assign self.args = args in Machine.__init__.
> That feels a little crazy - and would probably turn into a fairly
> big/error-prone refactor.
I think this larger problem is better solved by separating installation, and probably coming up with a completely new interface. I think as part of that sorting out which arguments are used for installation, machine management, and test running might serve us well and allow us to pass those around in ways that make more sense.

Revision history for this message
Andy Doan (doanac) wrote :

On 04/26/2013 03:02 PM, Max Brustkern wrote:
> I think this larger problem is better solved by separating installation, and probably coming up with a completely new interface. I think as part of that sorting out which arguments are used for installation, machine management, and test running might serve us well and allow us to pass those around in ways that make more sense.

+1 - I hesitated to say that because its even more work :)

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

There are a few lines that have to be removed in:
debian/utah.manpages

to avoid generating manual pages for the scripts that have been removed.

review: Needs Fixing
878. By Javier Collado

Merged changes to fix DefaultValidator and updated schemas to draftv4 (LP: #1165175)

Source branch: lp:~javier.collado/utah/bug1165175

879. By Javier Collado

Merged changes to refactor cleanup for the machine class

Source branch: lp:~nuclearbob/utah/cleanup-cleanup

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

The exception handling in run_utah_tests.py has been updated so that the cleanup is executed after all exceptions are handled. The way it was written before, exceptions were handled just after the cleanup to make sure that error messages were printed at the bottom of the log file so that it was easy to know the error cause without having to read the log backwards and skip all the cleanup. I think I prefer that unless there's some other thing I'm missing. Please let me know your thoughts on this.

Aside from this, I see a few new default values have been added to command line parameters. Please consider adding those values to the help string via %(default)s, so that the user knows that values when passing -h/--help to run_utah_tests.py.

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

You have a good point about the finally for the cleanup. Does this look better to you:
if __name__ == '__main__':
    try:
        try:
            exitstatus = timeout(config.jobtimeout, run_utah_tests)
        finally:
            cleanup.run()
    except UTAHTimeout as exception:
        sys.stderr.write('UTAH timeout: {}\n'.format(exception.message))
        sys.exit(ReturnCodes.TIMEOUT_ERROR)
    except UTAHException as error:
        sys.stderr.write('UTAH exception: {}\n'.format(error))
        sys.exit(ReturnCodes.UTAH_EXCEPTION_ERROR)
    except Exception:
        sys.stderr.write('Unhandled error in UTAH:\n{}\n'
                         .format(''.join(format_exception(*sys.exc_info()))))
        sys.exit(ReturnCodes.UNHANDLED_ERROR)
    sys.exit(exitstatus)

As far as the default values, do you think I should add all of them, or just the ones that aren't inherited from config? It seems weird to have a default potentially dependent on environment variables, but since that's how we're processing things it makes sense.

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

Yes, that would look good to me.

Regarding default values, I was thinking about the ones that were newly added, but it's true that to be consistent lot of others default could be added as well. Maybe we should skip this for now, since I understand is out of the scope of this merge request.

918. By Max Brustkern

Moved cleanup before exception handling

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

When passing the -i/--image argument through the command line, I see that utah is trying to download the mini image instead of using the one that was passed as an argument.

review: Needs Fixing
919. By Max Brustkern

Updated help strings

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

Example output:
$ PYTHONPATH=. examples/run_utah_tests.py -i ~/download/distro/raring/raring-server-i386.iso utah/client/examples/pass.run -d -n
2013-05-01 11:02:30,082 root INFO: UTAH version: dev-r881~raring
2013-05-01 11:02:30,083 root DEBUG: Executing SQL statement: CREATE TABLE IF NOT EXISTS machines(machineid INTEGER PRIMARY KEY, state TEXT), [
]
2013-05-01 11:02:30,083 root DEBUG: Executing SQL statement: INSERT INTO machines (state) VALUES ('provisioned'), []
2013-05-01 11:02:30,259 utah-22 INFO: Attempting to retrieve raring-mini-amd64.iso
2013-05-01 11:02:30,266 utah-22 INFO: Download attempt 0
2013-05-01 11:02:30,284 utah-22 DEBUG: Server md5 is 69c919c499068b1681303130093f21cc
2013-05-01 11:02:30,284 utah-22 INFO: Attempting to download http://archive.ubuntu.com/ubuntu/dists/raring/main/installer-amd64/current/images
/./netboot/mini.iso
2013-05-01 11:02:30,320 utah-22 INFO: File 0% downloaded
2013-05-01 11:02:30,321 utah-22 DEBUG: 0 read, 0% of 36700160 total
2013-05-01 11:02:30,324 utah-22 DEBUG: 8192 read, 0% of 36700160 total

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

I moved cleanup and updated the help strings. I'll sort out the image thing, thanks for finding that.

920. By Max Brustkern

Fixed image handling typos

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

Fixed some dumb typos on the image thing.

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

When trying to provision a VM, I got the following traceback:

Unhandled error in UTAH:
Traceback (most recent call last):
  File "examples/run_utah_tests.py", line 216, in <module>
    exitstatus = timeout(config.jobtimeout, run_utah_tests)
  File "utah/timeout.py", line 65, in timeout
    return command(*args, **kw)
  File "examples/run_utah_tests.py", line 205, in run_utah_tests
    exitstatus, locallogs = run_tests(args, _get_machine(args))
  File "examples/run_utah_tests.py", line 187, in _get_machine
    machine = inventory.request(**kw)
  File "utah/provisioning/vm/vm.py", line 570, in request
    return machinetype(machineid=machineid, *args, **kw)
  File "utah/provisioning/vm/vm.py", line 173, in __init__
    self._namesetup()
  File "utah/provisioning/provisioning.py", line 208, in _namesetup
    self.name = self._makename()
  File "utah/provisioning/provisioning.py", line 238, in _makename
    machineid = str(self.machineid)
AttributeError: 'CustomVM' object has no attribute 'machineid'

review: Needs Fixing
921. By Max Brustkern

Fixed machineid not being set

922. By Max Brustkern

Fixed failure to chmod preseed when it doesn't exist, and fixed self tests

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

Working fine for me now. Thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2013-05-01 17:37:58 +0000
+++ debian/changelog 2013-05-01 21:24:29 +0000
@@ -14,9 +14,20 @@
14 * Make rsyslog timeout error message clearer (LP: #1169846)14 * Make rsyslog timeout error message clearer (LP: #1169846)
15 * Write to log UTAH version as soon as possible (LP: #1152216)15 * Write to log UTAH version as soon as possible (LP: #1152216)
16 * Fixed help output to use just one runlist (LP: #1112597)16 * Fixed help output to use just one runlist (LP: #1112597)
17<<<<<<< TREE
17 * Setup rc.local to use output passed via command line (LP: #1155615)18 * Setup rc.local to use output passed via command line (LP: #1155615)
19=======
20 * Combined current provisioning functions into one script and removed
21 old scripts
22 * Set permissions when copying preseed so overwrite works (LP: #1130901)
23 * Enabled reading power command from config (LP: #1153735)
24>>>>>>> MERGE-SOURCE
1825
26<<<<<<< TREE
19 -- Max Brustkern <max@canonical.com> Fri, 26 Apr 2013 13:58:25 -040027 -- Max Brustkern <max@canonical.com> Fri, 26 Apr 2013 13:58:25 -0400
28=======
29 -- Max Brustkern <max@canonical.com> Thu, 25 Apr 2013 11:02:23 -0400
30>>>>>>> MERGE-SOURCE
2031
21utah (0.10ubuntu1) UNRELEASED; urgency=low32utah (0.10ubuntu1) UNRELEASED; urgency=low
2233
2334
=== modified file 'debian/utah.manpages'
--- debian/utah.manpages 2012-08-31 15:36:31 +0000
+++ debian/utah.manpages 2013-05-01 21:24:29 +0000
@@ -1,4 +1,1 @@
1docs/build/man/run_install_test.py.1
2docs/build/man/run_test_cobbler.py.1
3docs/build/man/run_test_vm.py.1
4docs/build/man/run_utah_tests.py.11docs/build/man/run_utah_tests.py.1
52
=== modified file 'docs/source/conf.py'
--- docs/source/conf.py 2013-04-18 10:46:00 +0000
+++ docs/source/conf.py 2013-05-01 21:24:29 +0000
@@ -148,8 +148,7 @@
148148
149 return description, options, epilog149 return description, options, epilog
150150
151module_names = ('client', 'run_install_test', 'run_test_cobbler',151module_names = ('client', 'run_utah_tests')
152 'run_test_vm', 'run_utah_tests')
153for module_name in module_names:152for module_name in module_names:
154 module = __import__(module_name)153 module = __import__(module_name)
155 parser = module.get_parser()154 parser = module.get_parser()
@@ -367,13 +366,6 @@
367man_pages = [366man_pages = [
368 ('man/utah', 'utah', u'UTAH client test runner',367 ('man/utah', 'utah', u'UTAH client test runner',
369 [u'Canonical Ltd'], 1),368 [u'Canonical Ltd'], 1),
370 ('man/run_install_test.py', 'run_install_test.py',
371 u'UTAH server test runner (provisioning)', [u'Canonical Ltd'], 1),
372 ('man/run_test_cobbler.py', 'run_test_cobbler.py',
373 u'UTAH server test runner (physical hardware)', [u'Canonical Ltd'], 1),
374 ('man/run_test_vm.py', 'run_test_vm.py',
375 u'UTAH server test runner (virtual hardware)',
376 [u'Canonical Ltd'], 1),
377 ('man/run_utah_tests.py', 'run_utah_tests.py',369 ('man/run_utah_tests.py', 'run_utah_tests.py',
378 u'UTAH server test runner (any hardware)', [u'Canonical Ltd'], 1),370 u'UTAH server test runner (any hardware)', [u'Canonical Ltd'], 1),
379]371]
380372
=== removed file 'docs/source/man/run_install_test.py.rst'
--- docs/source/man/run_install_test.py.rst 2012-09-05 11:30:16 +0000
+++ docs/source/man/run_install_test.py.rst 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
1:orphan:
2
3run_install_test.py manual page
4===============================
5
6Synopsis
7--------
8**run_install_test.py** [options] [runlist ...]
9
10Description
11-----------
12.. include:: run_install_test_description.txt
13
14Options
15-------
16.. include:: run_install_test_options.txt
17
18Examples
19--------
20.. include:: run_install_test_epilog.txt
21
22See also
23--------
24:manpage:`run_test_cobbler.py(1)`
25:manpage:`run_test_vm.py(1)`
26:manpage:`run_utah_tests.py(1)`
270
=== removed file 'docs/source/man/run_test_cobbler.py.rst'
--- docs/source/man/run_test_cobbler.py.rst 2012-09-05 11:30:16 +0000
+++ docs/source/man/run_test_cobbler.py.rst 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
1:orphan:
2
3run_test_cobbler.py manual page
4===============================
5
6Synopsis
7--------
8**run_test_cobbler.py** [options] [runlist ...]
9
10Description
11-----------
12.. include:: run_test_cobbler_description.txt
13
14Options
15-------
16.. include:: run_test_cobbler_options.txt
17
18Examples
19--------
20.. include:: run_test_cobbler_epilog.txt
21
22See also
23--------
24:manpage:`run_install_test.py(1)`
25:manpage:`run_test_vm.py(1)`
26:manpage:`run_utah_tests.py(1)`
270
=== removed file 'docs/source/man/run_test_vm.py.rst'
--- docs/source/man/run_test_vm.py.rst 2012-09-05 11:30:16 +0000
+++ docs/source/man/run_test_vm.py.rst 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
1:orphan:
2
3run_test_vm.py manual page
4==========================
5
6Synopsis
7--------
8**run_test_vm.py** [options] [runlist ...]
9
10Description
11-----------
12.. include:: run_test_vm_description.txt
13
14Options
15-------
16.. include:: run_test_vm_options.txt
17
18Examples
19--------
20.. include:: run_test_vm_epilog.txt
21
22See also
23--------
24:manpage:`run_install_test.py(1)`
25:manpage:`run_test_cobbler.py(1)`
26:manpage:`run_utah_tests.py(1)`
270
=== removed file 'examples/run_install_test.py'
--- examples/run_install_test.py 2013-04-18 14:15:12 +0000
+++ examples/run_install_test.py 1970-01-01 00:00:00 +0000
@@ -1,114 +0,0 @@
1#!/usr/bin/env python
2
3# Ubuntu Testing Automation Harness
4# Copyright 2012 Canonical Ltd.
5
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Create a VM and run a test."""
19
20
21import argparse
22import logging
23import sys
24
25from utah.cleanup import cleanup
26from utah.exceptions import UTAHException
27from utah.group import check_user_group, print_group_error_message
28from utah.provisioning.vm.vm import CustomVM, TinySQLiteInventory
29from utah.run import (
30 common_arguments,
31 custom_arguments,
32 file_arguments,
33 run_tests,
34 virtual_arguments,
35 configure_logging,
36 ReturnCodes,
37)
38
39
40def get_parser():
41 parser = argparse.ArgumentParser(
42 description=('Provision a machine '
43 'and run one or more UTAH runlists there.'),
44 epilog=("For example:\n"
45 "Provision a VM using a precise server image "
46 "with i386 architecture and run the two given runlists\n"
47 "\t%(prog)s -s precise -t server -a i386 \\\n"
48 "\t\t/usr/share/utah/client/examples/master.run \\\n"
49 "\t\t'http://people.canonical.com/~max/max_test.run'"),
50 formatter_class=argparse.RawDescriptionHelpFormatter)
51 parser = common_arguments(parser)
52 parser = custom_arguments(parser)
53 parser = file_arguments(parser)
54 parser = virtual_arguments(parser)
55 return parser
56
57
58def run_install_test(args=None):
59 if args is None:
60 args = get_parser().parse_args()
61
62 if not check_user_group():
63 print_group_error_message(__file__)
64 sys.exit(ReturnCodes.GROUP_ERROR)
65
66 locallogs = []
67 exitstatus = ReturnCodes.SUCCESS
68 machine = None
69
70 configure_logging(args.debug)
71
72 try:
73 inventory = TinySQLiteInventory()
74 machine = inventory.request(
75 CustomVM,
76 arch=args.arch, boot=args.boot, clean=(not args.no_destroy),
77 debug=args.debug, diskbus=args.diskbus,
78 disksizes=args.gigabytes, dlpercentincrement=10,
79 emulator=args.emulator, image=args.image, initrd=args.initrd,
80 installtype=args.type, kernel=args.kernel, new=True,
81 preseed=args.preseed, rewrite=args.rewrite,
82 series=args.series, xml=args.xml)
83 exitstatus, locallogs = run_tests(args, machine)
84 finally:
85 if not args.no_destroy and machine is not None:
86 try:
87 machine.destroy()
88 except UTAHException as error:
89 sys.stderr.write('Failed to destroy machine: ' + str(error))
90 finally:
91 try:
92 inventory.destroy(machine.machineid)
93 except UTAHException as error:
94 sys.stderr.write('Failed to update inventory: '
95 + str(error))
96 finally:
97 del machine
98 if len(locallogs) != 0:
99 print('Test logs copied to the following files:')
100 print("\t" + "\n\t".join(locallogs))
101
102 sys.exit(exitstatus)
103
104
105if __name__ == '__main__':
106 logging.warning('This script is deprecated; please use run_utah_tests.py')
107 logging.warning('The same command line arguments should work there, i.e.:')
108 argv = list(sys.argv)
109 argv[0] = 'run_utah_tests.py'
110 logging.warning(' '.join(argv))
111 try:
112 run_install_test()
113 finally:
114 cleanup.run()
1150
=== removed file 'examples/run_test_bamboo_feeder.py'
--- examples/run_test_bamboo_feeder.py 2013-04-10 15:34:49 +0000
+++ examples/run_test_bamboo_feeder.py 1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
1#!/usr/bin/env python
2
3# Ubuntu Testing Automation Harness
4# Copyright 2012 Canonical Ltd.
5
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Provision a panda board in a bamboo-feeder setup and run a test."""
19
20
21import argparse
22import os
23import sys
24import logging
25
26from utah.cleanup import cleanup
27from utah.exceptions import UTAHException
28from utah.group import check_user_group, print_group_error_message
29from utah.provisioning.baremetal.bamboofeeder import BambooFeederMachine
30from utah.provisioning.baremetal.inventory import \
31 ManualBaremetalSQLiteInventory
32from utah.run import (
33 common_arguments,
34 custom_arguments,
35 name_argument,
36 run_tests,
37 configure_logging,
38 ReturnCodes,
39)
40
41
42def get_parser():
43 parser = argparse.ArgumentParser(
44 description=('Provision a pandaboard in a bamboo-feeder setup '
45 'and run one or more UTAH runlists there.'),
46 epilog=("For example:\n"
47 "Provision a machine using a precise server image "
48 "with i386 architecture and run the two given runlists\n"
49 "\t%(prog)s -s precise -t server -a i386 \\\n"
50 "\t\t/usr/share/utah/client/examples/master.run \\\n"
51 "\t\t'http://people.canonical.com/~max/max_test.run'"),
52 formatter_class=argparse.RawDescriptionHelpFormatter)
53 parser = common_arguments(parser)
54 parser = custom_arguments(parser)
55 parser = name_argument(parser)
56 return parser
57
58
59def run_test_bamboo_feeder(args=None):
60 if args is None:
61 args = get_parser().parse_args()
62
63 if not check_user_group():
64 print_group_error_message(__file__)
65 sys.exit(ReturnCodes.GROUP_ERROR)
66
67 locallogs = []
68 exitstatus = ReturnCodes.SUCCESS
69 machine = None
70
71 configure_logging(args.debug)
72
73 try:
74 inventory = ManualBaremetalSQLiteInventory(
75 db=os.path.join('~', '.utah-bamboofeeder-inventory'),
76 lockfile=os.path.join('~', '.utah-bamboofeeder-lock'))
77 kw = {}
78 for arg in ['boot', 'image', 'preseed']:
79 value = getattr(args, arg)
80 if value is not None:
81 kw[arg] = value
82 machine = inventory.request(machinetype=BambooFeederMachine,
83 clean=(not args.no_destroy),
84 debug=args.debug, new=True,
85 dlpercentincrement=10, **kw)
86 exitstatus, locallogs = run_tests(args, machine)
87
88 except UTAHException as error:
89 mesg = 'Exception: ' + str(error)
90 try:
91 logging.error(mesg)
92 except (AttributeError, NameError):
93 sys.stderr.write(mesg)
94 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
95 except Exception:
96 logging.exception('Unhandled error in UTAH')
97 exitstatus = ReturnCodes.UNHANDLED_ERROR
98 finally:
99 if machine is not None:
100 try:
101 machine.destroy()
102 except UTAHException as error:
103 sys.stderr.write('Failed to destroy machine: ' + str(error))
104
105 if len(locallogs) != 0:
106 print('Test logs copied to the following files:')
107 print("\t" + "\n\t".join(locallogs))
108
109 sys.exit(exitstatus)
110
111
112if __name__ == '__main__':
113 logging.warning('This script is thought to be broken')
114 logging.warning('If it is working, please report it to the UTAH team via '
115 'ubuntu-utah-devel@lists.ubuntu.com')
116 try:
117 run_test_bamboo_feeder()
118 finally:
119 cleanup.run()
1200
=== removed file 'examples/run_test_cobbler.py'
--- examples/run_test_cobbler.py 2013-04-10 15:34:49 +0000
+++ examples/run_test_cobbler.py 1970-01-01 00:00:00 +0000
@@ -1,127 +0,0 @@
1#!/usr/bin/env python
2
3# Ubuntu Testing Automation Harness
4# Copyright 2012 Canonical Ltd.
5
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Provision a machine with cobbler and run a test."""
19
20
21import argparse
22import sys
23import logging
24
25from utah.cleanup import cleanup
26from utah.exceptions import UTAHException
27from utah.group import check_user_group, print_group_error_message
28from utah.provisioning.baremetal.cobbler import CobblerMachine
29from utah.provisioning.baremetal.inventory import \
30 ManualBaremetalSQLiteInventory
31from utah.run import (
32 common_arguments,
33 custom_arguments,
34 name_argument,
35 run_tests,
36 configure_logging,
37 ReturnCodes,
38)
39
40
41def get_parser():
42 parser = argparse.ArgumentParser(
43 description=('Provision a machine using cobbler '
44 'and run one or more UTAH runlists there.'),
45 epilog=("For example:\n"
46 "Provision a machine using a precise server image "
47 "with i386 architecture and run the two given runlists\n"
48 "\t%(prog)s -s precise -t server -a i386 \\\n"
49 "\t\t/usr/share/utah/client/examples/master.run \\\n"
50 "\t\t'http://people.canonical.com/~max/max_test.run'"),
51 formatter_class=argparse.RawDescriptionHelpFormatter)
52 parser = common_arguments(parser)
53 parser = custom_arguments(parser)
54 parser = name_argument(parser)
55 return parser
56
57
58def run_test_cobbler(args=None):
59 if args is None:
60 args = get_parser().parse_args()
61
62 if not check_user_group():
63 print_group_error_message(__file__)
64 sys.exit(ReturnCodes.GROUP_ERROR)
65
66 locallogs = []
67 exitstatus = ReturnCodes.SUCCESS
68 machine = None
69
70 configure_logging(args.debug)
71
72 try:
73 inventory = ManualBaremetalSQLiteInventory()
74 kw = {}
75 for arg in ['arch',
76 'boot',
77 'image',
78 'preseed',
79 'rewrite',
80 'series',
81 ]:
82 value = getattr(args, arg)
83 if value is not None:
84 kw[arg] = value
85 if getattr(args, 'type') is not None:
86 kw['installtype'] = args.type
87 machine = inventory.request(CobblerMachine,
88 clean=(not args.no_destroy),
89 debug=args.debug, dlpercentincrement=10,
90 name=args.name, new=True, **kw)
91 exitstatus, locallogs = run_tests(args, machine)
92
93 except UTAHException as error:
94 mesg = 'Exception: ' + str(error)
95 try:
96 logging.error(mesg)
97 except (AttributeError, NameError):
98 sys.stderr.write(mesg)
99 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
100 except Exception:
101 logging.exception('Unhandled error in UTAH')
102 exitstatus = ReturnCodes.UNHANDLED_ERROR
103 finally:
104 if machine is not None:
105 try:
106 machine.destroy()
107 except UTAHException as error:
108 sys.stderr.write('Failed to destroy machine: ' + str(error))
109
110 if len(locallogs) != 0:
111 print('Test logs copied to the following files:')
112 print("\t" + "\n\t".join(locallogs))
113
114 sys.exit(exitstatus)
115
116
117if __name__ == '__main__':
118 logging.warning('This script is deprecated; please use run_utah_tests.py')
119 logging.warning('Add the -m physical argument to your existing list, i.e.:')
120 argv = list(sys.argv)
121 argv[0] = 'run_utah_tests.py'
122 argv.extend(['-m', 'physical'])
123 logging.warning(' '.join(argv))
124 try:
125 run_test_cobbler()
126 finally:
127 cleanup.run()
1280
=== removed file 'examples/run_test_vm.py'
--- examples/run_test_vm.py 2013-04-10 15:34:49 +0000
+++ examples/run_test_vm.py 1970-01-01 00:00:00 +0000
@@ -1,115 +0,0 @@
1#!/usr/bin/env python
2
3# Ubuntu Testing Automation Harness
4# Copyright 2012 Canonical Ltd.
5
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Create a VM and run a test."""
19
20
21import argparse
22import logging
23import sys
24
25from utah.cleanup import cleanup
26from utah.exceptions import UTAHException
27from utah.group import check_user_group, print_group_error_message
28from utah.provisioning.vm.vm import TinySQLiteInventory
29from utah.run import (
30 common_arguments,
31 run_tests,
32 configure_logging,
33 ReturnCodes,
34)
35
36
37def get_parser():
38 parser = argparse.ArgumentParser(
39 description=('Create a virtual machine '
40 'and run a UTAH runlist there.'),
41 epilog=("For example:\n"
42 "Provision a VM using a precise server image "
43 "with i386 architecture and run the two given runlists\n"
44 "\t%(prog)s -s precise -t server -a i386 \\\n"
45 "\t\t/usr/share/utah/client/examples/master.run \\\n"
46 "\t\t'http://people.canonical.com/~max/max_test.run'"),
47 formatter_class=argparse.RawDescriptionHelpFormatter)
48 return common_arguments(parser)
49
50
51def run_test_vm(args=None):
52 if args is None:
53 args = get_parser().parse_args()
54
55 if not check_user_group():
56 print_group_error_message(__file__)
57 sys.exit(ReturnCodes.GROUP_ERROR)
58
59 locallogs = []
60 exitstatus = ReturnCodes.SUCCESS
61 machine = None
62
63 configure_logging(args.debug)
64
65 try:
66 inventory = TinySQLiteInventory()
67 kw = {}
68 for arg in ['arch', 'series']:
69 value = getattr(args, arg)
70 if value is not None:
71 kw[arg] = value
72 if args.type is not None:
73 kw.update([('installtype', args.type)])
74 machine = inventory.request(clean=(not args.no_destroy),
75 debug=args.debug, new=True,
76 dlpercentincrement=10, **kw)
77 exitstatus, locallogs = run_tests(args, machine)
78
79 except UTAHException as error:
80 sys.stderr.write('Exception: ' + str(error))
81 exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
82 except Exception:
83 logging.exception('Unhandled error in UTAH')
84 exitstatus = ReturnCodes.UNHANDLED_ERROR
85 finally:
86 if not args.no_destroy and machine is not None:
87 try:
88 machine.destroy()
89 except UTAHException as error:
90 sys.stderr.write('Failed to destroy machine: ' + str(error))
91 finally:
92 try:
93 inventory.destroy(machine.machineid)
94 except UTAHException as error:
95 sys.stderr.write('Failed to update inventory: '
96 + str(error))
97 finally:
98 del machine
99 if len(locallogs) != 0:
100 print('Test logs copied to the following files:')
101 print("\t" + "\n\t".join(locallogs))
102
103 sys.exit(exitstatus)
104
105
106if __name__ == '__main__':
107 logging.warning('This script is deprecated; please use run_utah_tests.py')
108 logging.warning('The same command line arguments should work there, i.e.:')
109 argv = list(sys.argv)
110 argv[0] = 'run_utah_tests.py'
111 logging.warning(' '.join(argv))
112 try:
113 run_test_vm()
114 finally:
115 cleanup.run()
1160
=== modified file 'examples/run_utah_tests.py'
--- examples/run_utah_tests.py 2013-04-25 12:29:33 +0000
+++ examples/run_utah_tests.py 2013-05-01 21:24:29 +0000
@@ -20,27 +20,31 @@
2020
21import argparse21import argparse
22import logging22import logging
23import os
23import sys24import sys
25
24from traceback import format_exception26from traceback import format_exception
2527
26import utah28import utah
29
27from utah import config30from utah import config
28from utah.cleanup import cleanup31from utah.cleanup import cleanup
32from utah.exceptions import UTAHException
29from utah.group import check_user_group, print_group_error_message33from utah.group import check_user_group, print_group_error_message
34from utah.provisioning.baremetal.bamboofeeder import BambooFeederMachine
35from utah.provisioning.baremetal.cobbler import CobblerMachine
36from utah.provisioning.baremetal.inventory import \
37 ManualBaremetalSQLiteInventory
38from utah.provisioning.ssh import ProvisionedMachine
39from utah.provisioning.vm.vm import TinySQLiteInventory
30from utah.run import (40from utah.run import (
31 common_arguments,
32 custom_arguments,
33 file_arguments,
34 name_argument,
35 virtual_arguments,
36 configure_logging,41 configure_logging,
42 master_runlist_argument,
37 run_tests,43 run_tests,
38 ReturnCodes,44 ReturnCodes,
39)45)
40from utah.timeout import timeout, UTAHTimeout46from utah.timeout import timeout, UTAHTimeout
41from run_install_test import run_install_test47from utah.url import url_argument
42from utah.provisioning.ssh import ProvisionedMachine
43from utah.exceptions import UTAHException
4448
4549
46def get_parser():50def get_parser():
@@ -57,75 +61,159 @@
57 formatter_class=argparse.RawDescriptionHelpFormatter)61 formatter_class=argparse.RawDescriptionHelpFormatter)
58 parser.add_argument('-m', '--machinetype', metavar='MACHINETYPE',62 parser.add_argument('-m', '--machinetype', metavar='MACHINETYPE',
59 choices=('physical', 'virtual'),63 choices=('physical', 'virtual'),
60 help='Type of machine to provision (%(choices)s)')64 default=config.machinetype,
65 help='Type of machine to provision (%(choices)s) '
66 '(Default is %(default)s)')
61 parser.add_argument('-v', '--variant',67 parser.add_argument('-v', '--variant',
68 default=config.variant,
62 help='Variant of architecture, i.e., armel, armhf')69 help='Variant of architecture, i.e., armel, armhf')
63 parser.add_argument('--skip-provisioning', action='store_true',70 parser.add_argument('--skip-provisioning', action='store_true',
64 help=('Reuse a system that is already provisioned '71 help='Reuse a system that is already provisioned '
65 '(name argument must be passed)'))72 '(name argument must be passed)')
66 parser = common_arguments(parser)73 parser.add_argument('runlist', metavar='runlist',
67 parser = custom_arguments(parser)74 type=master_runlist_argument,
68 parser = file_arguments(parser)75 help='URLs of runlist files to run')
69 parser = name_argument(parser)76 parser.add_argument('-s', '--series', metavar='SERIES',
70 parser = virtual_arguments(parser)77 choices=config.serieschoices,
78 default=config.series,
79 help='Series to use for installation (%(choices)s) '
80 '(Default is %(default)s)')
81 parser.add_argument('-t', '--type', metavar='TYPE',
82 choices=('desktop', 'server', 'mini', 'alternate'),
83 default=config.installtype,
84 help='Install type to use for installation '
85 '(%(choices)s) (Default is %(default)s)')
86 parser.add_argument('-a', '--arch', metavar='ARCH',
87 choices=('i386', 'amd64', 'arm'),
88 default=config.arch,
89 help='Architecture to use for installation '
90 '(%(choices)s) (Default is %(default)s)')
91 parser.add_argument('-n', '--no-destroy', action='store_true',
92 help='Preserve VM after tests have run')
93 parser.add_argument('-d', '--debug', action='store_true',
94 help='Enable debug logging')
95 parser.add_argument('-j', '--json', action='store_true',
96 help='Enable json logging (default is YAML)')
97 parser.add_argument('-f', '--files', action='append',
98 help='File or directory to copy from test system ')
99 parser.add_argument('-o', '--outdir',
100 help=('Directory to store locally copied files '
101 '(Default is {}/machine-name)'
102 .format(config.logpath)))
103 parser.add_argument('--dumplogs', action='store_true',
104 help='Write client output logs to standard out')
105 parser.add_argument('--outputpreseed', action='store_true',
106 help='Copy preseed to logs directory and list as '
107 'log file in output')
108 parser.add_argument('-i', '--image', type=url_argument,
109 default=config.image,
110 help='Image/ISO file to use for installation')
111 parser.add_argument('-p', '--preseed', type=url_argument,
112 default=config.preseed,
113 help='Preseed file to use for installation')
114 parser.add_argument('-b', '--boot',
115 default=config.boot,
116 help='Boot arguments for initial installation')
117 parser.add_argument('--rewrite',
118 choices=('all', 'minimal', 'casperonly', 'none'),
119 default=config.rewrite,
120 help='Set level of automatic configuration rewriting '
121 '(Default is %(default)s)')
122 parser.add_argument('-k', '--kernel', type=url_argument,
123 default=config.kernel,
124 help='Kernel file to use for installation')
125 parser.add_argument('-r', '--initrd', type=url_argument,
126 default=config.initrd,
127 help='InitRD file to use for installation')
128 parser.add_argument('--name',
129 default=config.name,
130 help='Name of machine to provision')
131 parser.add_argument('-e', '--emulator',
132 default=config.emulator,
133 help='Emulator to use (kvm and qemu are supported, '
134 'kvm will be favored if available)')
135 parser.add_argument('-x', '--xml', type=url_argument,
136 default=config.xml,
137 help='XML VM definition file '
138 '(Default is %(default)s)')
139 parser.add_argument('-g', '--gigabytes', action='append',
140 default=config.disksizes,
141 help='Size in gigabytes of virtual disk, '
142 'specify more than once for multiple disks '
143 '(Default is %(default)s)')
144 parser.add_argument('--diskbus', metavar='DISKBUS',
145 choices=('virtio', 'sata', 'ide'),
146 default=config.diskbus,
147 help='Disk bus to use for customvm installation '
148 '(%(choices)s) (Default is %(default)s)')
71 return parser149 return parser
72150
73151
152def _get_machine(args):
153 if args.skip_provisioning:
154 # TBD: Inventory should be used to verify machine
155 # is not running other tests
156 machine = ProvisionedMachine(name=args.name)
157 else:
158 kw = {'clean': (not args.no_destroy),
159 'new': True,
160 }
161 kw['arch'] = args.arch
162 kw['boot'] = args.boot
163 kw['debug'] = args.debug
164 kw['image'] = args.image
165 kw['initrd'] = args.initrd
166 kw['kernel'] = args.kernel
167 kw['name'] = args.name
168 kw['preseed'] = args.preseed
169 kw['rewrite'] = args.rewrite
170 kw['series'] = args.series
171 kw['xml'] = args.xml
172 kw['installtype'] = args.type
173 if args.machinetype == 'physical':
174 if 'arm' in args.arch:
175 inventory = ManualBaremetalSQLiteInventory(
176 db=os.path.join('~', '.utah-bamboofeeder-inventory'),
177 lockfile=os.path.join('~', '.utah-bamboofeeder-lock'))
178 kw['machinetype'] = BambooFeederMachine
179 else:
180 inventory = ManualBaremetalSQLiteInventory()
181 kw['machinetype'] = CobblerMachine
182 else:
183 inventory = TinySQLiteInventory()
184 kw['diskbus'] = args.diskbus
185 kw['emulator'] = args.emulator
186 kw['disksizes'] = args.gigabytes
187 machine = inventory.request(**kw)
188 return machine
189
190
74def run_utah_tests(args=None):191def run_utah_tests(args=None):
75 if args is None:192 if args is None:
76 args = get_parser().parse_args()193 args = get_parser().parse_args()
77194
78 if not check_user_group():195 if not check_user_group():
79 print_group_error_message(__file__)196 print_group_error_message(__file__)
80 sys.exit(ReturnCodes.GROUP_ERROR)197 return ReturnCodes.GROUP_ERROR
81
82 if args.machinetype is None:
83 machinetype = config.machinetype
84 else:
85 machinetype = args.machinetype
86198
87 configure_logging(args.debug)199 configure_logging(args.debug)
88 logging.info('UTAH version: %s', utah.__version__)200 logging.info('UTAH version: %s', utah.__version__)
89201
90 # Default is now CustomVM202 exitstatus = ReturnCodes.SUCCESS
91 function = run_install_test203 locallogs = []
92204
93 if args.skip_provisioning:205 exitstatus, locallogs = run_tests(args, _get_machine(args))
94 def run_provisioned_tests(args):206 if len(locallogs) > 0:
95 """Run test cases in a provisioned machine."""207 print('Test logs copied to the following files:')
96 locallogs = []208 print("\t" + "\n\t".join(locallogs))
97 try:209
98 # TBD: Inventory should be used to verify machine210 return(exitstatus)
99 # is not running other tests211
100 machine = ProvisionedMachine(name=args.name)
101 exitstatus, locallogs = run_tests(args, machine)
102 finally:
103 if len(locallogs) != 0:
104 print('Test logs copied to the following files:')
105 print("\t" + "\n\t".join(locallogs))
106 sys.exit(ReturnCodes.SUCCESS)
107
108 function = run_provisioned_tests
109 if args.arch is not None and 'arm' in args.arch:
110 # If arch is arm, use BambooFeederMachine
111 from run_test_bamboo_feeder import run_test_bamboo_feeder
112 function = run_test_bamboo_feeder
113 elif machinetype == 'physical':
114 # If machinetype is physical but arch isn't arm, use CobblerMachine
115 from run_test_cobbler import run_test_cobbler
116 function = run_test_cobbler
117
118 function(args=args)
119212
120if __name__ == '__main__':213if __name__ == '__main__':
121 try:214 try:
122 try:215 try:
123 if isinstance(config.jobtimeout, int):216 exitstatus = timeout(config.jobtimeout, run_utah_tests)
124 timeout(config.jobtimeout, run_utah_tests)
125 else:
126 run_utah_tests()
127 except AttributeError:
128 run_utah_tests()
129 finally:217 finally:
130 cleanup.run()218 cleanup.run()
131 except UTAHTimeout as exception:219 except UTAHTimeout as exception:
@@ -138,3 +226,4 @@
138 sys.stderr.write('Unhandled error in UTAH:\n{}\n'226 sys.stderr.write('Unhandled error in UTAH:\n{}\n'
139 .format(''.join(format_exception(*sys.exc_info()))))227 .format(''.join(format_exception(*sys.exc_info()))))
140 sys.exit(ReturnCodes.UNHANDLED_ERROR)228 sys.exit(ReturnCodes.UNHANDLED_ERROR)
229 sys.exit(exitstatus)
141230
=== modified file 'tests/test_run.py'
--- tests/test_run.py 2013-04-23 17:17:44 +0000
+++ tests/test_run.py 2013-05-01 21:24:29 +0000
@@ -134,10 +134,9 @@
134 logs = []134 logs = []
135 args = Mock()135 args = Mock()
136 args.outputpreseed = True136 args.outputpreseed = True
137
138 machine = Mock()137 machine = Mock()
139 machine.configure_mock(name='name', finalpreseed='/bad file name')138 machine.configure_mock(name='name', finalpreseed='/bad file name')
140 _copy_preseed(machine, machine, logs)139 _copy_preseed(machine, args, logs)
141 self.assertEqual(0, len(logs))140 self.assertEqual(0, len(logs))
142 self.assertTrue(warning.called)141 self.assertTrue(warning.called)
143 call_args, _call_kwargs = warning.call_args142 call_args, _call_kwargs = warning.call_args
@@ -148,8 +147,10 @@
148 def test_copy_preseed_good(self, copyfile):147 def test_copy_preseed_good(self, copyfile):
149 """Ensure _copy_preseed works for good data."""148 """Ensure _copy_preseed works for good data."""
150 logs = []149 logs = []
150 args = Mock()
151 args.outputpreseed = True
151 machine = Mock()152 machine = Mock()
152 machine.configure_mock(name='name', finalpreseed='/bin/true')153 machine.configure_mock(name='name', finalpreseed='/bin/true')
153 _copy_preseed(machine, machine, logs)154 _copy_preseed(machine, args, logs)
154 self.assertEqual(1, len(logs))155 self.assertEqual(1, len(logs))
155 self.assertTrue(copyfile.called)156 self.assertTrue(copyfile.called)
156157
=== modified file 'utah/config.py'
--- utah/config.py 2013-04-04 14:55:25 +0000
+++ utah/config.py 2013-05-01 21:24:29 +0000
@@ -60,6 +60,8 @@
60 boottimeout=90,60 boottimeout=90,
61 # Time to wait between checking if system is available over ssh61 # Time to wait between checking if system is available over ssh
62 checktimeout=15,62 checktimeout=15,
63 # Default setting for whether to clean up after a test run
64 clean=True,
63 # Default log level to print to the console65 # Default log level to print to the console
64 consoleloglevel=logging.WARNING,66 consoleloglevel=logging.WARNING,
65 # Default debug setting67 # Default debug setting
@@ -67,7 +69,7 @@
67 # Command to download test images69 # Command to download test images
68 dlcommand='dl-ubuntu-test-iso',70 dlcommand='dl-ubuntu-test-iso',
69 # Percentage increment at which to report download updates71 # Percentage increment at which to report download updates
70 dlpercentincrement=1,72 dlpercentincrement=10,
71 # Number of times to retry image download73 # Number of times to retry image download
72 dlretries=10,74 dlretries=10,
73 # Default diskbus for VMs75 # Default diskbus for VMs
@@ -93,14 +95,24 @@
93 installtype='mini',95 installtype='mini',
94 # Directory to store local images96 # Directory to store local images
95 isodir='/var/cache/utah/iso',97 isodir='/var/cache/utah/iso',
98 # Overall timeout for run_utah_tests
99 jobtimeout=None,
96 # Default kernel for installation100 # Default kernel for installation
97 kernel=None,101 kernel=None,
98 # Default location of log directory102 # Default location of log directory
99 logpath=os.path.join('/', 'var', 'log', 'utah'),103 logpath=os.path.join('/', 'var', 'log', 'utah'),
104 # Directory to hold non-temporary files (mostly for VM)
105 machinedir=None,
100 # Default machine ID106 # Default machine ID
101 machineid=None,107 machineid=None,
108 # Machine information object for physical machines
109 machineinfo=None,
102 # Default machine type110 # Default machine type
103 machinetype='virtual',111 machinetype='virtual',
112 # UUID for machine
113 machineuuid=None,
114 # List of mac addresses for VM
115 macs=[],
104 # Default machine name116 # Default machine name
105 name=None,117 name=None,
106 # Default setting of installing a new machine vs. using an existing one118 # Default setting of installing a new machine vs. using an existing one
@@ -117,14 +129,22 @@
117 outputpreseed=False,129 outputpreseed=False,
118 # Directory where utah client and other needed packages reside130 # Directory where utah client and other needed packages reside
119 packagedir=os.path.join('/', 'usr', 'share', 'utah'),131 packagedir=os.path.join('/', 'usr', 'share', 'utah'),
132 # Command to use to power cycle machine
133 powercmd=None,
120 # Time to wait between power off and power on for physical systems134 # Time to wait between power off and power on for physical systems
121 powertimeout=15,135 powertimeout=15,
136 # Preboot for bamboo-feeder panda boards
137 preboot=None,
138 # Prefix for machine names
139 prefix='utah',
122 # Default preseed140 # Default preseed
123 preseed=os.path.join('/', 'etc', 'utah', 'default-preseed.cfg'),141 preseed=os.path.join('/', 'etc', 'utah', 'default-preseed.cfg'),
124 # Location of PXE configuration files142 # Location of PXE configuration files
125 pxedir=os.path.join('/', 'var', 'lib', 'tftpboot', 'pxelinux.cfg'),143 pxedir=os.path.join('/', 'var', 'lib', 'tftpboot', 'pxelinux.cfg'),
126 # libvirt URL for virtual machine creation144 # libvirt URL for virtual machine creation
127 qemupath='qemu:///system',145 qemupath='qemu:///system',
146 # default timeout between retry attempts
147 retry_timeout=3,
128 # Default setting for configuration rewriting148 # Default setting for configuration rewriting
129 rewrite='all',149 rewrite='all',
130 # Time to wait for client process to finish in run.py150 # Time to wait for client process to finish in run.py
@@ -140,17 +160,19 @@
140 'quantal',160 'quantal',
141 'raring',161 'raring',
142 ],162 ],
163 # sqlite database connection timeout
164 # a value higher than the default is used to avoid db locking problems
165 sqlite3_db_connection_timeout=30,
143 # Default machine template166 # Default machine template
144 template=None,167 template=None,
168 # location of the jinja2 templates used by the provisionig module
169 template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates'),
145 # Directory to hold web-accessible files170 # Directory to hold web-accessible files
146 wwwdir=os.path.join('/', 'var', 'www', 'utah'),171 wwwdir=os.path.join('/', 'var', 'www', 'utah'),
172 # Default architecture variant (armel, armhd, non-pae, etc.)
173 variant=None,
147 # Default VM XML file174 # Default VM XML file
148 xml=os.path.join('/', 'etc', 'utah', 'default-vm.xml'),175 xml=os.path.join('/', 'etc', 'utah', 'default-vm.xml'),
149 # sqlite database connection timeout
150 # a value higher than the default is used to avoid db locking problems
151 sqlite3_db_connection_timeout=30,
152 # location of the jinja2 templates used by the provisionig module
153 template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates'),
154176
155 install_steps=[177 install_steps=[
156 {178 {
@@ -208,9 +230,6 @@
208 'timeout': 180,230 'timeout': 180,
209 }231 }
210 ],232 ],
211
212 # default timeout between retry attempts
213 retry_timeout=3,
214)233)
215234
216# These depend on the local user/path, and need to be filtered out235# These depend on the local user/path, and need to be filtered out
217236
=== modified file 'utah/provisioning/baremetal/bamboofeeder.py'
--- utah/provisioning/baremetal/bamboofeeder.py 2013-04-24 14:27:37 +0000
+++ utah/provisioning/baremetal/bamboofeeder.py 2013-05-01 21:24:29 +0000
@@ -40,8 +40,8 @@
4040
41 # TODO: raise more exceptions if ProcessRunner fails41 # TODO: raise more exceptions if ProcessRunner fails
42 # maybe get some easy way to do that like failok42 # maybe get some easy way to do that like failok
43 def __init__(self, machineinfo=None, name=None, preboot=None, *args,43 def __init__(self, machineinfo=config.machineinfo, name=config.name,
44 **kw):44 preboot=config.preboot, *args, **kw):
45 # TODO: respect rewrite setting45 # TODO: respect rewrite setting
46 if name is None:46 if name is None:
47 raise UTAHBMProvisioningException(47 raise UTAHBMProvisioningException(
@@ -55,23 +55,20 @@
55 name=name, **kw)55 name=name, **kw)
56 if self.inventory is not None:56 if self.inventory is not None:
57 self.cleanfunction(self.inventory.release, machine=self)57 self.cleanfunction(self.inventory.release, machine=self)
58 self._depcheck()
59 if self.image is None:58 if self.image is None:
60 raise UTAHBMProvisioningException(59 raise UTAHBMProvisioningException(
61 'Image file required for bamboo-feeder installation')60 'Image file required for bamboo-feeder installation')
61 self._depcheck()
62 self.ip = self._ipaddr(config.wwwiface)62 self.ip = self._ipaddr(config.wwwiface)
63 self.logger.debug('Configuring for %s with IP %s',63 self.logger.debug('Configuring for %s with IP %s',
64 config.wwwiface, self.ip)64 config.wwwiface, self.ip)
65 self._cmdlinesetup()65 self._cmdlinesetup()
66 imageurl = 'http://{}/utah/{}.img'.format(self.ip, self.name)66 imageurl = 'http://{}/utah/{}.img'.format(self.ip, self.name)
67 preenvurl = 'http://{}/utah/{}.preEnv'.format(self.ip, self.name)67 preenvurl = 'http://{}/utah/{}.preEnv'.format(self.ip, self.name)
68 if preboot is None:68 self.preboot = (preboot or
69 self.preboot = ('console=ttyO2,115200n8 imageurl={imageurl} '69 'console=ttyO2,115200n8 imageurl={imageurl} '
70 'bootcfg={preenvurl}'.format(70 'bootcfg={preenvurl}'
71 imageurl=imageurl, preenvurl=preenvurl))71 .format(imageurl=imageurl, preenvurl=preenvurl))
72 else:
73 # TODO: maybe make this automatically add needed options
74 self.preboot = preboot
75 self.logger.debug('Preboot setup:')72 self.logger.debug('Preboot setup:')
76 self.logger.debug(self.preboot)73 self.logger.debug(self.preboot)
77 self.logger.debug('BambooFeederMachine init finished')74 self.logger.debug('BambooFeederMachine init finished')
7875
=== modified file 'utah/provisioning/baremetal/cobbler.py'
--- utah/provisioning/baremetal/cobbler.py 2013-04-24 14:27:37 +0000
+++ utah/provisioning/baremetal/cobbler.py 2013-05-01 21:24:29 +0000
@@ -39,7 +39,8 @@
3939
40 # TODO: raise more exceptions if ProcessRunner fails40 # TODO: raise more exceptions if ProcessRunner fails
41 # maybe get some easy way to do that like failok41 # maybe get some easy way to do that like failok
42 def __init__(self, machineinfo=None, name=None, *args, **kw):42 def __init__(self, machineinfo=config.machineinfo, name=config.name,
43 *args, **kw):
43 # TODO: support for reusing existing machines44 # TODO: support for reusing existing machines
44 if name is None:45 if name is None:
45 raise UTAHBMProvisioningException(46 raise UTAHBMProvisioningException(
@@ -49,7 +50,6 @@
49 'No cobbler arguments given for machine creation')50 'No cobbler arguments given for machine creation')
50 else:51 else:
51 self.machineinfo = machineinfo52 self.machineinfo = machineinfo
52 self.power = {}
53 super(CobblerMachine, self).__init__(*args, machineinfo=machineinfo,53 super(CobblerMachine, self).__init__(*args, machineinfo=machineinfo,
54 name=name, **kw)54 name=name, **kw)
55 if self.inventory is not None:55 if self.inventory is not None:
5656
=== modified file 'utah/provisioning/baremetal/power.py'
--- utah/provisioning/baremetal/power.py 2013-04-04 13:19:16 +0000
+++ utah/provisioning/baremetal/power.py 2013-05-01 21:24:29 +0000
@@ -33,15 +33,15 @@
3333
34 """34 """
3535
36 def __init__(self, machineinfo=None, powercmd=None, *args, **kw):36 def __init__(self, machineinfo=config.machineinfo,
37 powercmd=config.powercmd, *args, **kw):
37 """Store power control info for later use."""38 """Store power control info for later use."""
38 if machineinfo is not None:39 if machineinfo is not None:
39 self.power = {}40 self.power = {}
40 for item in machineinfo:41 for item in machineinfo:
41 if 'power' in item:42 if 'power' in item:
42 self.power[item] = machineinfo[item]43 self.power[item] = machineinfo[item]
43 if powercmd is not None:44 self.powercmd = powercmd
44 self.powercmd = powercmd
45 super(PowerMixin, self).__init__(*args, **kw)45 super(PowerMixin, self).__init__(*args, **kw)
4646
47 def powercommand(self):47 def powercommand(self):
4848
=== modified file 'utah/provisioning/provisioning.py'
--- utah/provisioning/provisioning.py 2013-04-24 14:27:37 +0000
+++ utah/provisioning/provisioning.py 2013-05-01 21:24:29 +0000
@@ -64,12 +64,15 @@
6464
65 """65 """
6666
67 def __init__(self, arch=None, boot=None, clean=True, debug=False,67 def __init__(self, arch=config.arch, boot=config.boot, clean=True,
68 directory=None, image=None, dlpercentincrement=1,68 debug=False, image=config.image,
69 initrd=None, installtype=None, inventory=None, kernel=None,69 dlpercentincrement=config.dlpercentincrement,
70 machineid=None, machineuuid=None, name=None, new=False,70 initrd=config.initrd, installtype=config.installtype,
71 prefix='utah', preseed=None, rewrite=None, series=None,71 inventory=None, kernel=config.kernel,
72 template=None, xml=None):72 machineid=config.machineid, machineuuid=config.machineuuid,
73 name=config.name, new=False, preseed=config.preseed,
74 rewrite=config.rewrite, series=config.series,
75 template=config.template, xml=config.xml):
73 """Initialize the object representing the machine.76 """Initialize the object representing the machine.
7477
75 One of these groups of arguments should be included:78 One of these groups of arguments should be included:
@@ -85,9 +88,6 @@
85 Other arguments:88 Other arguments:
86 clean: Enable cleanup functions.89 clean: Enable cleanup functions.
87 debug: Enable debug logging.90 debug: Enable debug logging.
88 directory: Where the machine's files go. Should be persistent for
89 VMs, temporary is fine for installation-only files, like those
90 used to install a physical machine using another method.
91 dlpercentincrement: How often to log download updates to INFO91 dlpercentincrement: How often to log download updates to INFO
92 (All updates logged to DEBUG)92 (All updates logged to DEBUG)
93 inventory: Inventory object managing the machine; used for cleanup93 inventory: Inventory object managing the machine; used for cleanup
@@ -98,7 +98,6 @@
98 supplied.98 supplied.
99 new: Request a new machine (or a reinstall if a specific machine99 new: Request a new machine (or a reinstall if a specific machine
100 was requested.)100 was requested.)
101 prefix: prefix for automatically named machines.
102 rewrite: How much to alter supplied preseed and xml files.101 rewrite: How much to alter supplied preseed and xml files.
103 all: everything we need for an automated install102 all: everything we need for an automated install
104 minimal: insert latecommand into preseed103 minimal: insert latecommand into preseed
@@ -117,45 +116,27 @@
117 """116 """
118 # TODO: Make this work right with super at some point.117 # TODO: Make this work right with super at some point.
119 # TODO: Consider a global temp file creator, maybe as part of install.118 # TODO: Consider a global temp file creator, maybe as part of install.
119 # TODO: Make everything use config.dlpercentincrement instead of
120 # passing it around all the time
121 self.arch = arch
122 self.boot = boot
123 self.clean = clean
120 self.debug = debug124 self.debug = debug
121 self.dlpercentincrement = dlpercentincrement125 self.dlpercentincrement = dlpercentincrement
126 self.installtype = installtype
122 self.inventory = inventory127 self.inventory = inventory
123 self.machineid = machineid128 self.machineid = machineid
124 self.new = new129 self.new = new
125 self.prefix = prefix130 self.rewrite = rewrite
131 self.series = series
126 self.template = template132 self.template = template
133 self.uuid = uuid
127134
128 self.boottimeout = config.boottimeout135 self.boottimeout = config.boottimeout
129136
130 if clean is None:
131 self.clean = True
132 else:
133 self.clean = clean
134
135 # TODO: Move namesetup into vm137 # TODO: Move namesetup into vm
136 self._namesetup(name)138 self._namesetup(name)
137139
138 if arch is None:
139 self.arch = config.arch
140 else:
141 self.arch = arch
142 if boot is None:
143 self.boot = config.boot
144 else:
145 self.boot = boot
146 if installtype is None:
147 self.installtype = config.installtype
148 else:
149 self.installtype = installtype
150 if rewrite is None:
151 self.rewrite = config.rewrite
152 else:
153 self.rewrite = rewrite
154 if series is None:
155 self.series = config.series
156 else:
157 self.series = series
158
159 if machineuuid is None:140 if machineuuid is None:
160 self.uuid = str(uuid.uuid4())141 self.uuid = str(uuid.uuid4())
161 else:142 else:
@@ -165,20 +146,18 @@
165 self.active = False146 self.active = False
166 self._loggersetup()147 self._loggersetup()
167148
168 if preseed is None:
169 preseed = config.preseed
170
171 fileargs = ['initrd', 'kernel', 'preseed', 'xml']149 fileargs = ['initrd', 'kernel', 'preseed', 'xml']
172150
173 if image is None:151 if image is None:
174 image = config.image
175 if image is None or image.endswith('.iso'):
176 self.image = ISO(arch=arch,152 self.image = ISO(arch=arch,
177 dlpercentincrement=self.dlpercentincrement,153 dlpercentincrement=dlpercentincrement,
178 image=image,
179 installtype=installtype,154 installtype=installtype,
180 logger=self.logger,155 logger=self.logger,
181 series=series)156 series=series)
157 elif image.endswith('.iso'):
158 self.image = ISO(dlpercentincrement=dlpercentincrement,
159 image=image,
160 logger=self.logger)
182 else:161 else:
183 fileargs.append('image')162 fileargs.append('image')
184163
@@ -186,8 +165,6 @@
186 # Ensure every file/url type argument is available locally165 # Ensure every file/url type argument is available locally
187 arg = locals()[item]166 arg = locals()[item]
188 if arg is None:167 if arg is None:
189 arg = getattr(config, item)
190 if arg is None:
191 setattr(self, item, None)168 setattr(self, item, None)
192 else:169 else:
193 if arg.startswith('~'):170 if arg.startswith('~'):
@@ -199,6 +176,7 @@
199176
200 self.percent = 0177 self.percent = 0
201 self.logger.info('Preparing %s: %s', item, path)178 self.logger.info('Preparing %s: %s', item, path)
179 # TODO: implement download utility function and use it here
202 filename = urllib.urlretrieve(path,180 filename = urllib.urlretrieve(path,
203 reporthook=self.dldisplay)[0]181 reporthook=self.dldisplay)[0]
204 setattr(self, item, filename)182 setattr(self, item, filename)
205183
=== modified file 'utah/provisioning/vm/vm.py'
--- utah/provisioning/vm/vm.py 2013-04-24 14:31:11 +0000
+++ utah/provisioning/vm/vm.py 2013-05-01 21:24:29 +0000
@@ -134,9 +134,10 @@
134 """Install a VM from an image using libvirt direct kernel booting."""134 """Install a VM from an image using libvirt direct kernel booting."""
135135
136 # TODO: probably remove parameters from the private methods136 # TODO: probably remove parameters from the private methods
137 def __init__(self, directory=None, diskbus=None, disksizes=None,137 def __init__(self, directory=config.machinedir, diskbus=config.diskbus,
138 emulator=None, machineid=None, macs=None, name=None,138 disksizes=config.disksizes, emulator=config.emulator,
139 prefix='utah', *args, **kw):139 machineid=config.machineid, macs=config.macs,
140 name=config.name, prefix=config.prefix, *args, **kw):
140 # Make sure that no other virtualization solutions are running141 # Make sure that no other virtualization solutions are running
141 # TODO: see if this is needed for qemu or just kvm142 # TODO: see if this is needed for qemu or just kvm
142 process_checker = ProcessChecker()143 process_checker = ProcessChecker()
@@ -146,16 +147,11 @@
146 message = process_checker.get_error_message(app)147 message = process_checker.get_error_message(app)
147 raise UTAHVMProvisioningException(message)148 raise UTAHVMProvisioningException(message)
148149
149 if diskbus is None:150 self.diskbus = diskbus
150 self.diskbus = config.diskbus151 self.disksizes = disksizes
151 else:152 self.emulator = emulator
152 self.diskbus = diskbus153 self.macs = macs
153 if disksizes is None:154 self.prefix = prefix
154 disksizes = config.disksizes
155 if disksizes is None:
156 self.disksizes = [8]
157 else:
158 self.disksizes = disksizes
159 self.disks = []155 self.disks = []
160 if name is None:156 if name is None:
161 autoname = True157 autoname = True
@@ -178,34 +174,21 @@
178 self._loggerunsetup()174 self._loggerunsetup()
179 self._loggersetup()175 self._loggersetup()
180 self._cmdlinesetup()176 self._cmdlinesetup()
181 if emulator is None:177 if self.emulator is None:
182 emulator = config.emulator
183 if emulator is None:
184 if self._supportsdomaintype('kvm'):178 if self._supportsdomaintype('kvm'):
185 self.logger.info(179 self.logger.info(
186 'Setting type to kvm since it is in libvirt capabilities')180 'Setting type to kvm since it is in libvirt capabilities')
187 self.domaintype = 'kvm'181 self.emulator = 'kvm'
188 elif self._supportsdomaintype('qemu'):182 elif self._supportsdomaintype('qemu'):
189 self.logger.info(183 self.logger.info(
190 'Setting type to qemu since it is in libvirt capabilities')184 'Setting type to qemu since it is in libvirt capabilities')
191 self.domaintype = 'qemu'185 self.emulator = 'qemu'
192 else:186 else:
193 raise UTAHVMProvisioningException(187 raise UTAHVMProvisioningException(
194 'kvm and qemu not supported in libvirt capabilities; '188 'kvm and qemu not supported in libvirt capabilities; '
195 'please make sure qemu and/or kvm are installed '189 'please make sure qemu and/or kvm are installed '
196 'and libvirt is configured correctly')190 'and libvirt is configured correctly')
197 else:191 self.directory = (directory or os.path.join(config.vmpath, self.name))
198 self.domaintype = emulator
199 if self.domaintype == 'qemu':
200 self.logger.debug('Raising boot timeout for qemu domain')
201 self.boottimeout *= 4
202 if macs is None:
203 macs = []
204 self.macs = macs
205 if directory is None:
206 self.directory = os.path.join(config.vmpath, self.name)
207 else:
208 self.directory = directory
209 self.cleanfile(self.directory)192 self.cleanfile(self.directory)
210 self.logger.info('Checking if machine directory {} exists'193 self.logger.info('Checking if machine directory {} exists'
211 .format(self.directory))194 .format(self.directory))
@@ -298,7 +281,7 @@
298 xmlt.find('uuid').text = self.uuid281 xmlt.find('uuid').text = self.uuid
299 self.logger.debug(282 self.logger.debug(
300 'Setting type to qemu in case no hardware virtualization present')283 'Setting type to qemu in case no hardware virtualization present')
301 xmlt.getroot().set('type', self.domaintype)284 xmlt.getroot().set('type', self.emulator)
302 ose = xmlt.find('os')285 ose = xmlt.find('os')
303 if self.arch == ('i386'):286 if self.arch == ('i386'):
304 ose.find('type').set('arch', 'i686')287 ose.find('type').set('arch', 'i686')
305288
=== modified file 'utah/run.py'
--- utah/run.py 2013-04-19 19:27:58 +0000
+++ utah/run.py 2013-05-01 21:24:29 +0000
@@ -33,22 +33,21 @@
33 parse_yaml_file,33 parse_yaml_file,
34 ReturnCodes as ClientReturnCodes,34 ReturnCodes as ClientReturnCodes,
35)35)
36from utah.client.runner import Runner
37from utah.client.exceptions import (36from utah.client.exceptions import (
38 YAMLEmptyFile,37 YAMLEmptyFile,
39 YAMLParsingError,38 YAMLParsingError,
40)39)
40from utah.client.runner import Runner
41from utah.exceptions import UTAHException41from utah.exceptions import UTAHException
42from utah.retry import retry42from utah.retry import retry
43from utah.timeout import timeout43from utah.timeout import timeout
44from utah.url import url_argument44from utah.url import url_argument
45from utah.provisioning.ssh import ProvisionedMachine
4645
4746
48# Return codes for the server47# Return codes for the server
49class ReturnCodes:48class ReturnCodes:
5049
51 """Provide standard return codes for run\_ scripts."""50 r"""Provide standard return codes for run\_ scripts."""
5251
53 SUCCESS = 0 # No problems found52 SUCCESS = 0 # No problems found
54 UTAH_EXCEPTION_ERROR = 1 # UTAH exception caught53 UTAH_EXCEPTION_ERROR = 1 # UTAH exception caught
@@ -131,114 +130,8 @@
131 return filename130 return filename
132131
133132
134def common_arguments(parser):
135 """Centralize command line arguments for all run\_ scripts.
136
137 :returns: argparse parser with arguments added
138 :rtype: obj
139
140 """
141 parser.add_argument('runlist', metavar='runlist',
142 type=master_runlist_argument,
143 help='URLs of runlist files to run')
144 parser.add_argument('-s', '--series', metavar='SERIES',
145 choices=config.serieschoices,
146 help='Series to use for VM creation (%(choices)s)')
147 parser.add_argument('-t', '--type', metavar='TYPE',
148 choices=('desktop', 'server', 'mini', 'alternate'),
149 help=('Install type to use for VM creation '
150 '(%(choices)s)'))
151 parser.add_argument('-a', '--arch', metavar='ARCH',
152 choices=('i386', 'amd64'),
153 help=('Architecture to use for VM creation '
154 '(%(choices)s)'))
155 parser.add_argument('-n', '--no-destroy', action='store_true',
156 help='Preserve VM after tests have run')
157 parser.add_argument('-d', '--debug', action='store_true',
158 help='Enable debug logging')
159 parser.add_argument('-j', '--json', action='store_true',
160 help='Enable json logging (default is YAML)')
161 parser.add_argument('-f', '--files', action='append',
162 help='File or directory to copy from test system ')
163 parser.add_argument('-o', '--outdir',
164 help=('Directory to store locally copied files '
165 '(Default is {}/machine-name)'
166 .format(config.logpath)))
167 parser.add_argument('--dumplogs', action='store_true',
168 help='Write client output logs to standard out')
169 parser.add_argument('--outputpreseed', action='store_true',
170 help='Copy preseed to logs directory and list as '
171 'log file in output')
172 return parser
173
174
175def custom_arguments(parser):
176 """Centralize arguments for installing from an image.
177
178 :returns: argparse parser with arguments added
179 :rtype: obj
180
181 """
182 parser.add_argument('-i', '--image', type=url_argument,
183 help='Image/ISO file to use for installation')
184 parser.add_argument('-p', '--preseed', type=url_argument,
185 help='Preseed file to use for installation')
186 parser.add_argument('-b', '--boot',
187 help='Boot arguments for initial installation')
188 parser.add_argument('--rewrite', choices=('all', 'minimal', 'casperonly',
189 'none'), help='Enable or disable automatic '
190 'configuration rewriting')
191 return parser
192
193
194def file_arguments(parser):
195 """Centralize arguments for custom kernel and initrd support.
196
197 :returns: argparse parser with arguments added
198 :rtype: obj
199
200 """
201 parser.add_argument('-k', '--kernel', type=url_argument,
202 help='Kernel file to use for installation')
203 parser.add_argument('-r', '--initrd', type=url_argument,
204 help='InitRD file to use for installation')
205 return parser
206
207
208def name_argument(parser):
209 """Centralize arguments for named machines.
210
211 :returns: argparse parser with arguments added
212 :rtype: obj
213
214 """
215 parser.add_argument('--name', help='Name of machine to provision')
216 return parser
217
218
219def virtual_arguments(parser):
220 """Centralize arguments for virtual machines.
221
222 :returns: argparse parser with arguments added
223 :rtype: obj
224
225 """
226 parser.add_argument('-e', '--emulator',
227 help=('Emulator to use (kvm and qemu are supported, '
228 'kvm will be favored if available)'))
229 parser.add_argument('-x', '--xml', type=url_argument,
230 help='XML VM definition file')
231 parser.add_argument('-g', '--gigabytes', action='append',
232 help=('Size in gigabytes of virtual disk, '
233 'specify more than once for multiple disks'))
234 parser.add_argument('--diskbus', metavar='DISKBUS',
235 choices=('virtio', 'sata', 'ide'),
236 help=('Disk bus to use for customvm installation '
237 '(%(choices)s)'))
238 return parser
239
240
241def _get_runlist(url):133def _get_runlist(url):
134 # TODO: Make something that this and utah.iso._get_resource can both use
242 try:135 try:
243 return urllib.urlretrieve(url)[0]136 return urllib.urlretrieve(url)[0]
244 except urllib.ContentTooShortError as e:137 except urllib.ContentTooShortError as e:
@@ -329,21 +222,25 @@
329 """Copy preseed to locallogs.222 """Copy preseed to locallogs.
330223
331 If we are provisioning a system, we can optionally copy its preseed along224 If we are provisioning a system, we can optionally copy its preseed along
332 with other locallogs from the job. Systems already provisioned will not225 with other locallogs from the job.
333226
334 """227 """
335 if (not isinstance(machine, ProvisionedMachine) and228 if args.outputpreseed or config.outputpreseed:
336 (args.outputpreseed or config.outputpreseed)):
337 if args.outputpreseed:229 if args.outputpreseed:
338 logging.debug('Capturing preseed due to command line option')230 logging.debug('Capturing preseed due to command line option')
339231
340 p = os.path.join(config.logpath, '{}-preseed.cfg'.format(machine.name))232 p = os.path.join(config.logpath, '{}-preseed.cfg'.format(machine.name))
341 try:233 if machine.hasattr('finalpreseed'):
342 shutil.copyfile(machine.finalpreseed, p)234 try:
343 except (IOError, shutil.Error) as err:235 if os.path.isfile(p):
344 logging.warning('Failed to copy preseed file: %s', err)236 os.chmod(p, 0664)
237 shutil.copyfile(machine.finalpreseed, p)
238 except (IOError, OSError, shutil.Error) as err:
239 logging.warning('Failed to copy preseed file: %s', err)
240 else:
241 locallogs.append(p)
345 else:242 else:
346 locallogs.append(p)243 logging.debug('Machine has no preseed to capture')
347244
348245
349def run_tests(args, machine):246def run_tests(args, machine):
@@ -391,10 +288,7 @@
391 :rtype: list(str)288 :rtype: list(str)
392289
393 """290 """
394 if args.outdir is None:291 outdir = (args.outdir or os.path.join(config.logpath, machine.name))
395 outdir = os.path.join(config.logpath, machine.name)
396 else:
397 outdir = args.outdir
398 if not os.path.isdir(outdir):292 if not os.path.isdir(outdir):
399 try:293 try:
400 os.makedirs(outdir)294 os.makedirs(outdir)
@@ -507,7 +401,7 @@
507401
508 """402 """
509 logging.info('Checking if UTAH client is finished')403 logging.info('Checking if UTAH client is finished')
510 machine.sshcheck()404 machine.activecheck()
511 try:405 try:
512 exitstatus = machine.run('/usr/share/utah/client/utah-done.py',406 exitstatus = machine.run('/usr/share/utah/client/utah-done.py',
513 quiet=True)[0]407 quiet=True)[0]

Subscribers

People subscribed via source and target branches