#!/usr/bin/env python3 import logging import sys import importlib import argparse import multiprocessing as mp from uncloud import UncloudException from contextlib import suppress # the components that use etcd ETCD_COMPONENTS= ['api', 'scheduler', 'host', 'filescanner', 'imagescanner', 'metadata', 'configure' ] ALL_COMPONENTS = ETCD_COMPONENTS.copy() ALL_COMPONENTS.append('cli') def exception_hook(exc_type, exc_value, exc_traceback): logging.getLogger(__name__).error( 'Uncaught exception', exc_info=(exc_type, exc_value, exc_traceback) ) sys.excepthook = exception_hook if __name__ == '__main__': # Setting up root logger logger = logging.getLogger() logger.setLevel(logging.DEBUG) arg_parser = argparse.ArgumentParser() subparsers = arg_parser.add_subparsers(dest='command') parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('--debug', '-d', action='store_true', default=False, help='More verbose logging') parent_parser.add_argument('--conf-dir', '-c', help='Configuration directory') etcd_parser = argparse.ArgumentParser(add_help=False) etcd_parser.add_argument('--etcd-host') etcd_parser.add_argument('--etcd-port') etcd_parser.add_argument('--etcd-ca-cert', help="CA that signed the etcd certificate") etcd_parser.add_argument('--etcd-cert-cert', help="Path to client certificate") etcd_parser.add_argument('--etcd-cert-key', help="Path to client certificate key") for component in ALL_COMPONENTS: mod = importlib.import_module('uncloud.{}.main'.format(component)) parser = getattr(mod, 'arg_parser') if component in ETCD_COMPONENTS: subparsers.add_parser(name=parser.prog, parents=[parser, parent_parser, etcd_parser]) else: subparsers.add_parser(name=parser.prog, parents=[parser, parent_parser]) args = arg_parser.parse_args() if not args.command: arg_parser.print_help() else: # if we start etcd in seperate process with default settings # i.e inheriting few things from parent process etcd3 module # errors out, so the following command configure multiprocessing # module to not inherit anything from parent. # mp.set_start_method('spawn') arguments = vars(args) name = arguments.pop('command') mod = importlib.import_module('uncloud.{}.main'.format(name)) main = getattr(mod, 'main') # If the component requires etcd3, we import it and catch the # etcd3.exceptions.ConnectionFailedError if name in ETCD_COMPONENTS: import etcd3 try: main(arguments) except UncloudException as err: logger.error(err) sys.exit(1) except etcd3.exceptions.ConnectionFailedError as err: logger.error("Cannot connect to etcd") except Exception as err: logger.exception(err) sys.exit(1)