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
1=== modified file 'debian/changelog'
2--- debian/changelog 2013-05-01 17:37:58 +0000
3+++ debian/changelog 2013-05-01 21:24:29 +0000
4@@ -14,9 +14,20 @@
5 * Make rsyslog timeout error message clearer (LP: #1169846)
6 * Write to log UTAH version as soon as possible (LP: #1152216)
7 * Fixed help output to use just one runlist (LP: #1112597)
8+<<<<<<< TREE
9 * Setup rc.local to use output passed via command line (LP: #1155615)
10+=======
11+ * Combined current provisioning functions into one script and removed
12+ old scripts
13+ * Set permissions when copying preseed so overwrite works (LP: #1130901)
14+ * Enabled reading power command from config (LP: #1153735)
15+>>>>>>> MERGE-SOURCE
16
17+<<<<<<< TREE
18 -- Max Brustkern <max@canonical.com> Fri, 26 Apr 2013 13:58:25 -0400
19+=======
20+ -- Max Brustkern <max@canonical.com> Thu, 25 Apr 2013 11:02:23 -0400
21+>>>>>>> MERGE-SOURCE
22
23 utah (0.10ubuntu1) UNRELEASED; urgency=low
24
25
26=== modified file 'debian/utah.manpages'
27--- debian/utah.manpages 2012-08-31 15:36:31 +0000
28+++ debian/utah.manpages 2013-05-01 21:24:29 +0000
29@@ -1,4 +1,1 @@
30-docs/build/man/run_install_test.py.1
31-docs/build/man/run_test_cobbler.py.1
32-docs/build/man/run_test_vm.py.1
33 docs/build/man/run_utah_tests.py.1
34
35=== modified file 'docs/source/conf.py'
36--- docs/source/conf.py 2013-04-18 10:46:00 +0000
37+++ docs/source/conf.py 2013-05-01 21:24:29 +0000
38@@ -148,8 +148,7 @@
39
40 return description, options, epilog
41
42-module_names = ('client', 'run_install_test', 'run_test_cobbler',
43- 'run_test_vm', 'run_utah_tests')
44+module_names = ('client', 'run_utah_tests')
45 for module_name in module_names:
46 module = __import__(module_name)
47 parser = module.get_parser()
48@@ -367,13 +366,6 @@
49 man_pages = [
50 ('man/utah', 'utah', u'UTAH client test runner',
51 [u'Canonical Ltd'], 1),
52- ('man/run_install_test.py', 'run_install_test.py',
53- u'UTAH server test runner (provisioning)', [u'Canonical Ltd'], 1),
54- ('man/run_test_cobbler.py', 'run_test_cobbler.py',
55- u'UTAH server test runner (physical hardware)', [u'Canonical Ltd'], 1),
56- ('man/run_test_vm.py', 'run_test_vm.py',
57- u'UTAH server test runner (virtual hardware)',
58- [u'Canonical Ltd'], 1),
59 ('man/run_utah_tests.py', 'run_utah_tests.py',
60 u'UTAH server test runner (any hardware)', [u'Canonical Ltd'], 1),
61 ]
62
63=== removed file 'docs/source/man/run_install_test.py.rst'
64--- docs/source/man/run_install_test.py.rst 2012-09-05 11:30:16 +0000
65+++ docs/source/man/run_install_test.py.rst 1970-01-01 00:00:00 +0000
66@@ -1,26 +0,0 @@
67-:orphan:
68-
69-run_install_test.py manual page
70-===============================
71-
72-Synopsis
73---------
74-**run_install_test.py** [options] [runlist ...]
75-
76-Description
77------------
78-.. include:: run_install_test_description.txt
79-
80-Options
81--------
82-.. include:: run_install_test_options.txt
83-
84-Examples
85---------
86-.. include:: run_install_test_epilog.txt
87-
88-See also
89---------
90-:manpage:`run_test_cobbler.py(1)`
91-:manpage:`run_test_vm.py(1)`
92-:manpage:`run_utah_tests.py(1)`
93
94=== removed file 'docs/source/man/run_test_cobbler.py.rst'
95--- docs/source/man/run_test_cobbler.py.rst 2012-09-05 11:30:16 +0000
96+++ docs/source/man/run_test_cobbler.py.rst 1970-01-01 00:00:00 +0000
97@@ -1,26 +0,0 @@
98-:orphan:
99-
100-run_test_cobbler.py manual page
101-===============================
102-
103-Synopsis
104---------
105-**run_test_cobbler.py** [options] [runlist ...]
106-
107-Description
108------------
109-.. include:: run_test_cobbler_description.txt
110-
111-Options
112--------
113-.. include:: run_test_cobbler_options.txt
114-
115-Examples
116---------
117-.. include:: run_test_cobbler_epilog.txt
118-
119-See also
120---------
121-:manpage:`run_install_test.py(1)`
122-:manpage:`run_test_vm.py(1)`
123-:manpage:`run_utah_tests.py(1)`
124
125=== removed file 'docs/source/man/run_test_vm.py.rst'
126--- docs/source/man/run_test_vm.py.rst 2012-09-05 11:30:16 +0000
127+++ docs/source/man/run_test_vm.py.rst 1970-01-01 00:00:00 +0000
128@@ -1,26 +0,0 @@
129-:orphan:
130-
131-run_test_vm.py manual page
132-==========================
133-
134-Synopsis
135---------
136-**run_test_vm.py** [options] [runlist ...]
137-
138-Description
139------------
140-.. include:: run_test_vm_description.txt
141-
142-Options
143--------
144-.. include:: run_test_vm_options.txt
145-
146-Examples
147---------
148-.. include:: run_test_vm_epilog.txt
149-
150-See also
151---------
152-:manpage:`run_install_test.py(1)`
153-:manpage:`run_test_cobbler.py(1)`
154-:manpage:`run_utah_tests.py(1)`
155
156=== removed file 'examples/run_install_test.py'
157--- examples/run_install_test.py 2013-04-18 14:15:12 +0000
158+++ examples/run_install_test.py 1970-01-01 00:00:00 +0000
159@@ -1,114 +0,0 @@
160-#!/usr/bin/env python
161-
162-# Ubuntu Testing Automation Harness
163-# Copyright 2012 Canonical Ltd.
164-
165-# This program is free software: you can redistribute it and/or modify it
166-# under the terms of the GNU General Public License version 3, as published
167-# by the Free Software Foundation.
168-
169-# This program is distributed in the hope that it will be useful, but
170-# WITHOUT ANY WARRANTY; without even the implied warranties of
171-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
172-# PURPOSE. See the GNU General Public License for more details.
173-
174-# You should have received a copy of the GNU General Public License along
175-# with this program. If not, see <http://www.gnu.org/licenses/>.
176-
177-"""Create a VM and run a test."""
178-
179-
180-import argparse
181-import logging
182-import sys
183-
184-from utah.cleanup import cleanup
185-from utah.exceptions import UTAHException
186-from utah.group import check_user_group, print_group_error_message
187-from utah.provisioning.vm.vm import CustomVM, TinySQLiteInventory
188-from utah.run import (
189- common_arguments,
190- custom_arguments,
191- file_arguments,
192- run_tests,
193- virtual_arguments,
194- configure_logging,
195- ReturnCodes,
196-)
197-
198-
199-def get_parser():
200- parser = argparse.ArgumentParser(
201- description=('Provision a machine '
202- 'and run one or more UTAH runlists there.'),
203- epilog=("For example:\n"
204- "Provision a VM using a precise server image "
205- "with i386 architecture and run the two given runlists\n"
206- "\t%(prog)s -s precise -t server -a i386 \\\n"
207- "\t\t/usr/share/utah/client/examples/master.run \\\n"
208- "\t\t'http://people.canonical.com/~max/max_test.run'"),
209- formatter_class=argparse.RawDescriptionHelpFormatter)
210- parser = common_arguments(parser)
211- parser = custom_arguments(parser)
212- parser = file_arguments(parser)
213- parser = virtual_arguments(parser)
214- return parser
215-
216-
217-def run_install_test(args=None):
218- if args is None:
219- args = get_parser().parse_args()
220-
221- if not check_user_group():
222- print_group_error_message(__file__)
223- sys.exit(ReturnCodes.GROUP_ERROR)
224-
225- locallogs = []
226- exitstatus = ReturnCodes.SUCCESS
227- machine = None
228-
229- configure_logging(args.debug)
230-
231- try:
232- inventory = TinySQLiteInventory()
233- machine = inventory.request(
234- CustomVM,
235- arch=args.arch, boot=args.boot, clean=(not args.no_destroy),
236- debug=args.debug, diskbus=args.diskbus,
237- disksizes=args.gigabytes, dlpercentincrement=10,
238- emulator=args.emulator, image=args.image, initrd=args.initrd,
239- installtype=args.type, kernel=args.kernel, new=True,
240- preseed=args.preseed, rewrite=args.rewrite,
241- series=args.series, xml=args.xml)
242- exitstatus, locallogs = run_tests(args, machine)
243- finally:
244- if not args.no_destroy and machine is not None:
245- try:
246- machine.destroy()
247- except UTAHException as error:
248- sys.stderr.write('Failed to destroy machine: ' + str(error))
249- finally:
250- try:
251- inventory.destroy(machine.machineid)
252- except UTAHException as error:
253- sys.stderr.write('Failed to update inventory: '
254- + str(error))
255- finally:
256- del machine
257- if len(locallogs) != 0:
258- print('Test logs copied to the following files:')
259- print("\t" + "\n\t".join(locallogs))
260-
261- sys.exit(exitstatus)
262-
263-
264-if __name__ == '__main__':
265- logging.warning('This script is deprecated; please use run_utah_tests.py')
266- logging.warning('The same command line arguments should work there, i.e.:')
267- argv = list(sys.argv)
268- argv[0] = 'run_utah_tests.py'
269- logging.warning(' '.join(argv))
270- try:
271- run_install_test()
272- finally:
273- cleanup.run()
274
275=== removed file 'examples/run_test_bamboo_feeder.py'
276--- examples/run_test_bamboo_feeder.py 2013-04-10 15:34:49 +0000
277+++ examples/run_test_bamboo_feeder.py 1970-01-01 00:00:00 +0000
278@@ -1,119 +0,0 @@
279-#!/usr/bin/env python
280-
281-# Ubuntu Testing Automation Harness
282-# Copyright 2012 Canonical Ltd.
283-
284-# This program is free software: you can redistribute it and/or modify it
285-# under the terms of the GNU General Public License version 3, as published
286-# by the Free Software Foundation.
287-
288-# This program is distributed in the hope that it will be useful, but
289-# WITHOUT ANY WARRANTY; without even the implied warranties of
290-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
291-# PURPOSE. See the GNU General Public License for more details.
292-
293-# You should have received a copy of the GNU General Public License along
294-# with this program. If not, see <http://www.gnu.org/licenses/>.
295-
296-"""Provision a panda board in a bamboo-feeder setup and run a test."""
297-
298-
299-import argparse
300-import os
301-import sys
302-import logging
303-
304-from utah.cleanup import cleanup
305-from utah.exceptions import UTAHException
306-from utah.group import check_user_group, print_group_error_message
307-from utah.provisioning.baremetal.bamboofeeder import BambooFeederMachine
308-from utah.provisioning.baremetal.inventory import \
309- ManualBaremetalSQLiteInventory
310-from utah.run import (
311- common_arguments,
312- custom_arguments,
313- name_argument,
314- run_tests,
315- configure_logging,
316- ReturnCodes,
317-)
318-
319-
320-def get_parser():
321- parser = argparse.ArgumentParser(
322- description=('Provision a pandaboard in a bamboo-feeder setup '
323- 'and run one or more UTAH runlists there.'),
324- epilog=("For example:\n"
325- "Provision a machine using a precise server image "
326- "with i386 architecture and run the two given runlists\n"
327- "\t%(prog)s -s precise -t server -a i386 \\\n"
328- "\t\t/usr/share/utah/client/examples/master.run \\\n"
329- "\t\t'http://people.canonical.com/~max/max_test.run'"),
330- formatter_class=argparse.RawDescriptionHelpFormatter)
331- parser = common_arguments(parser)
332- parser = custom_arguments(parser)
333- parser = name_argument(parser)
334- return parser
335-
336-
337-def run_test_bamboo_feeder(args=None):
338- if args is None:
339- args = get_parser().parse_args()
340-
341- if not check_user_group():
342- print_group_error_message(__file__)
343- sys.exit(ReturnCodes.GROUP_ERROR)
344-
345- locallogs = []
346- exitstatus = ReturnCodes.SUCCESS
347- machine = None
348-
349- configure_logging(args.debug)
350-
351- try:
352- inventory = ManualBaremetalSQLiteInventory(
353- db=os.path.join('~', '.utah-bamboofeeder-inventory'),
354- lockfile=os.path.join('~', '.utah-bamboofeeder-lock'))
355- kw = {}
356- for arg in ['boot', 'image', 'preseed']:
357- value = getattr(args, arg)
358- if value is not None:
359- kw[arg] = value
360- machine = inventory.request(machinetype=BambooFeederMachine,
361- clean=(not args.no_destroy),
362- debug=args.debug, new=True,
363- dlpercentincrement=10, **kw)
364- exitstatus, locallogs = run_tests(args, machine)
365-
366- except UTAHException as error:
367- mesg = 'Exception: ' + str(error)
368- try:
369- logging.error(mesg)
370- except (AttributeError, NameError):
371- sys.stderr.write(mesg)
372- exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
373- except Exception:
374- logging.exception('Unhandled error in UTAH')
375- exitstatus = ReturnCodes.UNHANDLED_ERROR
376- finally:
377- if machine is not None:
378- try:
379- machine.destroy()
380- except UTAHException as error:
381- sys.stderr.write('Failed to destroy machine: ' + str(error))
382-
383- if len(locallogs) != 0:
384- print('Test logs copied to the following files:')
385- print("\t" + "\n\t".join(locallogs))
386-
387- sys.exit(exitstatus)
388-
389-
390-if __name__ == '__main__':
391- logging.warning('This script is thought to be broken')
392- logging.warning('If it is working, please report it to the UTAH team via '
393- 'ubuntu-utah-devel@lists.ubuntu.com')
394- try:
395- run_test_bamboo_feeder()
396- finally:
397- cleanup.run()
398
399=== removed file 'examples/run_test_cobbler.py'
400--- examples/run_test_cobbler.py 2013-04-10 15:34:49 +0000
401+++ examples/run_test_cobbler.py 1970-01-01 00:00:00 +0000
402@@ -1,127 +0,0 @@
403-#!/usr/bin/env python
404-
405-# Ubuntu Testing Automation Harness
406-# Copyright 2012 Canonical Ltd.
407-
408-# This program is free software: you can redistribute it and/or modify it
409-# under the terms of the GNU General Public License version 3, as published
410-# by the Free Software Foundation.
411-
412-# This program is distributed in the hope that it will be useful, but
413-# WITHOUT ANY WARRANTY; without even the implied warranties of
414-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
415-# PURPOSE. See the GNU General Public License for more details.
416-
417-# You should have received a copy of the GNU General Public License along
418-# with this program. If not, see <http://www.gnu.org/licenses/>.
419-
420-"""Provision a machine with cobbler and run a test."""
421-
422-
423-import argparse
424-import sys
425-import logging
426-
427-from utah.cleanup import cleanup
428-from utah.exceptions import UTAHException
429-from utah.group import check_user_group, print_group_error_message
430-from utah.provisioning.baremetal.cobbler import CobblerMachine
431-from utah.provisioning.baremetal.inventory import \
432- ManualBaremetalSQLiteInventory
433-from utah.run import (
434- common_arguments,
435- custom_arguments,
436- name_argument,
437- run_tests,
438- configure_logging,
439- ReturnCodes,
440-)
441-
442-
443-def get_parser():
444- parser = argparse.ArgumentParser(
445- description=('Provision a machine using cobbler '
446- 'and run one or more UTAH runlists there.'),
447- epilog=("For example:\n"
448- "Provision a machine using a precise server image "
449- "with i386 architecture and run the two given runlists\n"
450- "\t%(prog)s -s precise -t server -a i386 \\\n"
451- "\t\t/usr/share/utah/client/examples/master.run \\\n"
452- "\t\t'http://people.canonical.com/~max/max_test.run'"),
453- formatter_class=argparse.RawDescriptionHelpFormatter)
454- parser = common_arguments(parser)
455- parser = custom_arguments(parser)
456- parser = name_argument(parser)
457- return parser
458-
459-
460-def run_test_cobbler(args=None):
461- if args is None:
462- args = get_parser().parse_args()
463-
464- if not check_user_group():
465- print_group_error_message(__file__)
466- sys.exit(ReturnCodes.GROUP_ERROR)
467-
468- locallogs = []
469- exitstatus = ReturnCodes.SUCCESS
470- machine = None
471-
472- configure_logging(args.debug)
473-
474- try:
475- inventory = ManualBaremetalSQLiteInventory()
476- kw = {}
477- for arg in ['arch',
478- 'boot',
479- 'image',
480- 'preseed',
481- 'rewrite',
482- 'series',
483- ]:
484- value = getattr(args, arg)
485- if value is not None:
486- kw[arg] = value
487- if getattr(args, 'type') is not None:
488- kw['installtype'] = args.type
489- machine = inventory.request(CobblerMachine,
490- clean=(not args.no_destroy),
491- debug=args.debug, dlpercentincrement=10,
492- name=args.name, new=True, **kw)
493- exitstatus, locallogs = run_tests(args, machine)
494-
495- except UTAHException as error:
496- mesg = 'Exception: ' + str(error)
497- try:
498- logging.error(mesg)
499- except (AttributeError, NameError):
500- sys.stderr.write(mesg)
501- exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
502- except Exception:
503- logging.exception('Unhandled error in UTAH')
504- exitstatus = ReturnCodes.UNHANDLED_ERROR
505- finally:
506- if machine is not None:
507- try:
508- machine.destroy()
509- except UTAHException as error:
510- sys.stderr.write('Failed to destroy machine: ' + str(error))
511-
512- if len(locallogs) != 0:
513- print('Test logs copied to the following files:')
514- print("\t" + "\n\t".join(locallogs))
515-
516- sys.exit(exitstatus)
517-
518-
519-if __name__ == '__main__':
520- logging.warning('This script is deprecated; please use run_utah_tests.py')
521- logging.warning('Add the -m physical argument to your existing list, i.e.:')
522- argv = list(sys.argv)
523- argv[0] = 'run_utah_tests.py'
524- argv.extend(['-m', 'physical'])
525- logging.warning(' '.join(argv))
526- try:
527- run_test_cobbler()
528- finally:
529- cleanup.run()
530
531=== removed file 'examples/run_test_vm.py'
532--- examples/run_test_vm.py 2013-04-10 15:34:49 +0000
533+++ examples/run_test_vm.py 1970-01-01 00:00:00 +0000
534@@ -1,115 +0,0 @@
535-#!/usr/bin/env python
536-
537-# Ubuntu Testing Automation Harness
538-# Copyright 2012 Canonical Ltd.
539-
540-# This program is free software: you can redistribute it and/or modify it
541-# under the terms of the GNU General Public License version 3, as published
542-# by the Free Software Foundation.
543-
544-# This program is distributed in the hope that it will be useful, but
545-# WITHOUT ANY WARRANTY; without even the implied warranties of
546-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
547-# PURPOSE. See the GNU General Public License for more details.
548-
549-# You should have received a copy of the GNU General Public License along
550-# with this program. If not, see <http://www.gnu.org/licenses/>.
551-
552-"""Create a VM and run a test."""
553-
554-
555-import argparse
556-import logging
557-import sys
558-
559-from utah.cleanup import cleanup
560-from utah.exceptions import UTAHException
561-from utah.group import check_user_group, print_group_error_message
562-from utah.provisioning.vm.vm import TinySQLiteInventory
563-from utah.run import (
564- common_arguments,
565- run_tests,
566- configure_logging,
567- ReturnCodes,
568-)
569-
570-
571-def get_parser():
572- parser = argparse.ArgumentParser(
573- description=('Create a virtual machine '
574- 'and run a UTAH runlist there.'),
575- epilog=("For example:\n"
576- "Provision a VM using a precise server image "
577- "with i386 architecture and run the two given runlists\n"
578- "\t%(prog)s -s precise -t server -a i386 \\\n"
579- "\t\t/usr/share/utah/client/examples/master.run \\\n"
580- "\t\t'http://people.canonical.com/~max/max_test.run'"),
581- formatter_class=argparse.RawDescriptionHelpFormatter)
582- return common_arguments(parser)
583-
584-
585-def run_test_vm(args=None):
586- if args is None:
587- args = get_parser().parse_args()
588-
589- if not check_user_group():
590- print_group_error_message(__file__)
591- sys.exit(ReturnCodes.GROUP_ERROR)
592-
593- locallogs = []
594- exitstatus = ReturnCodes.SUCCESS
595- machine = None
596-
597- configure_logging(args.debug)
598-
599- try:
600- inventory = TinySQLiteInventory()
601- kw = {}
602- for arg in ['arch', 'series']:
603- value = getattr(args, arg)
604- if value is not None:
605- kw[arg] = value
606- if args.type is not None:
607- kw.update([('installtype', args.type)])
608- machine = inventory.request(clean=(not args.no_destroy),
609- debug=args.debug, new=True,
610- dlpercentincrement=10, **kw)
611- exitstatus, locallogs = run_tests(args, machine)
612-
613- except UTAHException as error:
614- sys.stderr.write('Exception: ' + str(error))
615- exitstatus = ReturnCodes.UTAH_EXCEPTION_ERROR
616- except Exception:
617- logging.exception('Unhandled error in UTAH')
618- exitstatus = ReturnCodes.UNHANDLED_ERROR
619- finally:
620- if not args.no_destroy and machine is not None:
621- try:
622- machine.destroy()
623- except UTAHException as error:
624- sys.stderr.write('Failed to destroy machine: ' + str(error))
625- finally:
626- try:
627- inventory.destroy(machine.machineid)
628- except UTAHException as error:
629- sys.stderr.write('Failed to update inventory: '
630- + str(error))
631- finally:
632- del machine
633- if len(locallogs) != 0:
634- print('Test logs copied to the following files:')
635- print("\t" + "\n\t".join(locallogs))
636-
637- sys.exit(exitstatus)
638-
639-
640-if __name__ == '__main__':
641- logging.warning('This script is deprecated; please use run_utah_tests.py')
642- logging.warning('The same command line arguments should work there, i.e.:')
643- argv = list(sys.argv)
644- argv[0] = 'run_utah_tests.py'
645- logging.warning(' '.join(argv))
646- try:
647- run_test_vm()
648- finally:
649- cleanup.run()
650
651=== modified file 'examples/run_utah_tests.py'
652--- examples/run_utah_tests.py 2013-04-25 12:29:33 +0000
653+++ examples/run_utah_tests.py 2013-05-01 21:24:29 +0000
654@@ -20,27 +20,31 @@
655
656 import argparse
657 import logging
658+import os
659 import sys
660+
661 from traceback import format_exception
662
663 import utah
664+
665 from utah import config
666 from utah.cleanup import cleanup
667+from utah.exceptions import UTAHException
668 from utah.group import check_user_group, print_group_error_message
669+from utah.provisioning.baremetal.bamboofeeder import BambooFeederMachine
670+from utah.provisioning.baremetal.cobbler import CobblerMachine
671+from utah.provisioning.baremetal.inventory import \
672+ ManualBaremetalSQLiteInventory
673+from utah.provisioning.ssh import ProvisionedMachine
674+from utah.provisioning.vm.vm import TinySQLiteInventory
675 from utah.run import (
676- common_arguments,
677- custom_arguments,
678- file_arguments,
679- name_argument,
680- virtual_arguments,
681 configure_logging,
682+ master_runlist_argument,
683 run_tests,
684 ReturnCodes,
685 )
686 from utah.timeout import timeout, UTAHTimeout
687-from run_install_test import run_install_test
688-from utah.provisioning.ssh import ProvisionedMachine
689-from utah.exceptions import UTAHException
690+from utah.url import url_argument
691
692
693 def get_parser():
694@@ -57,75 +61,159 @@
695 formatter_class=argparse.RawDescriptionHelpFormatter)
696 parser.add_argument('-m', '--machinetype', metavar='MACHINETYPE',
697 choices=('physical', 'virtual'),
698- help='Type of machine to provision (%(choices)s)')
699+ default=config.machinetype,
700+ help='Type of machine to provision (%(choices)s) '
701+ '(Default is %(default)s)')
702 parser.add_argument('-v', '--variant',
703+ default=config.variant,
704 help='Variant of architecture, i.e., armel, armhf')
705 parser.add_argument('--skip-provisioning', action='store_true',
706- help=('Reuse a system that is already provisioned '
707- '(name argument must be passed)'))
708- parser = common_arguments(parser)
709- parser = custom_arguments(parser)
710- parser = file_arguments(parser)
711- parser = name_argument(parser)
712- parser = virtual_arguments(parser)
713+ help='Reuse a system that is already provisioned '
714+ '(name argument must be passed)')
715+ parser.add_argument('runlist', metavar='runlist',
716+ type=master_runlist_argument,
717+ help='URLs of runlist files to run')
718+ parser.add_argument('-s', '--series', metavar='SERIES',
719+ choices=config.serieschoices,
720+ default=config.series,
721+ help='Series to use for installation (%(choices)s) '
722+ '(Default is %(default)s)')
723+ parser.add_argument('-t', '--type', metavar='TYPE',
724+ choices=('desktop', 'server', 'mini', 'alternate'),
725+ default=config.installtype,
726+ help='Install type to use for installation '
727+ '(%(choices)s) (Default is %(default)s)')
728+ parser.add_argument('-a', '--arch', metavar='ARCH',
729+ choices=('i386', 'amd64', 'arm'),
730+ default=config.arch,
731+ help='Architecture to use for installation '
732+ '(%(choices)s) (Default is %(default)s)')
733+ parser.add_argument('-n', '--no-destroy', action='store_true',
734+ help='Preserve VM after tests have run')
735+ parser.add_argument('-d', '--debug', action='store_true',
736+ help='Enable debug logging')
737+ parser.add_argument('-j', '--json', action='store_true',
738+ help='Enable json logging (default is YAML)')
739+ parser.add_argument('-f', '--files', action='append',
740+ help='File or directory to copy from test system ')
741+ parser.add_argument('-o', '--outdir',
742+ help=('Directory to store locally copied files '
743+ '(Default is {}/machine-name)'
744+ .format(config.logpath)))
745+ parser.add_argument('--dumplogs', action='store_true',
746+ help='Write client output logs to standard out')
747+ parser.add_argument('--outputpreseed', action='store_true',
748+ help='Copy preseed to logs directory and list as '
749+ 'log file in output')
750+ parser.add_argument('-i', '--image', type=url_argument,
751+ default=config.image,
752+ help='Image/ISO file to use for installation')
753+ parser.add_argument('-p', '--preseed', type=url_argument,
754+ default=config.preseed,
755+ help='Preseed file to use for installation')
756+ parser.add_argument('-b', '--boot',
757+ default=config.boot,
758+ help='Boot arguments for initial installation')
759+ parser.add_argument('--rewrite',
760+ choices=('all', 'minimal', 'casperonly', 'none'),
761+ default=config.rewrite,
762+ help='Set level of automatic configuration rewriting '
763+ '(Default is %(default)s)')
764+ parser.add_argument('-k', '--kernel', type=url_argument,
765+ default=config.kernel,
766+ help='Kernel file to use for installation')
767+ parser.add_argument('-r', '--initrd', type=url_argument,
768+ default=config.initrd,
769+ help='InitRD file to use for installation')
770+ parser.add_argument('--name',
771+ default=config.name,
772+ help='Name of machine to provision')
773+ parser.add_argument('-e', '--emulator',
774+ default=config.emulator,
775+ help='Emulator to use (kvm and qemu are supported, '
776+ 'kvm will be favored if available)')
777+ parser.add_argument('-x', '--xml', type=url_argument,
778+ default=config.xml,
779+ help='XML VM definition file '
780+ '(Default is %(default)s)')
781+ parser.add_argument('-g', '--gigabytes', action='append',
782+ default=config.disksizes,
783+ help='Size in gigabytes of virtual disk, '
784+ 'specify more than once for multiple disks '
785+ '(Default is %(default)s)')
786+ parser.add_argument('--diskbus', metavar='DISKBUS',
787+ choices=('virtio', 'sata', 'ide'),
788+ default=config.diskbus,
789+ help='Disk bus to use for customvm installation '
790+ '(%(choices)s) (Default is %(default)s)')
791 return parser
792
793
794+def _get_machine(args):
795+ if args.skip_provisioning:
796+ # TBD: Inventory should be used to verify machine
797+ # is not running other tests
798+ machine = ProvisionedMachine(name=args.name)
799+ else:
800+ kw = {'clean': (not args.no_destroy),
801+ 'new': True,
802+ }
803+ kw['arch'] = args.arch
804+ kw['boot'] = args.boot
805+ kw['debug'] = args.debug
806+ kw['image'] = args.image
807+ kw['initrd'] = args.initrd
808+ kw['kernel'] = args.kernel
809+ kw['name'] = args.name
810+ kw['preseed'] = args.preseed
811+ kw['rewrite'] = args.rewrite
812+ kw['series'] = args.series
813+ kw['xml'] = args.xml
814+ kw['installtype'] = args.type
815+ if args.machinetype == 'physical':
816+ if 'arm' in args.arch:
817+ inventory = ManualBaremetalSQLiteInventory(
818+ db=os.path.join('~', '.utah-bamboofeeder-inventory'),
819+ lockfile=os.path.join('~', '.utah-bamboofeeder-lock'))
820+ kw['machinetype'] = BambooFeederMachine
821+ else:
822+ inventory = ManualBaremetalSQLiteInventory()
823+ kw['machinetype'] = CobblerMachine
824+ else:
825+ inventory = TinySQLiteInventory()
826+ kw['diskbus'] = args.diskbus
827+ kw['emulator'] = args.emulator
828+ kw['disksizes'] = args.gigabytes
829+ machine = inventory.request(**kw)
830+ return machine
831+
832+
833 def run_utah_tests(args=None):
834 if args is None:
835 args = get_parser().parse_args()
836
837 if not check_user_group():
838 print_group_error_message(__file__)
839- sys.exit(ReturnCodes.GROUP_ERROR)
840-
841- if args.machinetype is None:
842- machinetype = config.machinetype
843- else:
844- machinetype = args.machinetype
845+ return ReturnCodes.GROUP_ERROR
846
847 configure_logging(args.debug)
848 logging.info('UTAH version: %s', utah.__version__)
849
850- # Default is now CustomVM
851- function = run_install_test
852-
853- if args.skip_provisioning:
854- def run_provisioned_tests(args):
855- """Run test cases in a provisioned machine."""
856- locallogs = []
857- try:
858- # TBD: Inventory should be used to verify machine
859- # is not running other tests
860- machine = ProvisionedMachine(name=args.name)
861- exitstatus, locallogs = run_tests(args, machine)
862- finally:
863- if len(locallogs) != 0:
864- print('Test logs copied to the following files:')
865- print("\t" + "\n\t".join(locallogs))
866- sys.exit(ReturnCodes.SUCCESS)
867-
868- function = run_provisioned_tests
869- if args.arch is not None and 'arm' in args.arch:
870- # If arch is arm, use BambooFeederMachine
871- from run_test_bamboo_feeder import run_test_bamboo_feeder
872- function = run_test_bamboo_feeder
873- elif machinetype == 'physical':
874- # If machinetype is physical but arch isn't arm, use CobblerMachine
875- from run_test_cobbler import run_test_cobbler
876- function = run_test_cobbler
877-
878- function(args=args)
879+ exitstatus = ReturnCodes.SUCCESS
880+ locallogs = []
881+
882+ exitstatus, locallogs = run_tests(args, _get_machine(args))
883+ if len(locallogs) > 0:
884+ print('Test logs copied to the following files:')
885+ print("\t" + "\n\t".join(locallogs))
886+
887+ return(exitstatus)
888+
889
890 if __name__ == '__main__':
891 try:
892 try:
893- if isinstance(config.jobtimeout, int):
894- timeout(config.jobtimeout, run_utah_tests)
895- else:
896- run_utah_tests()
897- except AttributeError:
898- run_utah_tests()
899+ exitstatus = timeout(config.jobtimeout, run_utah_tests)
900 finally:
901 cleanup.run()
902 except UTAHTimeout as exception:
903@@ -138,3 +226,4 @@
904 sys.stderr.write('Unhandled error in UTAH:\n{}\n'
905 .format(''.join(format_exception(*sys.exc_info()))))
906 sys.exit(ReturnCodes.UNHANDLED_ERROR)
907+ sys.exit(exitstatus)
908
909=== modified file 'tests/test_run.py'
910--- tests/test_run.py 2013-04-23 17:17:44 +0000
911+++ tests/test_run.py 2013-05-01 21:24:29 +0000
912@@ -134,10 +134,9 @@
913 logs = []
914 args = Mock()
915 args.outputpreseed = True
916-
917 machine = Mock()
918 machine.configure_mock(name='name', finalpreseed='/bad file name')
919- _copy_preseed(machine, machine, logs)
920+ _copy_preseed(machine, args, logs)
921 self.assertEqual(0, len(logs))
922 self.assertTrue(warning.called)
923 call_args, _call_kwargs = warning.call_args
924@@ -148,8 +147,10 @@
925 def test_copy_preseed_good(self, copyfile):
926 """Ensure _copy_preseed works for good data."""
927 logs = []
928+ args = Mock()
929+ args.outputpreseed = True
930 machine = Mock()
931 machine.configure_mock(name='name', finalpreseed='/bin/true')
932- _copy_preseed(machine, machine, logs)
933+ _copy_preseed(machine, args, logs)
934 self.assertEqual(1, len(logs))
935 self.assertTrue(copyfile.called)
936
937=== modified file 'utah/config.py'
938--- utah/config.py 2013-04-04 14:55:25 +0000
939+++ utah/config.py 2013-05-01 21:24:29 +0000
940@@ -60,6 +60,8 @@
941 boottimeout=90,
942 # Time to wait between checking if system is available over ssh
943 checktimeout=15,
944+ # Default setting for whether to clean up after a test run
945+ clean=True,
946 # Default log level to print to the console
947 consoleloglevel=logging.WARNING,
948 # Default debug setting
949@@ -67,7 +69,7 @@
950 # Command to download test images
951 dlcommand='dl-ubuntu-test-iso',
952 # Percentage increment at which to report download updates
953- dlpercentincrement=1,
954+ dlpercentincrement=10,
955 # Number of times to retry image download
956 dlretries=10,
957 # Default diskbus for VMs
958@@ -93,14 +95,24 @@
959 installtype='mini',
960 # Directory to store local images
961 isodir='/var/cache/utah/iso',
962+ # Overall timeout for run_utah_tests
963+ jobtimeout=None,
964 # Default kernel for installation
965 kernel=None,
966 # Default location of log directory
967 logpath=os.path.join('/', 'var', 'log', 'utah'),
968+ # Directory to hold non-temporary files (mostly for VM)
969+ machinedir=None,
970 # Default machine ID
971 machineid=None,
972+ # Machine information object for physical machines
973+ machineinfo=None,
974 # Default machine type
975 machinetype='virtual',
976+ # UUID for machine
977+ machineuuid=None,
978+ # List of mac addresses for VM
979+ macs=[],
980 # Default machine name
981 name=None,
982 # Default setting of installing a new machine vs. using an existing one
983@@ -117,14 +129,22 @@
984 outputpreseed=False,
985 # Directory where utah client and other needed packages reside
986 packagedir=os.path.join('/', 'usr', 'share', 'utah'),
987+ # Command to use to power cycle machine
988+ powercmd=None,
989 # Time to wait between power off and power on for physical systems
990 powertimeout=15,
991+ # Preboot for bamboo-feeder panda boards
992+ preboot=None,
993+ # Prefix for machine names
994+ prefix='utah',
995 # Default preseed
996 preseed=os.path.join('/', 'etc', 'utah', 'default-preseed.cfg'),
997 # Location of PXE configuration files
998 pxedir=os.path.join('/', 'var', 'lib', 'tftpboot', 'pxelinux.cfg'),
999 # libvirt URL for virtual machine creation
1000 qemupath='qemu:///system',
1001+ # default timeout between retry attempts
1002+ retry_timeout=3,
1003 # Default setting for configuration rewriting
1004 rewrite='all',
1005 # Time to wait for client process to finish in run.py
1006@@ -140,17 +160,19 @@
1007 'quantal',
1008 'raring',
1009 ],
1010+ # sqlite database connection timeout
1011+ # a value higher than the default is used to avoid db locking problems
1012+ sqlite3_db_connection_timeout=30,
1013 # Default machine template
1014 template=None,
1015+ # location of the jinja2 templates used by the provisionig module
1016+ template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates'),
1017 # Directory to hold web-accessible files
1018 wwwdir=os.path.join('/', 'var', 'www', 'utah'),
1019+ # Default architecture variant (armel, armhd, non-pae, etc.)
1020+ variant=None,
1021 # Default VM XML file
1022 xml=os.path.join('/', 'etc', 'utah', 'default-vm.xml'),
1023- # sqlite database connection timeout
1024- # a value higher than the default is used to avoid db locking problems
1025- sqlite3_db_connection_timeout=30,
1026- # location of the jinja2 templates used by the provisionig module
1027- template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates'),
1028
1029 install_steps=[
1030 {
1031@@ -208,9 +230,6 @@
1032 'timeout': 180,
1033 }
1034 ],
1035-
1036- # default timeout between retry attempts
1037- retry_timeout=3,
1038 )
1039
1040 # These depend on the local user/path, and need to be filtered out
1041
1042=== modified file 'utah/provisioning/baremetal/bamboofeeder.py'
1043--- utah/provisioning/baremetal/bamboofeeder.py 2013-04-24 14:27:37 +0000
1044+++ utah/provisioning/baremetal/bamboofeeder.py 2013-05-01 21:24:29 +0000
1045@@ -40,8 +40,8 @@
1046
1047 # TODO: raise more exceptions if ProcessRunner fails
1048 # maybe get some easy way to do that like failok
1049- def __init__(self, machineinfo=None, name=None, preboot=None, *args,
1050- **kw):
1051+ def __init__(self, machineinfo=config.machineinfo, name=config.name,
1052+ preboot=config.preboot, *args, **kw):
1053 # TODO: respect rewrite setting
1054 if name is None:
1055 raise UTAHBMProvisioningException(
1056@@ -55,23 +55,20 @@
1057 name=name, **kw)
1058 if self.inventory is not None:
1059 self.cleanfunction(self.inventory.release, machine=self)
1060- self._depcheck()
1061 if self.image is None:
1062 raise UTAHBMProvisioningException(
1063 'Image file required for bamboo-feeder installation')
1064+ self._depcheck()
1065 self.ip = self._ipaddr(config.wwwiface)
1066 self.logger.debug('Configuring for %s with IP %s',
1067 config.wwwiface, self.ip)
1068 self._cmdlinesetup()
1069 imageurl = 'http://{}/utah/{}.img'.format(self.ip, self.name)
1070 preenvurl = 'http://{}/utah/{}.preEnv'.format(self.ip, self.name)
1071- if preboot is None:
1072- self.preboot = ('console=ttyO2,115200n8 imageurl={imageurl} '
1073- 'bootcfg={preenvurl}'.format(
1074- imageurl=imageurl, preenvurl=preenvurl))
1075- else:
1076- # TODO: maybe make this automatically add needed options
1077- self.preboot = preboot
1078+ self.preboot = (preboot or
1079+ 'console=ttyO2,115200n8 imageurl={imageurl} '
1080+ 'bootcfg={preenvurl}'
1081+ .format(imageurl=imageurl, preenvurl=preenvurl))
1082 self.logger.debug('Preboot setup:')
1083 self.logger.debug(self.preboot)
1084 self.logger.debug('BambooFeederMachine init finished')
1085
1086=== modified file 'utah/provisioning/baremetal/cobbler.py'
1087--- utah/provisioning/baremetal/cobbler.py 2013-04-24 14:27:37 +0000
1088+++ utah/provisioning/baremetal/cobbler.py 2013-05-01 21:24:29 +0000
1089@@ -39,7 +39,8 @@
1090
1091 # TODO: raise more exceptions if ProcessRunner fails
1092 # maybe get some easy way to do that like failok
1093- def __init__(self, machineinfo=None, name=None, *args, **kw):
1094+ def __init__(self, machineinfo=config.machineinfo, name=config.name,
1095+ *args, **kw):
1096 # TODO: support for reusing existing machines
1097 if name is None:
1098 raise UTAHBMProvisioningException(
1099@@ -49,7 +50,6 @@
1100 'No cobbler arguments given for machine creation')
1101 else:
1102 self.machineinfo = machineinfo
1103- self.power = {}
1104 super(CobblerMachine, self).__init__(*args, machineinfo=machineinfo,
1105 name=name, **kw)
1106 if self.inventory is not None:
1107
1108=== modified file 'utah/provisioning/baremetal/power.py'
1109--- utah/provisioning/baremetal/power.py 2013-04-04 13:19:16 +0000
1110+++ utah/provisioning/baremetal/power.py 2013-05-01 21:24:29 +0000
1111@@ -33,15 +33,15 @@
1112
1113 """
1114
1115- def __init__(self, machineinfo=None, powercmd=None, *args, **kw):
1116+ def __init__(self, machineinfo=config.machineinfo,
1117+ powercmd=config.powercmd, *args, **kw):
1118 """Store power control info for later use."""
1119 if machineinfo is not None:
1120 self.power = {}
1121 for item in machineinfo:
1122 if 'power' in item:
1123 self.power[item] = machineinfo[item]
1124- if powercmd is not None:
1125- self.powercmd = powercmd
1126+ self.powercmd = powercmd
1127 super(PowerMixin, self).__init__(*args, **kw)
1128
1129 def powercommand(self):
1130
1131=== modified file 'utah/provisioning/provisioning.py'
1132--- utah/provisioning/provisioning.py 2013-04-24 14:27:37 +0000
1133+++ utah/provisioning/provisioning.py 2013-05-01 21:24:29 +0000
1134@@ -64,12 +64,15 @@
1135
1136 """
1137
1138- def __init__(self, arch=None, boot=None, clean=True, debug=False,
1139- directory=None, image=None, dlpercentincrement=1,
1140- initrd=None, installtype=None, inventory=None, kernel=None,
1141- machineid=None, machineuuid=None, name=None, new=False,
1142- prefix='utah', preseed=None, rewrite=None, series=None,
1143- template=None, xml=None):
1144+ def __init__(self, arch=config.arch, boot=config.boot, clean=True,
1145+ debug=False, image=config.image,
1146+ dlpercentincrement=config.dlpercentincrement,
1147+ initrd=config.initrd, installtype=config.installtype,
1148+ inventory=None, kernel=config.kernel,
1149+ machineid=config.machineid, machineuuid=config.machineuuid,
1150+ name=config.name, new=False, preseed=config.preseed,
1151+ rewrite=config.rewrite, series=config.series,
1152+ template=config.template, xml=config.xml):
1153 """Initialize the object representing the machine.
1154
1155 One of these groups of arguments should be included:
1156@@ -85,9 +88,6 @@
1157 Other arguments:
1158 clean: Enable cleanup functions.
1159 debug: Enable debug logging.
1160- directory: Where the machine's files go. Should be persistent for
1161- VMs, temporary is fine for installation-only files, like those
1162- used to install a physical machine using another method.
1163 dlpercentincrement: How often to log download updates to INFO
1164 (All updates logged to DEBUG)
1165 inventory: Inventory object managing the machine; used for cleanup
1166@@ -98,7 +98,6 @@
1167 supplied.
1168 new: Request a new machine (or a reinstall if a specific machine
1169 was requested.)
1170- prefix: prefix for automatically named machines.
1171 rewrite: How much to alter supplied preseed and xml files.
1172 all: everything we need for an automated install
1173 minimal: insert latecommand into preseed
1174@@ -117,45 +116,27 @@
1175 """
1176 # TODO: Make this work right with super at some point.
1177 # TODO: Consider a global temp file creator, maybe as part of install.
1178+ # TODO: Make everything use config.dlpercentincrement instead of
1179+ # passing it around all the time
1180+ self.arch = arch
1181+ self.boot = boot
1182+ self.clean = clean
1183 self.debug = debug
1184 self.dlpercentincrement = dlpercentincrement
1185+ self.installtype = installtype
1186 self.inventory = inventory
1187 self.machineid = machineid
1188 self.new = new
1189- self.prefix = prefix
1190+ self.rewrite = rewrite
1191+ self.series = series
1192 self.template = template
1193+ self.uuid = uuid
1194
1195 self.boottimeout = config.boottimeout
1196
1197- if clean is None:
1198- self.clean = True
1199- else:
1200- self.clean = clean
1201-
1202 # TODO: Move namesetup into vm
1203 self._namesetup(name)
1204
1205- if arch is None:
1206- self.arch = config.arch
1207- else:
1208- self.arch = arch
1209- if boot is None:
1210- self.boot = config.boot
1211- else:
1212- self.boot = boot
1213- if installtype is None:
1214- self.installtype = config.installtype
1215- else:
1216- self.installtype = installtype
1217- if rewrite is None:
1218- self.rewrite = config.rewrite
1219- else:
1220- self.rewrite = rewrite
1221- if series is None:
1222- self.series = config.series
1223- else:
1224- self.series = series
1225-
1226 if machineuuid is None:
1227 self.uuid = str(uuid.uuid4())
1228 else:
1229@@ -165,20 +146,18 @@
1230 self.active = False
1231 self._loggersetup()
1232
1233- if preseed is None:
1234- preseed = config.preseed
1235-
1236 fileargs = ['initrd', 'kernel', 'preseed', 'xml']
1237
1238 if image is None:
1239- image = config.image
1240- if image is None or image.endswith('.iso'):
1241 self.image = ISO(arch=arch,
1242- dlpercentincrement=self.dlpercentincrement,
1243- image=image,
1244+ dlpercentincrement=dlpercentincrement,
1245 installtype=installtype,
1246 logger=self.logger,
1247 series=series)
1248+ elif image.endswith('.iso'):
1249+ self.image = ISO(dlpercentincrement=dlpercentincrement,
1250+ image=image,
1251+ logger=self.logger)
1252 else:
1253 fileargs.append('image')
1254
1255@@ -186,8 +165,6 @@
1256 # Ensure every file/url type argument is available locally
1257 arg = locals()[item]
1258 if arg is None:
1259- arg = getattr(config, item)
1260- if arg is None:
1261 setattr(self, item, None)
1262 else:
1263 if arg.startswith('~'):
1264@@ -199,6 +176,7 @@
1265
1266 self.percent = 0
1267 self.logger.info('Preparing %s: %s', item, path)
1268+ # TODO: implement download utility function and use it here
1269 filename = urllib.urlretrieve(path,
1270 reporthook=self.dldisplay)[0]
1271 setattr(self, item, filename)
1272
1273=== modified file 'utah/provisioning/vm/vm.py'
1274--- utah/provisioning/vm/vm.py 2013-04-24 14:31:11 +0000
1275+++ utah/provisioning/vm/vm.py 2013-05-01 21:24:29 +0000
1276@@ -134,9 +134,10 @@
1277 """Install a VM from an image using libvirt direct kernel booting."""
1278
1279 # TODO: probably remove parameters from the private methods
1280- def __init__(self, directory=None, diskbus=None, disksizes=None,
1281- emulator=None, machineid=None, macs=None, name=None,
1282- prefix='utah', *args, **kw):
1283+ def __init__(self, directory=config.machinedir, diskbus=config.diskbus,
1284+ disksizes=config.disksizes, emulator=config.emulator,
1285+ machineid=config.machineid, macs=config.macs,
1286+ name=config.name, prefix=config.prefix, *args, **kw):
1287 # Make sure that no other virtualization solutions are running
1288 # TODO: see if this is needed for qemu or just kvm
1289 process_checker = ProcessChecker()
1290@@ -146,16 +147,11 @@
1291 message = process_checker.get_error_message(app)
1292 raise UTAHVMProvisioningException(message)
1293
1294- if diskbus is None:
1295- self.diskbus = config.diskbus
1296- else:
1297- self.diskbus = diskbus
1298- if disksizes is None:
1299- disksizes = config.disksizes
1300- if disksizes is None:
1301- self.disksizes = [8]
1302- else:
1303- self.disksizes = disksizes
1304+ self.diskbus = diskbus
1305+ self.disksizes = disksizes
1306+ self.emulator = emulator
1307+ self.macs = macs
1308+ self.prefix = prefix
1309 self.disks = []
1310 if name is None:
1311 autoname = True
1312@@ -178,34 +174,21 @@
1313 self._loggerunsetup()
1314 self._loggersetup()
1315 self._cmdlinesetup()
1316- if emulator is None:
1317- emulator = config.emulator
1318- if emulator is None:
1319+ if self.emulator is None:
1320 if self._supportsdomaintype('kvm'):
1321 self.logger.info(
1322 'Setting type to kvm since it is in libvirt capabilities')
1323- self.domaintype = 'kvm'
1324+ self.emulator = 'kvm'
1325 elif self._supportsdomaintype('qemu'):
1326 self.logger.info(
1327 'Setting type to qemu since it is in libvirt capabilities')
1328- self.domaintype = 'qemu'
1329+ self.emulator = 'qemu'
1330 else:
1331 raise UTAHVMProvisioningException(
1332 'kvm and qemu not supported in libvirt capabilities; '
1333 'please make sure qemu and/or kvm are installed '
1334 'and libvirt is configured correctly')
1335- else:
1336- self.domaintype = emulator
1337- if self.domaintype == 'qemu':
1338- self.logger.debug('Raising boot timeout for qemu domain')
1339- self.boottimeout *= 4
1340- if macs is None:
1341- macs = []
1342- self.macs = macs
1343- if directory is None:
1344- self.directory = os.path.join(config.vmpath, self.name)
1345- else:
1346- self.directory = directory
1347+ self.directory = (directory or os.path.join(config.vmpath, self.name))
1348 self.cleanfile(self.directory)
1349 self.logger.info('Checking if machine directory {} exists'
1350 .format(self.directory))
1351@@ -298,7 +281,7 @@
1352 xmlt.find('uuid').text = self.uuid
1353 self.logger.debug(
1354 'Setting type to qemu in case no hardware virtualization present')
1355- xmlt.getroot().set('type', self.domaintype)
1356+ xmlt.getroot().set('type', self.emulator)
1357 ose = xmlt.find('os')
1358 if self.arch == ('i386'):
1359 ose.find('type').set('arch', 'i686')
1360
1361=== modified file 'utah/run.py'
1362--- utah/run.py 2013-04-19 19:27:58 +0000
1363+++ utah/run.py 2013-05-01 21:24:29 +0000
1364@@ -33,22 +33,21 @@
1365 parse_yaml_file,
1366 ReturnCodes as ClientReturnCodes,
1367 )
1368-from utah.client.runner import Runner
1369 from utah.client.exceptions import (
1370 YAMLEmptyFile,
1371 YAMLParsingError,
1372 )
1373+from utah.client.runner import Runner
1374 from utah.exceptions import UTAHException
1375 from utah.retry import retry
1376 from utah.timeout import timeout
1377 from utah.url import url_argument
1378-from utah.provisioning.ssh import ProvisionedMachine
1379
1380
1381 # Return codes for the server
1382 class ReturnCodes:
1383
1384- """Provide standard return codes for run\_ scripts."""
1385+ r"""Provide standard return codes for run\_ scripts."""
1386
1387 SUCCESS = 0 # No problems found
1388 UTAH_EXCEPTION_ERROR = 1 # UTAH exception caught
1389@@ -131,114 +130,8 @@
1390 return filename
1391
1392
1393-def common_arguments(parser):
1394- """Centralize command line arguments for all run\_ scripts.
1395-
1396- :returns: argparse parser with arguments added
1397- :rtype: obj
1398-
1399- """
1400- parser.add_argument('runlist', metavar='runlist',
1401- type=master_runlist_argument,
1402- help='URLs of runlist files to run')
1403- parser.add_argument('-s', '--series', metavar='SERIES',
1404- choices=config.serieschoices,
1405- help='Series to use for VM creation (%(choices)s)')
1406- parser.add_argument('-t', '--type', metavar='TYPE',
1407- choices=('desktop', 'server', 'mini', 'alternate'),
1408- help=('Install type to use for VM creation '
1409- '(%(choices)s)'))
1410- parser.add_argument('-a', '--arch', metavar='ARCH',
1411- choices=('i386', 'amd64'),
1412- help=('Architecture to use for VM creation '
1413- '(%(choices)s)'))
1414- parser.add_argument('-n', '--no-destroy', action='store_true',
1415- help='Preserve VM after tests have run')
1416- parser.add_argument('-d', '--debug', action='store_true',
1417- help='Enable debug logging')
1418- parser.add_argument('-j', '--json', action='store_true',
1419- help='Enable json logging (default is YAML)')
1420- parser.add_argument('-f', '--files', action='append',
1421- help='File or directory to copy from test system ')
1422- parser.add_argument('-o', '--outdir',
1423- help=('Directory to store locally copied files '
1424- '(Default is {}/machine-name)'
1425- .format(config.logpath)))
1426- parser.add_argument('--dumplogs', action='store_true',
1427- help='Write client output logs to standard out')
1428- parser.add_argument('--outputpreseed', action='store_true',
1429- help='Copy preseed to logs directory and list as '
1430- 'log file in output')
1431- return parser
1432-
1433-
1434-def custom_arguments(parser):
1435- """Centralize arguments for installing from an image.
1436-
1437- :returns: argparse parser with arguments added
1438- :rtype: obj
1439-
1440- """
1441- parser.add_argument('-i', '--image', type=url_argument,
1442- help='Image/ISO file to use for installation')
1443- parser.add_argument('-p', '--preseed', type=url_argument,
1444- help='Preseed file to use for installation')
1445- parser.add_argument('-b', '--boot',
1446- help='Boot arguments for initial installation')
1447- parser.add_argument('--rewrite', choices=('all', 'minimal', 'casperonly',
1448- 'none'), help='Enable or disable automatic '
1449- 'configuration rewriting')
1450- return parser
1451-
1452-
1453-def file_arguments(parser):
1454- """Centralize arguments for custom kernel and initrd support.
1455-
1456- :returns: argparse parser with arguments added
1457- :rtype: obj
1458-
1459- """
1460- parser.add_argument('-k', '--kernel', type=url_argument,
1461- help='Kernel file to use for installation')
1462- parser.add_argument('-r', '--initrd', type=url_argument,
1463- help='InitRD file to use for installation')
1464- return parser
1465-
1466-
1467-def name_argument(parser):
1468- """Centralize arguments for named machines.
1469-
1470- :returns: argparse parser with arguments added
1471- :rtype: obj
1472-
1473- """
1474- parser.add_argument('--name', help='Name of machine to provision')
1475- return parser
1476-
1477-
1478-def virtual_arguments(parser):
1479- """Centralize arguments for virtual machines.
1480-
1481- :returns: argparse parser with arguments added
1482- :rtype: obj
1483-
1484- """
1485- parser.add_argument('-e', '--emulator',
1486- help=('Emulator to use (kvm and qemu are supported, '
1487- 'kvm will be favored if available)'))
1488- parser.add_argument('-x', '--xml', type=url_argument,
1489- help='XML VM definition file')
1490- parser.add_argument('-g', '--gigabytes', action='append',
1491- help=('Size in gigabytes of virtual disk, '
1492- 'specify more than once for multiple disks'))
1493- parser.add_argument('--diskbus', metavar='DISKBUS',
1494- choices=('virtio', 'sata', 'ide'),
1495- help=('Disk bus to use for customvm installation '
1496- '(%(choices)s)'))
1497- return parser
1498-
1499-
1500 def _get_runlist(url):
1501+ # TODO: Make something that this and utah.iso._get_resource can both use
1502 try:
1503 return urllib.urlretrieve(url)[0]
1504 except urllib.ContentTooShortError as e:
1505@@ -329,21 +222,25 @@
1506 """Copy preseed to locallogs.
1507
1508 If we are provisioning a system, we can optionally copy its preseed along
1509- with other locallogs from the job. Systems already provisioned will not
1510+ with other locallogs from the job.
1511
1512 """
1513- if (not isinstance(machine, ProvisionedMachine) and
1514- (args.outputpreseed or config.outputpreseed)):
1515+ if args.outputpreseed or config.outputpreseed:
1516 if args.outputpreseed:
1517 logging.debug('Capturing preseed due to command line option')
1518
1519 p = os.path.join(config.logpath, '{}-preseed.cfg'.format(machine.name))
1520- try:
1521- shutil.copyfile(machine.finalpreseed, p)
1522- except (IOError, shutil.Error) as err:
1523- logging.warning('Failed to copy preseed file: %s', err)
1524+ if machine.hasattr('finalpreseed'):
1525+ try:
1526+ if os.path.isfile(p):
1527+ os.chmod(p, 0664)
1528+ shutil.copyfile(machine.finalpreseed, p)
1529+ except (IOError, OSError, shutil.Error) as err:
1530+ logging.warning('Failed to copy preseed file: %s', err)
1531+ else:
1532+ locallogs.append(p)
1533 else:
1534- locallogs.append(p)
1535+ logging.debug('Machine has no preseed to capture')
1536
1537
1538 def run_tests(args, machine):
1539@@ -391,10 +288,7 @@
1540 :rtype: list(str)
1541
1542 """
1543- if args.outdir is None:
1544- outdir = os.path.join(config.logpath, machine.name)
1545- else:
1546- outdir = args.outdir
1547+ outdir = (args.outdir or os.path.join(config.logpath, machine.name))
1548 if not os.path.isdir(outdir):
1549 try:
1550 os.makedirs(outdir)
1551@@ -507,7 +401,7 @@
1552
1553 """
1554 logging.info('Checking if UTAH client is finished')
1555- machine.sshcheck()
1556+ machine.activecheck()
1557 try:
1558 exitstatus = machine.run('/usr/share/utah/client/utah-done.py',
1559 quiet=True)[0]

Subscribers

People subscribed via source and target branches