2014-03-23 16:04:03 +01:00
|
|
|
"""Main module containing all the setup necessary for running the bootstrapping process
|
|
|
|
.. module:: main
|
|
|
|
"""
|
|
|
|
|
2013-06-26 23:40:42 +02:00
|
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
2013-05-16 08:00:28 +02:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2014-03-23 16:04:03 +01:00
|
|
|
"""Main function for invoking the bootstrap process
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
Exception
|
|
|
|
"""
|
|
|
|
# Get the commandline arguments
|
2013-06-09 20:29:54 +02:00
|
|
|
args = get_args()
|
2014-02-23 22:22:29 +01:00
|
|
|
# Require root privileges, except when doing a dry-run where they aren't needed
|
2014-04-07 21:46:46 +02:00
|
|
|
import os
|
2014-02-23 22:22:29 +01:00
|
|
|
if os.geteuid() != 0 and not args.dry_run:
|
|
|
|
raise Exception('This program requires root privileges.')
|
2014-03-23 16:04:03 +01:00
|
|
|
# Setup logging
|
2014-02-23 22:22:29 +01:00
|
|
|
import log
|
2014-03-23 23:53:20 +01:00
|
|
|
log_dir = log.create_log_dir()
|
|
|
|
log_filename = log.get_log_filename(args.manifest)
|
|
|
|
logfile = os.path.join(log_dir, log_filename)
|
2013-06-23 22:30:41 +02:00
|
|
|
log.setup_logger(logfile=logfile, debug=args.debug)
|
2014-03-23 16:04:03 +01:00
|
|
|
# Everything has been set up, begin the bootstrapping process
|
2013-06-09 20:29:54 +02:00
|
|
|
run(args)
|
|
|
|
|
2013-06-26 20:14:37 +02:00
|
|
|
|
2013-06-09 20:29:54 +02:00
|
|
|
def get_args():
|
2014-03-23 16:04:03 +01:00
|
|
|
"""Creates an argument parser and returns the arguments it has parsed
|
|
|
|
"""
|
2013-05-16 08:00:28 +02:00
|
|
|
from argparse import ArgumentParser
|
|
|
|
parser = ArgumentParser(description='Bootstrap Debian for the cloud.')
|
|
|
|
parser.add_argument('--debug', action='store_true',
|
|
|
|
help='Print debugging information')
|
2013-09-14 23:29:12 +02:00
|
|
|
parser.add_argument('--pause-on-error', action='store_true',
|
|
|
|
help='Pause on error, before rollback')
|
2013-10-27 18:37:43 +01:00
|
|
|
parser.add_argument('--dry-run', action='store_true',
|
|
|
|
help='Dont\'t actually run the tasks')
|
2013-06-09 15:50:00 +02:00
|
|
|
parser.add_argument('manifest', help='Manifest file to use for bootstrapping', metavar='MANIFEST')
|
2013-06-09 20:29:54 +02:00
|
|
|
return parser.parse_args()
|
|
|
|
|
2013-05-16 08:00:28 +02:00
|
|
|
|
|
|
|
def run(args):
|
2014-03-23 16:04:03 +01:00
|
|
|
"""Runs the bootstrapping process
|
|
|
|
|
|
|
|
Args:
|
|
|
|
args (dict): Dictionary of arguments from the commandline
|
|
|
|
"""
|
|
|
|
# Load the manifest
|
2014-01-05 14:03:04 +01:00
|
|
|
from manifest import Manifest
|
|
|
|
manifest = Manifest(args.manifest)
|
2013-05-16 08:00:28 +02:00
|
|
|
|
2014-03-23 16:04:03 +01:00
|
|
|
# Get the tasklist
|
2013-06-09 16:23:08 +02:00
|
|
|
from tasklist import TaskList
|
|
|
|
tasklist = TaskList()
|
2014-03-23 16:04:03 +01:00
|
|
|
# 'resolve_tasks' is the name of the function to call on the provider and plugins
|
2014-01-05 15:13:09 +01:00
|
|
|
tasklist.load('resolve_tasks', manifest)
|
2013-05-16 08:00:28 +02:00
|
|
|
|
2014-03-23 16:04:03 +01:00
|
|
|
# Create the bootstrap information object that'll be used throughout the bootstrapping process
|
2013-06-09 16:15:23 +02:00
|
|
|
from bootstrapinfo import BootstrapInformation
|
2013-06-09 15:50:00 +02:00
|
|
|
bootstrap_info = BootstrapInformation(manifest=manifest, debug=args.debug)
|
2013-06-26 23:40:42 +02:00
|
|
|
|
|
|
|
try:
|
2014-03-23 16:04:03 +01:00
|
|
|
# Run all the tasks the tasklist has gathered
|
2013-10-27 18:37:43 +01:00
|
|
|
tasklist.run(info=bootstrap_info, dry_run=args.dry_run)
|
2014-03-23 16:04:03 +01:00
|
|
|
# We're done! :-)
|
2013-07-07 21:03:25 +02:00
|
|
|
log.info('Successfully completed bootstrapping')
|
2013-06-30 20:06:49 +02:00
|
|
|
except (Exception, KeyboardInterrupt) as e:
|
2014-03-23 16:04:03 +01:00
|
|
|
# When an error occurs, log it and begin rollback
|
2013-06-26 23:40:42 +02:00
|
|
|
log.exception(e)
|
2013-09-14 23:29:12 +02:00
|
|
|
if args.pause_on_error:
|
2014-03-23 16:04:03 +01:00
|
|
|
# The --pause-on-error is useful when the user wants to inspect the volume before rollback
|
2014-02-23 22:22:29 +01:00
|
|
|
raw_input('Press Enter to commence rollback')
|
2013-06-26 23:40:42 +02:00
|
|
|
log.error('Rolling back')
|
2014-01-05 15:13:09 +01:00
|
|
|
|
2014-03-23 16:04:03 +01:00
|
|
|
# Create a new tasklist to gather the necessary tasks for rollback
|
2013-06-26 23:40:42 +02:00
|
|
|
rollback_tasklist = TaskList()
|
2014-01-05 15:13:09 +01:00
|
|
|
|
2014-03-23 16:04:03 +01:00
|
|
|
# Create a useful little function for the provider and plugins to use,
|
|
|
|
# when figuring out what tasks should be added to the rollback list.
|
2014-01-05 15:13:09 +01:00
|
|
|
def counter_task(task, counter):
|
2014-03-23 16:04:03 +01:00
|
|
|
"""counter_task() adds the second argument to the rollback tasklist
|
|
|
|
if the first argument is present in the list of completed tasks
|
|
|
|
|
|
|
|
Args:
|
|
|
|
task (Task): The task to look for in the completed tasks list
|
|
|
|
counter (Task): The task to add to the rollback tasklist
|
|
|
|
"""
|
2014-01-05 15:13:09 +01:00
|
|
|
if task in tasklist.tasks_completed and counter not in tasklist.tasks_completed:
|
|
|
|
rollback_tasklist.tasks.add(counter)
|
2014-03-23 16:04:03 +01:00
|
|
|
# Ask the provider and plugins for tasks they'd like to add to the rollback tasklist
|
|
|
|
# Any additional arguments beyond the first two are passed directly to the provider and plugins
|
2014-01-05 15:13:09 +01:00
|
|
|
rollback_tasklist.load('resolve_rollback_tasks', manifest, counter_task)
|
|
|
|
|
2014-03-23 16:04:03 +01:00
|
|
|
# Run the rollback tasklist
|
2013-10-27 18:37:43 +01:00
|
|
|
rollback_tasklist.run(info=bootstrap_info, dry_run=args.dry_run)
|
2013-06-26 23:40:42 +02:00
|
|
|
log.info('Successfully completed rollback')
|
2014-04-07 21:47:05 +02:00
|
|
|
raise e
|