Merge lp:~nuclearbob/utah/various-fixes into lp:utah

Proposed by Max Brustkern
Status: Merged
Approved by: Javier Collado
Approved revision: 889
Merged at revision: 893
Proposed branch: lp:~nuclearbob/utah/various-fixes
Merge into: lp:utah
Diff against target: 1456 lines (+190/-729)
19 files modified
distribute_setup.py (+0/-485)
docs/source/reference.rst (+6/-26)
examples/run_utah_tests.py (+1/-1)
setup.py (+7/-5)
tests/__init__.py (+16/-0)
tests/test_rsyslog.py (+1/-1)
utah/client/common.py (+4/-3)
utah/client/tests/test_runner.py (+32/-23)
utah/client/tests/test_testcase.py (+22/-13)
utah/client/tests/test_testsuite.py (+29/-12)
utah/client/tests/test_vcs_git.py (+1/-0)
utah/provisioning/baremetal/inventory.py (+4/-3)
utah/provisioning/inventory.py (+58/-2)
utah/provisioning/inventory/__init__.py (+0/-16)
utah/provisioning/inventory/exceptions.py (+0/-26)
utah/provisioning/inventory/sqlite.py (+0/-69)
utah/provisioning/vm.py (+9/-2)
utah/provisioning/vm/__init__.py (+0/-16)
utah/provisioning/vm/exceptions.py (+0/-26)
To merge this branch: bzr merge lp:~nuclearbob/utah/various-fixes
Reviewer Review Type Date Requested Status
Javier Collado (community) Approve
Max Brustkern (community) Needs Resubmitting
Review via email: mp+161946@code.launchpad.net

Description of the change

This branch adds an init file to the tests directory so we can import tests.common so the server self tests can pass. I wonder if these tests should be in a different place at some point?

Also, I fixed a bunch of static analysis errors. Docstrings for many new tests were not imperative, so I tried to make them consistent since pep257 complained about some of them.

The last change adds a git config command to set the email address so that the git test can run on a system where the user has never configured their email address.

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

The test/__init__.py file was already added in the past:
https://code.launchpad.net/~doanac/utah/server-cleanups/+merge/159705

but it breaks packaging because the test files are included in multiple binary packages. I guess that one of this should fix the problem:
- an update to debian/*.install files
- an updated to setup.py to exclude the test package

review: Needs Fixing
lp:~nuclearbob/utah/various-fixes updated
881. By Javier Collado

Merged changes to consolidate scripts functionality

Source branch: lp:~nuclearbob/utah/consolidate-scripts

882. By Javier Collado

Updated version number to upload to PPA

886. By Max Brustkern

Moved to using explicit package selection

887. By Max Brustkern

Collapsed vm directory into a single file

888. By Max Brustkern

Collapsed inventory directory into one file

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

I changed setup.py to explicitly define the packages used. I also eliminated the utah.provisioning.vm and utah.provisioning.inventory packages.

review: Needs Resubmitting
lp:~nuclearbob/utah/various-fixes updated
889. By Max Brustkern

Removed distribute

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

Looks good. Thanks.

I tested the changes and they worked fine using a saucy desktop i386 image. In my test I also removed the utah client deb, since that is no longer needed. I'll take care of that when the changes are merged (once the new release has been created).

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

Merged. Thanks for the update in the test cases docstrings by the way.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'distribute-0.6.25-py2.7.egg'
2Binary files distribute-0.6.25-py2.7.egg 2012-06-01 22:04:50 +0000 and distribute-0.6.25-py2.7.egg 1970-01-01 00:00:00 +0000 differ
3=== removed file 'distribute-0.6.25.tar.gz'
4Binary files distribute-0.6.25.tar.gz 2012-04-12 15:36:27 +0000 and distribute-0.6.25.tar.gz 1970-01-01 00:00:00 +0000 differ
5=== removed file 'distribute_setup.py'
6--- distribute_setup.py 2012-12-05 12:08:46 +0000
7+++ distribute_setup.py 1970-01-01 00:00:00 +0000
8@@ -1,485 +0,0 @@
9-#!python
10-# flake8: noqa
11-
12-"""
13-Bootstrap distribute installation
14-
15-If you want to use setuptools in your package's setup.py, just include this
16-file in the same directory with it, and add this to the top of your setup.py::
17-
18- from distribute_setup import use_setuptools
19- use_setuptools()
20-
21-If you want to require a specific version of setuptools, set a download
22-mirror, or use an alternate download directory, you can do so by supplying
23-the appropriate options to ``use_setuptools()``.
24-
25-This file can also be run as a script to install or upgrade setuptools.
26-"""
27-import os
28-import sys
29-import time
30-import fnmatch
31-import tempfile
32-import tarfile
33-from distutils import log
34-
35-try:
36- from site import USER_SITE
37-except ImportError:
38- USER_SITE = None
39-
40-try:
41- import subprocess
42-
43- def _python_cmd(*args):
44- args = (sys.executable,) + args
45- return subprocess.call(args) == 0
46-
47-except ImportError:
48- # will be used for python 2.3
49- def _python_cmd(*args):
50- args = (sys.executable,) + args
51- # quoting arguments if windows
52- if sys.platform == 'win32':
53- def quote(arg):
54- if ' ' in arg:
55- return '"%s"' % arg
56- return arg
57- args = [quote(arg) for arg in args]
58- return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
59-
60-DEFAULT_VERSION = "0.6.25"
61-DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
62-SETUPTOOLS_FAKED_VERSION = "0.6c11"
63-
64-SETUPTOOLS_PKG_INFO = """\
65-Metadata-Version: 1.0
66-Name: setuptools
67-Version: %s
68-Summary: xxxx
69-Home-page: xxx
70-Author: xxx
71-Author-email: xxx
72-License: xxx
73-Description: xxx
74-""" % SETUPTOOLS_FAKED_VERSION
75-
76-
77-def _install(tarball, install_args=()):
78- # extracting the tarball
79- tmpdir = tempfile.mkdtemp()
80- log.warn('Extracting in %s', tmpdir)
81- old_wd = os.getcwd()
82- try:
83- os.chdir(tmpdir)
84- tar = tarfile.open(tarball)
85- _extractall(tar)
86- tar.close()
87-
88- # going in the directory
89- subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
90- os.chdir(subdir)
91- log.warn('Now working in %s', subdir)
92-
93- # installing
94- log.warn('Installing Distribute')
95- if not _python_cmd('setup.py', 'install', *install_args):
96- log.warn('Something went wrong during the installation.')
97- log.warn('See the error message above.')
98- finally:
99- os.chdir(old_wd)
100-
101-
102-def _build_egg(egg, tarball, to_dir):
103- # extracting the tarball
104- tmpdir = tempfile.mkdtemp()
105- log.warn('Extracting in %s', tmpdir)
106- old_wd = os.getcwd()
107- try:
108- os.chdir(tmpdir)
109- tar = tarfile.open(tarball)
110- _extractall(tar)
111- tar.close()
112-
113- # going in the directory
114- subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
115- os.chdir(subdir)
116- log.warn('Now working in %s', subdir)
117-
118- # building an egg
119- log.warn('Building a Distribute egg in %s', to_dir)
120- _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
121-
122- finally:
123- os.chdir(old_wd)
124- # returning the result
125- log.warn(egg)
126- if not os.path.exists(egg):
127- raise IOError('Could not build the egg.')
128-
129-
130-def _do_download(version, download_base, to_dir, download_delay):
131- egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
132- % (version, sys.version_info[0], sys.version_info[1]))
133- if not os.path.exists(egg):
134- tarball = download_setuptools(version, download_base,
135- to_dir, download_delay)
136- _build_egg(egg, tarball, to_dir)
137- sys.path.insert(0, egg)
138- import setuptools
139- setuptools.bootstrap_install_from = egg
140-
141-
142-def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
143- to_dir=os.curdir, download_delay=15, no_fake=True):
144- # making sure we use the absolute path
145- to_dir = os.path.abspath(to_dir)
146- was_imported = 'pkg_resources' in sys.modules or \
147- 'setuptools' in sys.modules
148- try:
149- try:
150- import pkg_resources
151- if not hasattr(pkg_resources, '_distribute'):
152- if not no_fake:
153- _fake_setuptools()
154- raise ImportError
155- except ImportError:
156- return _do_download(version, download_base, to_dir, download_delay)
157- try:
158- pkg_resources.require("distribute>="+version)
159- return
160- except pkg_resources.VersionConflict:
161- e = sys.exc_info()[1]
162- if was_imported:
163- sys.stderr.write(
164- "The required version of distribute (>=%s) is not available,\n"
165- "and can't be installed while this script is running. Please\n"
166- "install a more recent version first, using\n"
167- "'easy_install -U distribute'."
168- "\n\n(Currently using %r)\n" % (version, e.args[0]))
169- sys.exit(2)
170- else:
171- del pkg_resources, sys.modules['pkg_resources'] # reload ok
172- return _do_download(version, download_base, to_dir,
173- download_delay)
174- except pkg_resources.DistributionNotFound:
175- return _do_download(version, download_base, to_dir,
176- download_delay)
177- finally:
178- if not no_fake:
179- _create_fake_setuptools_pkg_info(to_dir)
180-
181-def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
182- to_dir=os.curdir, delay=15):
183- """Download distribute from a specified location and return its filename
184-
185- `version` should be a valid distribute version number that is available
186- as an egg for download under the `download_base` URL (which should end
187- with a '/'). `to_dir` is the directory where the egg will be downloaded.
188- `delay` is the number of seconds to pause before an actual download
189- attempt.
190- """
191- # making sure we use the absolute path
192- to_dir = os.path.abspath(to_dir)
193- try:
194- from urllib.request import urlopen
195- except ImportError:
196- from urllib2 import urlopen
197- tgz_name = "distribute-%s.tar.gz" % version
198- url = download_base + tgz_name
199- saveto = os.path.join(to_dir, tgz_name)
200- src = dst = None
201- if not os.path.exists(saveto): # Avoid repeated downloads
202- try:
203- log.warn("Downloading %s", url)
204- src = urlopen(url)
205- # Read/write all in one block, so we don't create a corrupt file
206- # if the download is interrupted.
207- data = src.read()
208- dst = open(saveto, "wb")
209- dst.write(data)
210- finally:
211- if src:
212- src.close()
213- if dst:
214- dst.close()
215- return os.path.realpath(saveto)
216-
217-def _no_sandbox(function):
218- def __no_sandbox(*args, **kw):
219- try:
220- from setuptools.sandbox import DirectorySandbox
221- if not hasattr(DirectorySandbox, '_old'):
222- def violation(*args):
223- pass
224- DirectorySandbox._old = DirectorySandbox._violation
225- DirectorySandbox._violation = violation
226- patched = True
227- else:
228- patched = False
229- except ImportError:
230- patched = False
231-
232- try:
233- return function(*args, **kw)
234- finally:
235- if patched:
236- DirectorySandbox._violation = DirectorySandbox._old
237- del DirectorySandbox._old
238-
239- return __no_sandbox
240-
241-def _patch_file(path, content):
242- """Will backup the file then patch it"""
243- existing_content = open(path).read()
244- if existing_content == content:
245- # already patched
246- log.warn('Already patched.')
247- return False
248- log.warn('Patching...')
249- _rename_path(path)
250- with open(path, 'w') as f:
251- f.write(content)
252- return True
253-
254-_patch_file = _no_sandbox(_patch_file)
255-
256-def _same_content(path, content):
257- return open(path).read() == content
258-
259-def _rename_path(path):
260- new_name = path + '.OLD.%s' % time.time()
261- log.warn('Renaming %s into %s', path, new_name)
262- os.rename(path, new_name)
263- return new_name
264-
265-def _remove_flat_installation(placeholder):
266- if not os.path.isdir(placeholder):
267- log.warn('Unkown installation at %s', placeholder)
268- return False
269- found = False
270- for file in os.listdir(placeholder):
271- if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
272- found = True
273- break
274- if not found:
275- log.warn('Could not locate setuptools*.egg-info')
276- return
277-
278- log.warn('Removing elements out of the way...')
279- pkg_info = os.path.join(placeholder, file)
280- if os.path.isdir(pkg_info):
281- patched = _patch_egg_dir(pkg_info)
282- else:
283- patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
284-
285- if not patched:
286- log.warn('%s already patched.', pkg_info)
287- return False
288- # now let's move the files out of the way
289- for element in ('setuptools', 'pkg_resources.py', 'site.py'):
290- element = os.path.join(placeholder, element)
291- if os.path.exists(element):
292- _rename_path(element)
293- else:
294- log.warn('Could not find the %s element of the '
295- 'Setuptools distribution', element)
296- return True
297-
298-_remove_flat_installation = _no_sandbox(_remove_flat_installation)
299-
300-def _after_install(dist):
301- log.warn('After install bootstrap.')
302- placeholder = dist.get_command_obj('install').install_purelib
303- _create_fake_setuptools_pkg_info(placeholder)
304-
305-def _create_fake_setuptools_pkg_info(placeholder):
306- if not placeholder or not os.path.exists(placeholder):
307- log.warn('Could not find the install location')
308- return
309- pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
310- setuptools_file = 'setuptools-%s-py%s.egg-info' % \
311- (SETUPTOOLS_FAKED_VERSION, pyver)
312- pkg_info = os.path.join(placeholder, setuptools_file)
313- if os.path.exists(pkg_info):
314- log.warn('%s already exists', pkg_info)
315- return
316-
317- log.warn('Creating %s', pkg_info)
318- with open(pkg_info, 'w') as f:
319- f.write(SETUPTOOLS_PKG_INFO)
320-
321- pth_file = os.path.join(placeholder, 'setuptools.pth')
322- log.warn('Creating %s', pth_file)
323- with open(pth_file, 'w') as f:
324- f.write(os.path.join(os.curdir, setuptools_file))
325-
326-_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
327-
328-def _patch_egg_dir(path):
329- # let's check if it's already patched
330- pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
331- if os.path.exists(pkg_info):
332- if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
333- log.warn('%s already patched.', pkg_info)
334- return False
335- _rename_path(path)
336- os.mkdir(path)
337- os.mkdir(os.path.join(path, 'EGG-INFO'))
338- pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
339- with open(pkg_info, 'w') as f:
340- f.write(SETUPTOOLS_PKG_INFO)
341- return True
342-
343-_patch_egg_dir = _no_sandbox(_patch_egg_dir)
344-
345-def _before_install():
346- log.warn('Before install bootstrap.')
347- _fake_setuptools()
348-
349-
350-def _under_prefix(location):
351- if 'install' not in sys.argv:
352- return True
353- args = sys.argv[sys.argv.index('install')+1:]
354- for index, arg in enumerate(args):
355- for option in ('--root', '--prefix'):
356- if arg.startswith('%s=' % option):
357- top_dir = arg.split('root=')[-1]
358- return location.startswith(top_dir)
359- elif arg == option:
360- if len(args) > index:
361- top_dir = args[index+1]
362- return location.startswith(top_dir)
363- if arg == '--user' and USER_SITE is not None:
364- return location.startswith(USER_SITE)
365- return True
366-
367-
368-def _fake_setuptools():
369- log.warn('Scanning installed packages')
370- try:
371- import pkg_resources
372- except ImportError:
373- # we're cool
374- log.warn('Setuptools or Distribute does not seem to be installed.')
375- return
376- ws = pkg_resources.working_set
377- try:
378- setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
379- replacement=False))
380- except TypeError:
381- # old distribute API
382- setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
383-
384- if setuptools_dist is None:
385- log.warn('No setuptools distribution found')
386- return
387- # detecting if it was already faked
388- setuptools_location = setuptools_dist.location
389- log.warn('Setuptools installation detected at %s', setuptools_location)
390-
391- # if --root or --preix was provided, and if
392- # setuptools is not located in them, we don't patch it
393- if not _under_prefix(setuptools_location):
394- log.warn('Not patching, --root or --prefix is installing Distribute'
395- ' in another location')
396- return
397-
398- # let's see if its an egg
399- if not setuptools_location.endswith('.egg'):
400- log.warn('Non-egg installation')
401- res = _remove_flat_installation(setuptools_location)
402- if not res:
403- return
404- else:
405- log.warn('Egg installation')
406- pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
407- if (os.path.exists(pkg_info) and
408- _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
409- log.warn('Already patched.')
410- return
411- log.warn('Patching...')
412- # let's create a fake egg replacing setuptools one
413- res = _patch_egg_dir(setuptools_location)
414- if not res:
415- return
416- log.warn('Patched done.')
417- _relaunch()
418-
419-
420-def _relaunch():
421- log.warn('Relaunching...')
422- # we have to relaunch the process
423- # pip marker to avoid a relaunch bug
424- if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
425- sys.argv[0] = 'setup.py'
426- args = [sys.executable] + sys.argv
427- sys.exit(subprocess.call(args))
428-
429-
430-def _extractall(self, path=".", members=None):
431- """Extract all members from the archive to the current working
432- directory and set owner, modification time and permissions on
433- directories afterwards. `path' specifies a different directory
434- to extract to. `members' is optional and must be a subset of the
435- list returned by getmembers().
436- """
437- import copy
438- import operator
439- from tarfile import ExtractError
440- directories = []
441-
442- if members is None:
443- members = self
444-
445- for tarinfo in members:
446- if tarinfo.isdir():
447- # Extract directories with a safe mode.
448- directories.append(tarinfo)
449- tarinfo = copy.copy(tarinfo)
450- tarinfo.mode = 448 # decimal for oct 0700
451- self.extract(tarinfo, path)
452-
453- # Reverse sort directories.
454- if sys.version_info < (2, 4):
455- def sorter(dir1, dir2):
456- return cmp(dir1.name, dir2.name)
457- directories.sort(sorter)
458- directories.reverse()
459- else:
460- directories.sort(key=operator.attrgetter('name'), reverse=True)
461-
462- # Set correct owner, mtime and filemode on directories.
463- for tarinfo in directories:
464- dirpath = os.path.join(path, tarinfo.name)
465- try:
466- self.chown(tarinfo, dirpath)
467- self.utime(tarinfo, dirpath)
468- self.chmod(tarinfo, dirpath)
469- except ExtractError:
470- e = sys.exc_info()[1]
471- if self.errorlevel > 1:
472- raise
473- else:
474- self._dbg(1, "tarfile: %s" % e)
475-
476-def _build_install_args(argv):
477- install_args = []
478- user_install = '--user' in argv
479- if user_install and sys.version_info < (2,6):
480- log.warn("--user requires Python 2.6 or later")
481- raise SystemExit(1)
482- if user_install:
483- install_args.append('--user')
484- return install_args
485-
486-def main(argv, version=DEFAULT_VERSION):
487- """Install or upgrade setuptools and EasyInstall"""
488- tarball = download_setuptools()
489- _install(tarball, _build_install_args(argv))
490-
491-
492-if __name__ == '__main__':
493- main(sys.argv[1:])
494
495=== modified file 'docs/source/reference.rst'
496--- docs/source/reference.rst 2013-04-24 10:32:29 +0000
497+++ docs/source/reference.rst 2013-05-02 18:27:25 +0000
498@@ -106,6 +106,9 @@
499 .. automodule:: utah.provisioning.exceptions
500 :members:
501
502+.. automodule:: utah.provisioning.inventory
503+ :members:
504+
505 .. automodule:: utah.provisioning.provisioning
506 :members:
507
508@@ -115,6 +118,9 @@
509 .. automodule:: utah.provisioning.ssh
510 :members:
511
512+.. automodule:: utah.provisioning.vm
513+ :members:
514+
515 ``utah.provisioning.baremetal``
516 -------------------------------
517
518@@ -131,29 +137,3 @@
519
520 .. automodule:: utah.provisioning.baremetal.exceptions
521 :members:
522-
523-``utah.provisioning.inventory``
524--------------------------------
525-
526-.. automodule:: utah.provisioning.inventory
527-
528-.. automodule:: utah.provisioning.inventory.exceptions
529- :members:
530-
531-.. automodule:: utah.provisioning.inventory.inventory
532- :members:
533-
534-.. automodule:: utah.provisioning.inventory.sqlite
535- :members:
536-
537-``utah.provisioning.vm``
538--------------------------
539-
540-.. automodule:: utah.provisioning.vm
541-
542-.. automodule:: utah.provisioning.vm.exceptions
543- :members:
544-
545-.. automodule:: utah.provisioning.vm.vm
546- :members:
547-
548
549=== modified file 'examples/run_utah_tests.py'
550--- examples/run_utah_tests.py 2013-05-01 18:04:36 +0000
551+++ examples/run_utah_tests.py 2013-05-02 18:27:25 +0000
552@@ -36,7 +36,7 @@
553 from utah.provisioning.baremetal.inventory import \
554 ManualBaremetalSQLiteInventory
555 from utah.provisioning.ssh import ProvisionedMachine
556-from utah.provisioning.vm.vm import TinySQLiteInventory
557+from utah.provisioning.vm import TinySQLiteInventory
558 from utah.run import (
559 configure_logging,
560 master_runlist_argument,
561
562=== modified file 'setup.py'
563--- setup.py 2013-04-10 20:13:44 +0000
564+++ setup.py 2013-05-02 18:27:25 +0000
565@@ -18,13 +18,12 @@
566 """Provide installation information for setuptools."""
567
568
569-import distribute_setup
570-distribute_setup.use_setuptools()
571-from setuptools import setup, find_packages
572-
573 import os
574 import re
575
576+from setuptools import setup
577+
578+
579 # look/set what version we have
580 version = "0.0"
581 changelog = "debian/changelog"
582@@ -48,7 +47,10 @@
583 setup(
584 name='utah',
585 version=version,
586- packages=find_packages(),
587+ packages=['utah',
588+ 'utah.client',
589+ 'utah.provisioning',
590+ 'utah.provisioning.baremetal'],
591 maintainer=maintainer,
592 maintainer_email=maintainer_email,
593 )
594
595=== added file 'tests/__init__.py'
596--- tests/__init__.py 1970-01-01 00:00:00 +0000
597+++ tests/__init__.py 2013-05-02 18:27:25 +0000
598@@ -0,0 +1,16 @@
599+# Ubuntu Testing Automation Harness
600+# Copyright 2012 Canonical Ltd.
601+
602+# This program is free software: you can redistribute it and/or modify it
603+# under the terms of the GNU General Public License version 3, as published
604+# by the Free Software Foundation.
605+
606+# This program is distributed in the hope that it will be useful, but
607+# WITHOUT ANY WARRANTY; without even the implied warranties of
608+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
609+# PURPOSE. See the GNU General Public License for more details.
610+
611+# You should have received a copy of the GNU General Public License along
612+# with this program. If not, see <http://www.gnu.org/licenses/>.
613+
614+"""server self tests"""
615
616=== modified file 'tests/test_rsyslog.py'
617--- tests/test_rsyslog.py 2013-04-24 11:37:21 +0000
618+++ tests/test_rsyslog.py 2013-05-02 18:27:25 +0000
619@@ -253,7 +253,7 @@
620 self.usefile(True)
621
622 def test_timeout(self):
623- """UTAHTimeout is raised on timeout"""
624+ """Verify UTAHTimeout is raised on timeout."""
625 steps = [
626 {
627 "message": "message_1",
628
629=== modified file 'utah/client/common.py'
630--- utah/client/common.py 2013-04-25 14:12:49 +0000
631+++ utah/client/common.py 2013-05-02 18:27:25 +0000
632@@ -115,7 +115,7 @@
633
634 # Process queue stuff inspired by:
635 # http://stackoverflow.com/a/4896288
636-def enqueue_output(out, queue):
637+def _enqueue_output(out, queue):
638 for line in iter(out.readline, b''):
639 queue.put(line)
640 out.close()
641@@ -195,10 +195,10 @@
642 signal.signal(signal.SIGALRM, alarm_handler)
643 signal.alarm(timeout)
644
645- outt = Thread(target=enqueue_output, args=(p.stdout, outq))
646+ outt = Thread(target=_enqueue_output, args=(p.stdout, outq))
647 outt.daemon = True
648 outt.start()
649- errt = Thread(target=enqueue_output, args=(p.stderr, errq))
650+ errt = Thread(target=_enqueue_output, args=(p.stderr, errq))
651 errt.daemon = True
652 errt.start()
653
654@@ -416,6 +416,7 @@
655
656 @classmethod
657 def check_schema(self, schema):
658+ """Call the superclass directly since super doesn't work here."""
659 jsonschema.Draft4Validator.check_schema(schema)
660
661 def validate_properties(self, properties, instance, schema):
662
663=== modified file 'utah/client/tests/test_runner.py'
664--- utah/client/tests/test_runner.py 2013-05-01 17:37:58 +0000
665+++ utah/client/tests/test_runner.py 2013-05-02 18:27:25 +0000
666@@ -49,7 +49,7 @@
667 self.result_class = ResultYAML
668 self.state_file = '/tmp/state.yaml'
669 self.state_agent = StateAgentYAML(state_file=self.state_file)
670- self.output_file='/tmp/utah.out'
671+ self.output_file = '/tmp/utah.out'
672 self.runner = Runner(install_type='desktop',
673 result_class=self.result_class,
674 state_agent=self.state_agent,
675@@ -202,27 +202,36 @@
676
677
678 class TestRunnerMasterRunlistSchema(unittest.TestCase):
679- """Master runlist schema test cases."""
680+
681+ """Provide master runlist schema test cases."""
682+
683 def setUp(self):
684+ """Setup needed resources."""
685 schema = Runner.MASTER_RUNLIST_SCHEMA
686 DefaultValidator.check_schema(schema)
687 self.validator = DefaultValidator(schema)
688
689 def validate(self, data):
690+ """Validate a schema.
691+
692+ :returns: validates schema
693+ :rtype: object
694+
695+ """
696 return self.validator.validate(data)
697
698 def test_empty_string_invalid(self):
699- """An empty string doesn't validate."""
700+ """Verify an empty string doesn't validate."""
701 with self.assertRaises(jsonschema.ValidationError):
702 self.validate('')
703
704 def test_empty_dict_invalid(self):
705- """An empty dictionary is invalid."""
706+ """Verify an empty dictionary is invalid."""
707 with self.assertRaises(jsonschema.ValidationError):
708 self.validate({})
709
710 def test_valid(self):
711- """An example of valid data."""
712+ """Verify valid data works."""
713 self.validate({
714 'testsuites': [{
715 'name': 'name',
716@@ -232,21 +241,21 @@
717 })
718
719 def test_testsuites_required(self):
720- """A list of test suites is required."""
721+ """Verify a list of test suites is required."""
722 with self.assertRaises(jsonschema.ValidationError):
723 self.validate({
724 'battery_measurements': True,
725 })
726
727 def test_testsuites_empty_invalid(self):
728- """An empty list of test suites is invalid."""
729+ """Verify an empty list of test suites is invalid."""
730 with self.assertRaises(jsonschema.ValidationError):
731 self.validate({
732 'testsuites': [],
733 })
734
735 def test_testsuite_name_required(self):
736- """Test suite name is required."""
737+ """Verify test suite name is required."""
738 with self.assertRaises(jsonschema.ValidationError):
739 self.validate({
740 'testsuites': [{
741@@ -256,7 +265,7 @@
742 })
743
744 def test_testsuite_fetch_method_required(self):
745- """Test suite fetch method is required."""
746+ """Verify test suite fetch method is required."""
747 with self.assertRaises(jsonschema.ValidationError):
748 self.validate({
749 'testsuites': [{
750@@ -266,7 +275,7 @@
751 })
752
753 def test_testsuite_fetch_method_known_values(self):
754- """Test suite fetch method known values are valid."""
755+ """Verify test suite fetch method known values are valid."""
756 testsuite = {
757 'name': 'name',
758 'fetch_location': 'fetch location',
759@@ -279,7 +288,7 @@
760 self.validate(data)
761
762 def test_testsuite_fetch_method_unknown_value(self):
763- """Test suite fetch method unknown values are valid."""
764+ """Verify test suite fetch method unknown values are valid."""
765 with self.assertRaises(jsonschema.ValidationError):
766 self.validate({
767 'testsuites': [{
768@@ -290,7 +299,7 @@
769 })
770
771 def test_testsuite_fetch_location_required(self):
772- """Test suite fetch location is required."""
773+ """Verify test suite fetch location is required."""
774 with self.assertRaises(jsonschema.ValidationError):
775 self.validate({
776 'testsuites': [{
777@@ -300,7 +309,7 @@
778 })
779
780 def test_testsuite_include_tests_empty_invalid(self):
781- """Empty list of included tests is invalid."""
782+ """Verify an empty list of included tests is invalid."""
783 with self.assertRaises(jsonschema.ValidationError):
784 self.validate({
785 'testsuites': [{
786@@ -312,7 +321,7 @@
787 })
788
789 def test_testsuite_include_tests_string(self):
790- """List of strings as included tests is valid."""
791+ """Verify a list of strings as included tests is valid."""
792 self.validate({
793 'testsuites': [{
794 'name': 'name',
795@@ -323,7 +332,7 @@
796 })
797
798 def test_testsuite_exclude_tests_empty_invalid(self):
799- """Empty list of excluded tests is invalid."""
800+ """Verify an empty list of excluded tests is invalid."""
801 with self.assertRaises(jsonschema.ValidationError):
802 self.validate({
803 'testsuites': [{
804@@ -335,7 +344,7 @@
805 })
806
807 def test_testsuite_exclude_tests_string(self):
808- """List of strings as excluded tests is valid."""
809+ """Verify a list of strings as excluded tests is valid."""
810 self.validate({
811 'testsuites': [{
812 'name': 'name',
813@@ -346,7 +355,7 @@
814 })
815
816 def test_battery_measurements_false_by_default(self):
817- """Battery measurements is false by default"""
818+ """Verify battery measurements is false by default."""
819 data = {
820 'testsuites': [{
821 'name': 'name',
822@@ -358,7 +367,7 @@
823 self.assertFalse(data['battery_measurements'])
824
825 def test_battery_measurements_string_invalid(self):
826- """A battery measurements string value is invalid"""
827+ """Verify battery measurements string value is invalid."""
828 with self.assertRaises(jsonschema.ValidationError):
829 self.validate({
830 'testsuites': [{
831@@ -370,7 +379,7 @@
832 })
833
834 def test_battery_measurements_boolean_valid(self):
835- """A battery measurements boolean value is valid"""
836+ """Verify a battery measurements boolean value is valid."""
837 self.validate({
838 'testsuites': [{
839 'name': 'name',
840@@ -381,7 +390,7 @@
841 })
842
843 def test_zero_timeout_invalid(self):
844- """A zero timeout is invalid"""
845+ """Verify a zero timeout is invalid."""
846 with self.assertRaises(jsonschema.ValidationError):
847 self.validate({
848 'testsuites': [{
849@@ -393,7 +402,7 @@
850 })
851
852 def test_negative_timeout_invalid(self):
853- """A negative timeout is invalid"""
854+ """Verify a negative timeout is invalid."""
855 with self.assertRaises(jsonschema.ValidationError):
856 self.validate({
857 'testsuites': [{
858@@ -405,7 +414,7 @@
859 })
860
861 def test_repeat_count_zero_by_default(self):
862- """Repeat count is zero by default"""
863+ """Verify repeat count is zero by default."""
864 data = {
865 'testsuites': [{
866 'name': 'name',
867@@ -418,7 +427,7 @@
868 self.assertEqual(data['repeat_count'], 0)
869
870 def test_negative_repeat_count_invalid(self):
871- """A negative repeat count is invalid"""
872+ """Verift. negative repeat count is invalid."""
873 with self.assertRaises(jsonschema.ValidationError):
874 self.validate({
875 'testsuites': [{
876
877=== modified file 'utah/client/tests/test_testcase.py'
878--- utah/client/tests/test_testcase.py 2013-04-29 21:04:46 +0000
879+++ utah/client/tests/test_testcase.py 2013-05-02 18:27:25 +0000
880@@ -143,13 +143,22 @@
881
882
883 class TestTestCaseControlSchema(unittest.TestCase):
884+
885 """Test case control schema test cases."""
886- def setUp(self,):
887+
888+ def setUp(self):
889+ """Setup needed resources."""
890 schema = testcase.TestCase.CONTROL_SCHEMA
891 DefaultValidator.check_schema(schema)
892 self.validator = DefaultValidator(schema)
893
894 def validate(self, data):
895+ """Validate a schema.
896+
897+ :returns: validates schema
898+ :rtype: object
899+
900+ """
901 schema = testcase.TestCase.CONTROL_SCHEMA
902 return jsonschema.validate(data, schema)
903
904@@ -164,7 +173,7 @@
905 self.validate({})
906
907 def test_valid(self):
908- """An example of valid data."""
909+ """Verify valid data works."""
910 self.validate({
911 'description': 'description',
912 'dependencies': 'dependencies',
913@@ -175,7 +184,7 @@
914 })
915
916 def test_description_required(self):
917- """Description is a required property."""
918+ """Verify description is a required property."""
919 with self.assertRaises(jsonschema.ValidationError):
920 self.validate({
921 'dependencies': 'dependencies',
922@@ -186,7 +195,7 @@
923 })
924
925 def test_dependencies_required(self):
926- """Dependencies is a required property."""
927+ """Verify dependencies is a required property."""
928 with self.assertRaises(jsonschema.ValidationError):
929 self.validate({
930 'description': 'description',
931@@ -197,7 +206,7 @@
932 })
933
934 def test_action_required(self):
935- """Action is a required property."""
936+ """Verify action is a required property."""
937 with self.assertRaises(jsonschema.ValidationError):
938 self.validate({
939 'description': 'description',
940@@ -208,7 +217,7 @@
941 })
942
943 def test_expected_results_required(self):
944- """Expected results is a required property."""
945+ """Verify expected results is a required property."""
946 with self.assertRaises(jsonschema.ValidationError):
947 self.validate({
948 'description': 'description',
949@@ -219,7 +228,7 @@
950 })
951
952 def test_command_required(self):
953- """Command is a required property."""
954+ """Verify command is a required property."""
955 with self.assertRaises(jsonschema.ValidationError):
956 self.validate({
957 'description': 'description',
958@@ -230,7 +239,7 @@
959 })
960
961 def test_zero_timeout_invalid(self):
962- """A zero timeout is invalid"""
963+ """Verify a zero timeout is invalid."""
964 with self.assertRaises(jsonschema.ValidationError):
965 self.validate({
966 'description': 'description',
967@@ -243,7 +252,7 @@
968 })
969
970 def test_negative_timeout_invalid(self):
971- """A negative timeout is invalid"""
972+ """Verify a negative timeout is invalid."""
973 with self.assertRaises(jsonschema.ValidationError):
974 self.validate({
975 'description': 'description',
976@@ -256,7 +265,7 @@
977 })
978
979 def test_type_userland_valid(self):
980- """Userland type is valid."""
981+ """Verify userland type is valid."""
982 self.validate({
983 'description': 'description',
984 'dependencies': 'dependencies',
985@@ -268,7 +277,7 @@
986 })
987
988 def test_type_unknown_invalid(self):
989- """Unknown type is valid."""
990+ """Verify unknown type is valid."""
991 with self.assertRaises(jsonschema.ValidationError):
992 self.validate({
993 'description': 'description',
994@@ -281,7 +290,7 @@
995 })
996
997 def test_reboot_known_valid(self):
998- """Reboot known values are valid."""
999+ """Verify reboot known values are valid."""
1000 data = {
1001 'description': 'description',
1002 'dependencies': 'dependencies',
1003@@ -296,7 +305,7 @@
1004 self.validate(data)
1005
1006 def test_unknown_reboot_invalid(self):
1007- """Reboot unknown value is invalid."""
1008+ """Verify reboot unknown value is invalid."""
1009 with self.assertRaises(jsonschema.ValidationError):
1010 self.validate({
1011 'description': 'description',
1012
1013=== modified file 'utah/client/tests/test_testsuite.py'
1014--- utah/client/tests/test_testsuite.py 2013-04-25 14:14:19 +0000
1015+++ utah/client/tests/test_testsuite.py 2013-05-02 18:27:25 +0000
1016@@ -163,43 +163,51 @@
1017
1018
1019 class TestTestSuiteRunlistSchema(unittest.TestCase):
1020+
1021 """Test suite run list schema test cases."""
1022
1023 def setUp(self):
1024+ """Initialize basic test case data."""
1025 schema = testsuite.TestSuite.RUNLIST_SCHEMA
1026 DefaultValidator.check_schema(schema)
1027 self.validator = DefaultValidator(schema)
1028
1029 def validate(self, data):
1030+ """Validate a schema.
1031+
1032+ :returns: validates schema
1033+ :rtype: object
1034+
1035+ """
1036 return self.validator.validate(data)
1037
1038 def test_empty_string_invalid(self):
1039- """An empty string doesn't validate."""
1040+ """Verify an empty string doesn't validate."""
1041 with self.assertRaises(jsonschema.ValidationError):
1042 self.validate('')
1043
1044 def test_empty_dict_invalid(self):
1045- """An empty dictionary doesn't validate."""
1046+ """Verify an empty dictionary doesn't validate."""
1047 with self.assertRaises(jsonschema.ValidationError):
1048 self.validate({})
1049
1050 def test_empty_list_invalid(self):
1051- """An empty list doesn't validate."""
1052+ """Verify an empty list doesn't validate."""
1053 with self.assertRaises(jsonschema.ValidationError):
1054 self.validate([])
1055
1056 def test_string_list_invalid(self):
1057- """A list of strings is invalid."""
1058+ """Verify a list of strings is invalid."""
1059 with self.assertRaises(jsonschema.ValidationError):
1060 self.validate(['a', 'b', 'c'])
1061
1062 def test_empty_dict_list_invalid(self):
1063- """A list of empty dictionaries is invalid."""
1064+ """Verify a list of empty dictionaries is invalid."""
1065 with self.assertRaises(jsonschema.ValidationError):
1066 self.validate([{}, {}, {}])
1067
1068 def test_unknown_test_property_invalid(self):
1069- """An unknown property in a test object invalid."""
1070+ """Verify an unknown property in a test object invalid."""
1071 with self.assertRaises(jsonschema.ValidationError):
1072 self.validate(
1073 [{'test': 'test name',
1074@@ -207,13 +215,13 @@
1075 }])
1076
1077 def test_empty_overrides_invalid(self):
1078- """An empty overrides section is invalid."""
1079+ """Verify an empty overrides section is invalid."""
1080 with self.assertRaises(jsonschema.ValidationError):
1081 self.validate([{'test': 'test name',
1082 'overrides': {}}])
1083
1084 def test_unknown_property_in_overrides_invalid(self):
1085- """An unknown property in overrides section is invalid."""
1086+ """Verify an unknown property in overrides section is invalid."""
1087 with self.assertRaises(jsonschema.ValidationError):
1088 self.validate(
1089 [{'test': 'test name',
1090@@ -221,25 +229,25 @@
1091 }])
1092
1093 def test_zero_timeout_invalid(self):
1094- """A zero timeout is invalid"""
1095+ """Verify a zero timeout is invalid."""
1096 with self.assertRaises(jsonschema.ValidationError):
1097 self.validate([{'test': 'test name',
1098 'overrides': {'timeout': 0}}])
1099
1100 def test_negative_timeout_invalid(self):
1101- """A negative timeout is invalid"""
1102+ """Verify a negative timeout is invalid."""
1103 with self.assertRaises(jsonschema.ValidationError):
1104 self.validate([{'test': 'test name',
1105 'overrides': {'timeout': -1}}])
1106
1107 def test_list_valid(self):
1108- """A list of test cases is valid."""
1109+ """Verify a list of test cases is valid."""
1110 self.validate(
1111 [{'test': 'test name'},
1112 {'test': 'test name 2'}])
1113
1114 def test_with_overrides_list_valid(self):
1115- """A list of test case names with overrides is valid."""
1116+ """Verify a list of test case names with overrides is valid."""
1117 self.validate([
1118 {'test': 'test name',
1119 'overrides': {'timeout': 1},
1120@@ -251,13 +259,22 @@
1121
1122
1123 class TestTestSuiteControlSchema(unittest.TestCase):
1124+
1125 """Test suite control schema test cases."""
1126+
1127 def setUp(self):
1128+ """Initialize basic test case data."""
1129 schema = testsuite.TestSuite.CONTROL_SCHEMA
1130 DefaultValidator.check_schema(schema)
1131 self.validator = DefaultValidator(schema)
1132
1133 def validate(self, data):
1134+ """Validate a schema.
1135+
1136+ :returns: validates schema
1137+ :rtype: object
1138+
1139+ """
1140 return self.validator.validate(data)
1141
1142 def test_empty_string_invalid(self):
1143
1144=== modified file 'utah/client/tests/test_vcs_git.py'
1145--- utah/client/tests/test_vcs_git.py 2013-04-05 19:32:58 +0000
1146+++ utah/client/tests/test_vcs_git.py 2013-05-02 18:27:25 +0000
1147@@ -33,6 +33,7 @@
1148 os.mkdir(GIT_TEST_REPO)
1149
1150 run_cmd("git init", cwd=GIT_TEST_REPO)
1151+ run_cmd('git config user.email "utah@launchpad.net"', cwd=GIT_TEST_REPO)
1152 run_cmd("touch test.py", cwd=GIT_TEST_REPO)
1153 run_cmd("git add test.py", cwd=GIT_TEST_REPO)
1154 run_cmd("git commit -m'Initial import' test.py", cwd=GIT_TEST_REPO)
1155
1156=== modified file 'utah/provisioning/baremetal/inventory.py'
1157--- utah/provisioning/baremetal/inventory.py 2013-04-10 15:42:26 +0000
1158+++ utah/provisioning/baremetal/inventory.py 2013-05-02 18:27:25 +0000
1159@@ -21,9 +21,10 @@
1160 import os
1161
1162 from utah.process import pid_in_use
1163-from utah.provisioning.inventory.exceptions import \
1164- UTAHProvisioningInventoryException
1165-from utah.provisioning.inventory.sqlite import SQLiteInventory
1166+from utah.provisioning.inventory import (
1167+ UTAHProvisioningInventoryException,
1168+ SQLiteInventory,
1169+)
1170
1171
1172 class ManualBaremetalSQLiteInventory(SQLiteInventory):
1173
1174=== removed directory 'utah/provisioning/inventory'
1175=== renamed file 'utah/provisioning/inventory/inventory.py' => 'utah/provisioning/inventory.py'
1176--- utah/provisioning/inventory/inventory.py 2013-04-04 15:39:49 +0000
1177+++ utah/provisioning/inventory.py 2013-05-02 18:27:25 +0000
1178@@ -16,9 +16,19 @@
1179 """Provide basic inventory routines."""
1180
1181
1182+import logging
1183 import os
1184-from utah.provisioning.inventory.exceptions import \
1185- UTAHProvisioningInventoryException
1186+import sqlite3
1187+
1188+from utah import config
1189+from utah.provisioning.exceptions import UTAHProvisioningException
1190+
1191+
1192+class UTAHProvisioningInventoryException(UTAHProvisioningException):
1193+
1194+ """Provide a class for UTAH provisioning inventory exceptions."""
1195+
1196+ pass
1197
1198
1199 class Inventory(object):
1200@@ -107,3 +117,49 @@
1201
1202 """
1203 return False
1204+
1205+
1206+class SQLiteInventory(Inventory):
1207+
1208+ """Provide basic SQLite database access with a cursor."""
1209+
1210+ def __init__(self, db='~/.utah-sqlite-inventory', *args, **kw):
1211+ db = os.path.expanduser(db)
1212+ super(SQLiteInventory, self).__init__(*args, uniqueid=db, **kw)
1213+ self.db = db
1214+ self._connection = sqlite3.connect(
1215+ self.db, config.sqlite3_db_connection_timeout)
1216+ self._connection.isolation_level = None
1217+ self._connection.row_factory = sqlite3.Row
1218+
1219+ def execute(self, sql, parameters=None):
1220+ """Execute SQL statement and return cursor.
1221+
1222+ This method is expected to be used as a wrapper around all
1223+ `connection.execute` calls so that all the SQL statements are logged in
1224+ case this information is needed to troubleshoot problems.
1225+
1226+ :param sql: A sql statement to be executed
1227+ :type sql: str
1228+ :param parameters:
1229+ Parameters to use to replace the placeholder
1230+ values in the sql statement.
1231+ :type parameters:
1232+ list (question mark placeholders) |
1233+ dict (colon named placeholders)
1234+ :returns: Cursor used to execute statement
1235+ :rtype: object
1236+
1237+ """
1238+ if parameters is None:
1239+ parameters = []
1240+
1241+ logging.debug('Executing SQL statement: {}, {}'
1242+ .format(sql, parameters))
1243+ cursor = self._connection.execute(sql, parameters)
1244+ return cursor
1245+
1246+ def delete(self):
1247+ """Remove database."""
1248+ os.unlink(self.db)
1249+ super(SQLiteInventory, self).delete()
1250
1251=== removed file 'utah/provisioning/inventory/__init__.py'
1252--- utah/provisioning/inventory/__init__.py 2013-04-04 13:42:40 +0000
1253+++ utah/provisioning/inventory/__init__.py 1970-01-01 00:00:00 +0000
1254@@ -1,16 +0,0 @@
1255-# Ubuntu Testing Automation Harness
1256-# Copyright 2012 Canonical Ltd.
1257-
1258-# This program is free software: you can redistribute it and/or modify it
1259-# under the terms of the GNU General Public License version 3, as published
1260-# by the Free Software Foundation.
1261-
1262-# This program is distributed in the hope that it will be useful, but
1263-# WITHOUT ANY WARRANTY; without even the implied warranties of
1264-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1265-# PURPOSE. See the GNU General Public License for more details.
1266-
1267-# You should have received a copy of the GNU General Public License along
1268-# with this program. If not, see <http://www.gnu.org/licenses/>.
1269-
1270-"""utah.provisioning.inventory"""
1271
1272=== removed file 'utah/provisioning/inventory/exceptions.py'
1273--- utah/provisioning/inventory/exceptions.py 2013-04-03 18:33:32 +0000
1274+++ utah/provisioning/inventory/exceptions.py 1970-01-01 00:00:00 +0000
1275@@ -1,26 +0,0 @@
1276-# Ubuntu Testing Automation Harness
1277-# Copyright 2012 Canonical Ltd.
1278-
1279-# This program is free software: you can redistribute it and/or modify it
1280-# under the terms of the GNU General Public License version 3, as published
1281-# by the Free Software Foundation.
1282-
1283-# This program is distributed in the hope that it will be useful, but
1284-# WITHOUT ANY WARRANTY; without even the implied warranties of
1285-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1286-# PURPOSE. See the GNU General Public License for more details.
1287-
1288-# You should have received a copy of the GNU General Public License along
1289-# with this program. If not, see <http://www.gnu.org/licenses/>.
1290-
1291-"""Provide exceptions specific to inventory issues."""
1292-
1293-
1294-from utah.provisioning.exceptions import UTAHProvisioningException
1295-
1296-
1297-class UTAHProvisioningInventoryException(UTAHProvisioningException):
1298-
1299- """Provide a class for UTAH provisioning inventory exceptions."""
1300-
1301- pass
1302
1303=== removed file 'utah/provisioning/inventory/sqlite.py'
1304--- utah/provisioning/inventory/sqlite.py 2013-04-04 14:55:25 +0000
1305+++ utah/provisioning/inventory/sqlite.py 1970-01-01 00:00:00 +0000
1306@@ -1,69 +0,0 @@
1307-# Ubuntu Testing Automation Harness
1308-# Copyright 2012 Canonical Ltd.
1309-
1310-# This program is free software: you can redistribute it and/or modify it
1311-# under the terms of the GNU General Public License version 3, as published
1312-# by the Free Software Foundation.
1313-
1314-# This program is distributed in the hope that it will be useful, but
1315-# WITHOUT ANY WARRANTY; without even the implied warranties of
1316-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1317-# PURPOSE. See the GNU General Public License for more details.
1318-
1319-# You should have received a copy of the GNU General Public License along
1320-# with this program. If not, see <http://www.gnu.org/licenses/>.
1321-"""Provide base class for SQLite-based inventories."""
1322-
1323-
1324-import sqlite3
1325-import os
1326-import logging
1327-
1328-from utah.provisioning.inventory.inventory import Inventory
1329-from utah import config
1330-
1331-
1332-class SQLiteInventory(Inventory):
1333-
1334- """Provide basic SQLite database access with a cursor."""
1335-
1336- def __init__(self, db='~/.utah-sqlite-inventory', *args, **kw):
1337- db = os.path.expanduser(db)
1338- super(SQLiteInventory, self).__init__(*args, uniqueid=db, **kw)
1339- self.db = db
1340- self._connection = sqlite3.connect(
1341- self.db, config.sqlite3_db_connection_timeout)
1342- self._connection.isolation_level = None
1343- self._connection.row_factory = sqlite3.Row
1344-
1345- def execute(self, sql, parameters=None):
1346- """Execute SQL statement and return cursor.
1347-
1348- This method is expected to be used as a wrapper around all
1349- `connection.execute` calls so that all the SQL statements are logged in
1350- case this information is needed to troubleshoot problems.
1351-
1352- :param sql: A sql statement to be executed
1353- :type sql: str
1354- :param parameters:
1355- Parameters to use to replace the placeholder
1356- values in the sql statement.
1357- :type parameters:
1358- list (question mark placeholders) |
1359- dict (colon named placeholders)
1360- :returns: Cursor used to execute statement
1361- :rtype: object
1362-
1363- """
1364- if parameters is None:
1365- parameters = []
1366-
1367- logging.debug('Executing SQL statement: {}, {}'
1368- .format(sql, parameters))
1369- cursor = self._connection.execute(sql, parameters)
1370- return cursor
1371-
1372- def delete(self):
1373- """Remove database."""
1374- os.unlink(self.db)
1375- super(SQLiteInventory, self).delete()
1376
1377=== removed directory 'utah/provisioning/vm'
1378=== renamed file 'utah/provisioning/vm/vm.py' => 'utah/provisioning/vm.py'
1379--- utah/provisioning/vm/vm.py 2013-04-26 17:33:15 +0000
1380+++ utah/provisioning/vm.py 2013-05-02 18:27:25 +0000
1381@@ -28,14 +28,21 @@
1382
1383 from utah import config
1384 from utah.process import ProcessChecker, ProcessRunner
1385-from utah.provisioning.inventory.sqlite import SQLiteInventory
1386+from utah.provisioning.exceptions import UTAHProvisioningException
1387+from utah.provisioning.inventory import SQLiteInventory
1388 from utah.provisioning.provisioning import CustomInstallMixin, Machine
1389 from utah.provisioning.rsyslog import RSyslog
1390 from utah.provisioning.ssh import SSHMixin
1391-from utah.provisioning.vm.exceptions import UTAHVMProvisioningException
1392 from utah.timeout import UTAHTimeout
1393
1394
1395+class UTAHVMProvisioningException(UTAHProvisioningException):
1396+
1397+ """Provide a foundation class for UTAH VM provisioning exceptions."""
1398+
1399+ pass
1400+
1401+
1402 class LibvirtVM(Machine):
1403
1404 """Provide a class to utilize VMs using libvirt.
1405
1406=== removed file 'utah/provisioning/vm/__init__.py'
1407--- utah/provisioning/vm/__init__.py 2013-04-04 13:42:40 +0000
1408+++ utah/provisioning/vm/__init__.py 1970-01-01 00:00:00 +0000
1409@@ -1,16 +0,0 @@
1410-# Ubuntu Testing Automation Harness
1411-# Copyright 2012 Canonical Ltd.
1412-
1413-# This program is free software: you can redistribute it and/or modify it
1414-# under the terms of the GNU General Public License version 3, as published
1415-# by the Free Software Foundation.
1416-
1417-# This program is distributed in the hope that it will be useful, but
1418-# WITHOUT ANY WARRANTY; without even the implied warranties of
1419-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1420-# PURPOSE. See the GNU General Public License for more details.
1421-
1422-# You should have received a copy of the GNU General Public License along
1423-# with this program. If not, see <http://www.gnu.org/licenses/>.
1424-
1425-"""utah.provisioning.vm"""
1426
1427=== removed file 'utah/provisioning/vm/exceptions.py'
1428--- utah/provisioning/vm/exceptions.py 2013-04-03 17:45:59 +0000
1429+++ utah/provisioning/vm/exceptions.py 1970-01-01 00:00:00 +0000
1430@@ -1,26 +0,0 @@
1431-# Ubuntu Testing Automation Harness
1432-# Copyright 2012 Canonical Ltd.
1433-
1434-# This program is free software: you can redistribute it and/or modify it
1435-# under the terms of the GNU General Public License version 3, as published
1436-# by the Free Software Foundation.
1437-
1438-# This program is distributed in the hope that it will be useful, but
1439-# WITHOUT ANY WARRANTY; without even the implied warranties of
1440-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1441-# PURPOSE. See the GNU General Public License for more details.
1442-
1443-# You should have received a copy of the GNU General Public License along
1444-# with this program. If not, see <http://www.gnu.org/licenses/>.
1445-
1446-"""Provide excpetions specific to virtual machines."""
1447-
1448-
1449-from utah.provisioning.exceptions import UTAHProvisioningException
1450-
1451-
1452-class UTAHVMProvisioningException(UTAHProvisioningException):
1453-
1454- """Provide a foundation class for UTAH VM provisioning exceptions."""
1455-
1456- pass

Subscribers

People subscribed via source and target branches