Switch to docopt for options parsing

Add option to not log to any file.
This commit is contained in:
Anders Ingemann 2014-04-08 21:22:34 +02:00
parent c154347849
commit 2017806d1f
3 changed files with 49 additions and 47 deletions

View file

@ -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

View file

@ -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 <path> Log to given directory [default: /var/log/bootstrap-vz]
If <path> 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

View file

@ -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',