From 0ae01e26a7eccf4dc5fbc479507c1e0c063fba25 Mon Sep 17 00:00:00 2001 From: Nikos Skalkotos Date: Fri, 16 Mar 2012 18:14:48 +0200 Subject: [PATCH] Create an exception based error reporting system All modules should use image_creator.FatalError exception to report fatal errors. --- image_creator/__init__.py | 2 ++ image_creator/disk.py | 15 ++++----- image_creator/main.py | 74 ++++++++++++++++++++++++++++----------------- 3 files changed, 57 insertions(+), 34 deletions(-) diff --git a/image_creator/__init__.py b/image_creator/__init__.py index 717e96f..920cc24 100644 --- a/image_creator/__init__.py +++ b/image_creator/__init__.py @@ -50,5 +50,7 @@ def get_os_class(distro, osfamily): return getattr(module, classname) +class FatalError(Exception): + pass # vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/disk.py b/image_creator/disk.py index 4ca3fd2..9476dc5 100644 --- a/image_creator/disk.py +++ b/image_creator/disk.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from image_creator.util import get_command +from image_creator import FatalError from clint.textui import progress import stat @@ -109,7 +110,7 @@ class Disk(object): def progress_generator(label=''): position = 0; - for i in progress.bar(range(100),''): + for i in progress.bar(range(100),label): if i < position: continue position = yield @@ -139,7 +140,7 @@ class DiskDevice(object): def enable(self): """Enable a newly created DiskDevice""" - self.progressbar = progress_generator() + self.progressbar = progress_generator("VM lauch: ") self.progressbar.next() eh = self.g.set_event_callback(self.progress_callback, guestfs.EVENT_PROGRESS) self.g.launch() @@ -151,9 +152,9 @@ class DiskDevice(object): roots = self.g.inspect_os() if len(roots) == 0: - raise DiskError("No operating system found") + raise FatalError("No operating system found") if len(roots) > 1: - raise DiskError("Multiple operating systems found") + raise FatalError("Multiple operating systems found") self.root = roots[0] self.ostype = self.g.inspect_get_type(self.root) @@ -174,7 +175,7 @@ class DiskDevice(object): total = array[3] assert self.progress_bar is not None - + print 'posisition/total: %s/%s' % (position, total) self.progress_bar.send((position * 100)//total) if position == total: @@ -214,13 +215,13 @@ class DiskDevice(object): dev = self.g.part_to_dev(self.root) parttype = self.g.part_get_parttype(dev) if parttype != 'msdos': - raise DiskError("You have a %s partition table. " + raise FatalError("You have a %s partition table. " "Only msdos partitions are supported" % parttype) last_partition = self.g.part_list(dev)[-1] if last_partition['part_num'] > 4: - raise DiskError("This disk contains logical partitions. " + raise FatalError("This disk contains logical partitions. " "Only primary partitions are supported.") part_dev = "%s%d" % (dev, last_partition['part_num']) diff --git a/image_creator/main.py b/image_creator/main.py index c08906f..6f0ecf0 100644 --- a/image_creator/main.py +++ b/image_creator/main.py @@ -33,6 +33,7 @@ from image_creator import get_os_class from image_creator import __version__ as version +from image_creator import FatalError from image_creator.disk import Disk from image_creator.util import get_command @@ -43,25 +44,22 @@ import optparse dd = get_command('dd') -class FatalError(Exception): - pass +def check_writable_dir(option, opt_str, value, parser): + dirname = os.path.dirname(value) + name = os.path.basename(value) + if dirname and not os.path.isdir(dirname): + parser.error("`%s' is not an existing directory" % dirname) + if not name: + parser.error("`%s' is not a valid file name" % dirname) -def check_writable_dir(option, opt_str, value, parser): - if not os.path.isdir(value): - raise OptionValueError("%s is not a valid directory name" % value) setattr(parser.values, option.dest, value) def parse_options(input_args): - usage = "Usage: %prog [options] " + usage = "Usage: %prog [options] " parser = optparse.OptionParser(version=version, usage=usage) - parser.add_option("-o", "--outdir", type="string", dest="outdir", - default=".", action="callback", callback=check_writable_dir, - help="Output files to DIR [default: working dir]", - metavar="DIR") - parser.add_option("-f", "--force", dest="force", default=False, action="store_true", help="Overwrite output files if they exist") @@ -77,6 +75,11 @@ def parse_options(input_args): help="Don't shrink any partition before extracting the image", action="store_false") + parser.add_option("-o", "--outfile", type="string", dest="outfile", + default=None, action="callback", callback=check_writable_dir, + help="Output image file", + metavar="FILE") + parser.add_option("-u", "--upload", dest="upload", default=False, help="Upload image to a pithos repository using kamaki", action="store_true") @@ -86,21 +89,22 @@ def parse_options(input_args): options, args = parser.parse_args(input_args) - if len(args) != 2: - parser.error('input media or name are missing') + if len(args) != 1: + parser.error('Wrong number of arguments') options.source = args[0] - options.name = args[1] - if not os.path.exists(options.source): - parser.error('Input media is not accessible') + parser.error('input media is not accessible') if options.register: options.upload = True + if options.outfile is None and not options.upload: + parser.error('either outfile (-o) or upload (-u) must be set.') + return options -def main(): +def image_creator(): options = parse_options(sys.argv[1:]) @@ -109,8 +113,8 @@ def main(): % os.path.basename(sys.argv[0])) if not options.force: - for extension in ('diskdump', 'meta'): - filename = "%s/%s.%s" % (options.outdir, options.name, extension) + for extension in ('', '.meta'): + filename = "%s%s" % (options.outfile, extension) if os.path.exists(filename): raise FatalError("Output file %s exists " "(use --force to overwrite it)." % filename) @@ -133,32 +137,48 @@ def main(): size = options.shrink and dev.shrink() or dev.size() metadata['size'] = str(size // 2 ** 20) + + outfile = "" + if options.outfile is not None: + outfile = options.outfile + f = open('%s.%s' % (options.outfile, 'meta'), 'w') + try: + for key in metadata.keys(): + f.write("%s=%s\n" % (key, metadata[key])) + finally: + f.close() + else: + outfd, outfile = tmpfile.mkstemp() + os.close(outfd) + dd('if=%s' % dev.device, - 'of=%s/%s.%s' % (options.outdir, options.name, 'diskdump'), + 'of=%s' % outfile, 'bs=4M', 'count=%d' % ((size + 1) // 2 ** 22)) - f = open('%s/%s.%s' % (options.outdir, options.name, 'meta'), 'w') - for key in metadata.keys(): - f.write("%s=%s\n" % (key, metadata[key])) - f.close() finally: disk.cleanup() #The image is ready, lets call kamaki if necessary if options.upload: - pass + pass + + if options.outfile is None: + os.unlink(outfile) return 0 COLOR_BLACK = "\033[00m" COLOR_RED = "\033[1;31m" -if __name__ == '__main__': +def main(): try: - ret = main() + ret = image_creator() sys.exit(ret) except FatalError as e: print >> sys.stderr, "\n%sError: %s%s\n" % (COLOR_RED, e, COLOR_BLACK) sys.exit(1) + +if __name__ == '__main__': + main() # vim: set sta sts=4 shiftwidth=4 sw=4 et ai : -- 1.7.10.4