From 2017806d1f9fe7db2f332ec08b396919ed7dbce2 Mon Sep 17 00:00:00 2001 From: Anders Ingemann Date: Tue, 8 Apr 2014 21:22:34 +0200 Subject: [PATCH] Switch to docopt for options parsing Add option to not log to any file. --- bootstrapvz/base/log.py | 31 +++++++------------ bootstrapvz/base/main.py | 64 ++++++++++++++++++++++++---------------- setup.py | 1 + 3 files changed, 49 insertions(+), 47 deletions(-) diff --git a/bootstrapvz/base/log.py b/bootstrapvz/base/log.py index 15551c8..93a1fa9 100644 --- a/bootstrapvz/base/log.py +++ b/bootstrapvz/base/log.py @@ -5,19 +5,6 @@ both to a file and to the console. import logging -def create_log_dir(): - """Creates the log directory - - Returns: - str. The path to the logdirectory - """ - log_dir_path = '/var/log/bootstrap-vz' - import os - if not os.path.exists(log_dir_path): - os.makedirs(log_dir_path) - return log_dir_path - - def get_log_filename(manifest_path): """Returns the path to a logfile given a manifest The logfile name is constructed from the current timestamp and the basename of the manifest @@ -49,14 +36,16 @@ def setup_logger(logfile=None, debug=False): # Make sure all logging statements are processed by our handlers, they decide the log level root.setLevel(logging.NOTSET) - # Create a file log handler - file_handler = logging.FileHandler(logfile) - # Absolute timestamps are rather useless when bootstrapping, it's much more interesting - # to see how long things take, so we log in a relative format instead - file_handler.setFormatter(FileFormatter('[%(relativeCreated)s] %(levelname)s: %(message)s')) - # The file log handler always logs everything - file_handler.setLevel(logging.DEBUG) - root.addHandler(file_handler) + # Only enable logging to file if a destination was supplied + if logfile is not None: + # Create a file log handler + file_handler = logging.FileHandler(logfile) + # Absolute timestamps are rather useless when bootstrapping, it's much more interesting + # to see how long things take, so we log in a relative format instead + file_handler.setFormatter(FileFormatter('[%(relativeCreated)s] %(levelname)s: %(message)s')) + # The file log handler always logs everything + file_handler.setLevel(logging.DEBUG) + root.addHandler(file_handler) # Create a console log handler import sys diff --git a/bootstrapvz/base/main.py b/bootstrapvz/base/main.py index e01ebd2..7330fd4 100644 --- a/bootstrapvz/base/main.py +++ b/bootstrapvz/base/main.py @@ -13,45 +13,57 @@ def main(): Exception """ # Get the commandline arguments - args = get_args() + opts = get_opts() # Require root privileges, except when doing a dry-run where they aren't needed import os - if os.geteuid() != 0 and not args.dry_run: + if os.geteuid() != 0 and not opts['--dry-run']: raise Exception('This program requires root privileges.') - # Setup logging + import log - log_dir = log.create_log_dir() - log_filename = log.get_log_filename(args.manifest) - logfile = os.path.join(log_dir, log_filename) - log.setup_logger(logfile=logfile, debug=args.debug) + # Log to file unless --log is a single dash + if opts['--log'] != '-': + # Setup logging + if not os.path.exists(opts['--log']): + os.makedirs(opts['--log']) + log_filename = log.get_log_filename(opts['MANIFEST']) + logfile = os.path.join(opts['--log'], log_filename) + else: + logfile = None + log.setup_logger(logfile=logfile, debug=opts['--debug']) + # Everything has been set up, begin the bootstrapping process - run(args) + run(opts) -def get_args(): +def get_opts(): """Creates an argument parser and returns the arguments it has parsed """ - from argparse import ArgumentParser - parser = ArgumentParser(description='Bootstrap Debian for the cloud.') - parser.add_argument('--debug', action='store_true', - help='Print debugging information') - parser.add_argument('--pause-on-error', action='store_true', - help='Pause on error, before rollback') - parser.add_argument('--dry-run', action='store_true', - help='Dont\'t actually run the tasks') - parser.add_argument('manifest', help='Manifest file to use for bootstrapping', metavar='MANIFEST') - return parser.parse_args() + from docopt import docopt + usage = """bootstrap-vz + +Usage: bootstrap-vz [options] MANIFEST + +Options: + --log Log to given directory [default: /var/log/bootstrap-vz] + If is `-' file logging will be disabled. + --pause-on-error Pause on error, before rollback + --dry-run Don't actually run the tasks + --debug Print debugging information + -h, --help show this help + """ + opts = docopt(usage) + return opts -def run(args): +def run(opts): """Runs the bootstrapping process Args: - args (dict): Dictionary of arguments from the commandline + opts (dict): Dictionary of options from the commandline """ # Load the manifest from manifest import Manifest - manifest = Manifest(args.manifest) + manifest = Manifest(opts['MANIFEST']) # Get the tasklist from tasklist import TaskList @@ -61,17 +73,17 @@ def run(args): # Create the bootstrap information object that'll be used throughout the bootstrapping process from bootstrapinfo import BootstrapInformation - bootstrap_info = BootstrapInformation(manifest=manifest, debug=args.debug) + bootstrap_info = BootstrapInformation(manifest=manifest, debug=opts['--debug']) try: # Run all the tasks the tasklist has gathered - tasklist.run(info=bootstrap_info, dry_run=args.dry_run) + tasklist.run(info=bootstrap_info, dry_run=opts['--dry-run']) # We're done! :-) log.info('Successfully completed bootstrapping') except (Exception, KeyboardInterrupt) as e: # When an error occurs, log it and begin rollback log.exception(e) - if args.pause_on_error: + if opts['--pause-on-error']: # The --pause-on-error is useful when the user wants to inspect the volume before rollback raw_input('Press Enter to commence rollback') log.error('Rolling back') @@ -96,6 +108,6 @@ def run(args): rollback_tasklist.load('resolve_rollback_tasks', manifest, counter_task) # Run the rollback tasklist - rollback_tasklist.run(info=bootstrap_info, dry_run=args.dry_run) + rollback_tasklist.run(info=bootstrap_info, dry_run=opts['--dry-run']) log.info('Successfully completed rollback') raise e diff --git a/setup.py b/setup.py index 20d6568..e10b1b6 100644 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ setup(name='bootstrap-vz', 'fysom >= 1.0.15', 'jsonschema >= 2.3.0', 'pyyaml >= 3.10', + 'docopt >= 0.6.1', ], license='Apache License, Version 2.0', description='Bootstrap Debian images for virtualized environments',