예제 #1
0
def is_lxd_ready():
    """ routine for making sure lxd is configured for localhost deployments
    """
    if utils.lxd_version() < parse_version('2.9'):
        return {
            "ready":
            False,
            "msg":
            "The current version of LXD found on this system is "
            "not compatible. Please run the following to get the latest "
            "supported LXD:\n\n"
            "  sudo apt-add-repository ppa:ubuntu-lxc/lxd-stable\n"
            "  sudo apt-get update\n"
            "  sudo apt-get install lxd lxd-client\n\n"
            "Or if you're using the snap version:\n\n"
            "  sudo snap refresh lxd\n\n"
            "Once complete please re-run conjure-up."
        }

    if not utils.check_user_in_group('lxd'):
        return {
            "ready":
            False,
            "msg":
            "User {} is not part of the LXD group. You will need "
            "to exit conjure-up and do one of the following:\n\n"
            " 1: Run `newgrp lxd` and re-launch conjure-up\n\n"
            "  Or\n\n"
            " 2: Log out completely, Log in and "
            "re-launch conjure-up".format(os.environ['USER'])
        }

    try:
        setup_lxdbr0_network()
        setup_conjureup0_network()
    except Exception as e:
        return {
            "ready":
            False,
            "msg":
            "Unable to determine an existing LXD network bridge, "
            "please make sure you've run `sudo lxd init` to configure "
            "LXD.\n\n{}".format(e)
        }

    if utils.lxd_has_ipv6():
        return {
            "ready":
            False,
            "msg":
            "The LXD bridge has IPv6 enabled. Currently this is "
            "unsupported by conjure-up. Please disable IPv6 and "
            "re-launch conjure-up\n\n"
            "Visit https://docs.ubuntu.com/conjure-up/en/troubleshoot#lxd "
            "for information on how to disable IPv6."
        }

    app.log.debug("Found an IPv4 address, " "assuming LXD is configured.")
    return {"ready": True, "msg": ""}
예제 #2
0
def handle_exception(loop, context):
    if 'exception' not in context:
        return  # not an error, cleanup message
    if isinstance(context['exception'], ExitMainLoop):
        Shutdown.set()  # use previously stored exit code
        return
    if Error.is_set():
        return  # already reporting an error
    Error.set()
    exc = context['exception']

    if not (app.noreport or any(pred(exc) for pred in NOTRACK_EXCEPTIONS)):
        track_exception(str(exc))
        try:
            exc_info = (type(exc), exc, exc.__traceback__)
            app.sentry.captureException(exc_info,
                                        tags={
                                            'spell': app.config.get('spell'),
                                            'cloud_type':
                                            app.current_cloud_type,
                                            'region': app.current_region,
                                            'jaas': app.is_jaas,
                                            'headless': app.headless,
                                            'juju_version':
                                            utils.juju_version(),
                                            'lxd_version': utils.lxd_version(),
                                        })
        except Exception:
            app.log.exception('Error reporting error')

    app.log.exception('Unhandled exception', exc_info=exc)

    if app.headless:
        msg = str(exc)
        utils.error(msg)
        Shutdown.set(1)
    else:
        app.exit_code = 1  # store exit code for later
        app.ui.show_exception_message(exc)  # eventually raises ExitMainLoop
예제 #3
0
def main():
    if os.geteuid() == 0:
        print("")
        print("  !! This should _not_ be run as root or with sudo. !!")
        print("")
        sys.exit(1)

    # Verify we can access ~/.local/share/juju if it exists
    juju_dir = pathlib.Path('~/.local/share/juju').expanduser()
    if juju_dir.exists():
        try:
            for f in juju_dir.iterdir():
                if f.is_file():
                    f.read_text()
        except PermissionError:
            print("")
            print("  !! Unable to read from ~/.local/share/juju, please "
                  "double check your permissions on that directory "
                  "and its files. !!")
            print("")
            sys.exit(1)

    utils.set_terminal_title("conjure-up")
    opts = parse_options(sys.argv[1:])
    spell = os.path.basename(os.path.abspath(opts.spell))

    if not os.path.isdir(opts.cache_dir):
        os.makedirs(opts.cache_dir)

    # Application Config
    app.state = redis.StrictRedis(host='localhost', port=opts.redis_port, db=0)
    app.env = os.environ.copy()
    app.config = {'metadata': None}
    app.argv = opts
    app.log = setup_logging(app, os.path.join(opts.cache_dir,
                                              'conjure-up.log'), opts.debug)

    if app.argv.conf_file.expanduser().exists():
        conf = configparser.ConfigParser()
        conf.read_string(app.argv.conf_file.expanduser().read_text())
        app.notrack = conf.getboolean('REPORTING', 'notrack', fallback=False)
        app.noreport = conf.getboolean('REPORTING', 'noreport', fallback=False)
    if app.argv.notrack:
        app.notrack = True
    if app.argv.noreport:
        app.noreport = True

    # Grab current LXD and Juju versions
    app.log.debug("LXD version: {}, "
                  "Juju version: {}, "
                  "conjure-up version: {}".format(utils.lxd_version(),
                                                  utils.juju_version(),
                                                  VERSION))

    # Setup proxy
    apply_proxy()

    app.session_id = os.getenv('CONJURE_TEST_SESSION_ID', str(uuid.uuid4()))

    spells_dir = app.argv.spells_dir

    app.config['spells-dir'] = spells_dir
    spells_index_path = os.path.join(app.config['spells-dir'],
                                     'spells-index.yaml')
    spells_registry_branch = os.getenv('CONJUREUP_REGISTRY_BRANCH', 'stable')

    if not app.argv.nosync:
        if not os.path.exists(spells_dir):
            utils.info("No spells found, syncing from registry, please wait.")
        try:
            download_or_sync_registry(app.argv.registry,
                                      spells_dir,
                                      branch=spells_registry_branch)
        except subprocess.CalledProcessError as e:
            if not os.path.exists(spells_dir):
                utils.error("Could not load from registry")
                sys.exit(1)

            app.log.debug('Could not sync spells from github: {}'.format(e))
    else:
        if not os.path.exists(spells_index_path):
            utils.error(
                "You opted to not sync from the spells registry, however, "
                "we could not find any suitable spells in: "
                "{}".format(spells_dir))
            sys.exit(1)

    with open(spells_index_path) as fp:
        app.spells_index = yaml.safe_load(fp.read())

    spell_name = spell
    app.endpoint_type = detect_endpoint(opts.spell)

    if app.endpoint_type == EndpointType.LOCAL_SEARCH:
        spells = utils.find_spells_matching(opts.spell)

        if len(spells) == 0:
            utils.error("Can't find a spell matching '{}'".format(opts.spell))
            sys.exit(1)

        # One result means it was a direct match and we can copy it
        # now. Changing the endpoint type then stops us from showing
        # the picker UI. More than one result means we need to show
        # the picker UI and will defer the copy to
        # SpellPickerController.finish(), so nothing to do here.
        if len(spells) == 1:
            app.log.debug("found spell {}".format(spells[0][1]))
            spell = spells[0][1]
            utils.set_chosen_spell(spell_name,
                                   os.path.join(opts.cache_dir, spell['key']))
            download_local(
                os.path.join(app.config['spells-dir'], spell['key']),
                app.config['spell-dir'])
            utils.set_spell_metadata()
            app.endpoint_type = EndpointType.LOCAL_DIR

    # download spell if necessary
    elif app.endpoint_type == EndpointType.LOCAL_DIR:
        if not os.path.isdir(opts.spell):
            utils.warning("Could not find spell {}".format(opts.spell))
            sys.exit(1)

        if not os.path.exists(os.path.join(opts.spell, "metadata.yaml")):
            utils.warning("'{}' does not appear to be a spell. "
                          "{}/metadata.yaml was not found.".format(
                              opts.spell, opts.spell))
            sys.exit(1)

        spell_name = os.path.basename(os.path.abspath(spell))
        utils.set_chosen_spell(spell_name, path.join(opts.cache_dir,
                                                     spell_name))
        download_local(opts.spell, app.config['spell-dir'])
        utils.set_spell_metadata()

    elif app.endpoint_type in [EndpointType.VCS, EndpointType.HTTP]:

        utils.set_chosen_spell(spell, path.join(opts.cache_dir, spell))
        remote = get_remote_url(opts.spell)

        if remote is None:
            utils.warning("Can't guess URL matching '{}'".format(opts.spell))
            sys.exit(1)

        download(remote, app.config['spell-dir'], True)
        utils.set_spell_metadata()

    app.env['CONJURE_UP_CACHEDIR'] = app.argv.cache_dir

    if app.argv.show_env:
        if not app.argv.cloud:
            utils.error("You must specify a cloud for headless mode.")
            sys.exit(1)
        if app.endpoint_type in [None, EndpointType.LOCAL_SEARCH]:
            utils.error("Please specify a spell for headless mode.")
            sys.exit(1)

        show_env()

    app.sentry = raven.Client(
        dsn=SENTRY_DSN,
        release=VERSION,
        processors=('conjureup.utils.SanitizeDataProcessor', ))

    track_screen("Application Start")
    track_event("OS", platform.platform(), "")

    app.loop = asyncio.get_event_loop()
    app.loop.add_signal_handler(signal.SIGINT, events.Shutdown.set)
    try:
        if app.argv.cloud:
            if '/' in app.argv.cloud:
                parse_cli_cloud = app.argv.cloud.split('/')
                app.current_cloud, app.current_region = parse_cli_cloud
                app.log.debug("Region found {} for cloud {}".format(
                    app.current_cloud, app.current_region))
            else:
                app.current_cloud = app.argv.cloud

            if app.endpoint_type in [None, EndpointType.LOCAL_SEARCH]:
                utils.error("Please specify a spell for headless mode.")
                sys.exit(1)

            cloud_types = juju.get_cloud_types_by_name()
            if app.current_cloud not in cloud_types:
                utils.error('Unknown cloud: {}'.format(app.current_cloud))
                sys.exit(1)
            app.current_cloud_type = cloud_types[app.current_cloud]

            app.headless = True
            app.ui = None
            app.env['CONJURE_UP_HEADLESS'] = "1"
            app.loop.create_task(events.shutdown_watcher())
            app.loop.create_task(_start())
            app.loop.run_forever()

        else:
            app.ui = ConjureUI()

            EventLoop.build_loop(app.ui,
                                 STYLES,
                                 unhandled_input=events.unhandled_input)
            app.loop.create_task(events.shutdown_watcher())
            app.loop.create_task(_start())
            EventLoop.run()
    finally:
        # explicitly close asyncio event loop to avoid hitting the
        # following issue due to signal handlers added by
        # asyncio.create_subprocess_exec being cleaned up during final
        # garbage collection: https://github.com/python/asyncio/issues/396
        app.loop.close()
    sys.exit(app.exit_code)