def render(self): if len(self.step_metas) == 0: self.finish(None, None, done=True) return step_widgets = deque() for step_meta_path in self.step_metas: step_ex_path, ext = path.splitext(step_meta_path) if not path.isfile(step_ex_path) or \ not os.access(step_ex_path, os.X_OK): app.log.error( 'Unable to process step, missing {}'.format(step_ex_path)) continue step_metadata = {} with open(step_meta_path) as fp: step_metadata = yaml.load(fp.read()) try: # Store step model and its widget model = StepModel(step_metadata, step_meta_path) step_widget = StepWidget( app, model, self.finish) if not step_widget.model.viewable: app.log.debug("Skipping step: {}".format(step_widget)) continue model.path = step_ex_path step_widgets.append(step_widget) app.log.debug("Queueing step: {}".format(step_widget)) except Exception as e: self.__handle_exception('E002', e) return try: self.all_step_widgets = list(step_widgets) self.view = StepsView(app, step_widgets, self.finish) # Set initial step as active and viewable step_widgets[0].description.set_text(( 'body', step_widgets[0].model.description)) step_widgets[0].icon.set_text(( 'pending_icon', step_widgets[0].icon.get_text()[0] )) step_widgets[0].generate_additional_input() self.view.step_pile.focus_position = 2 except Exception as e: self.__handle_exception('E002', e) return app.ui.set_header( title="Additional Application Configuration", excerpt="Please finish the installation by configuring your " "application with these steps.") app.ui.set_body(self.view) app.ui.set_footer('') self.update()
def render(self): if len(self.step_metas) == 0: self.finish(None, None, done=True) return step_widgets = deque() for step_meta_path in self.step_metas: step_ex_path, ext = path.splitext(step_meta_path) if not path.isfile(step_ex_path) or \ not os.access(step_ex_path, os.X_OK): app.log.error( 'Unable to process step, missing {}'.format(step_ex_path)) continue step_metadata = {} with open(step_meta_path) as fp: step_metadata = yaml.load(fp.read()) try: # Store step model and its widget model = StepModel(step_metadata, step_meta_path) step_widget = StepWidget(app, model, self.finish) if not step_widget.model.viewable: app.log.debug("Skipping step: {}".format(step_widget)) continue model.path = step_ex_path step_widgets.append(step_widget) app.log.debug("Queueing step: {}".format(step_widget)) except Exception as e: self.__handle_exception('E002', e) return try: self.all_step_widgets = list(step_widgets) self.view = StepsView(app, step_widgets, self.finish) # Set initial step as active and viewable step_widgets[0].description.set_text( ('body', step_widgets[0].model.description)) step_widgets[0].icon.set_text( ('pending_icon', step_widgets[0].icon.get_text()[0])) step_widgets[0].generate_additional_input() self.view.step_pile.focus_position = 2 except Exception as e: self.__handle_exception('E002', e) return app.ui.set_header( title="Additional Application Configuration", excerpt="Please finish the installation by configuring your " "application with these steps.") app.ui.set_body(self.view) app.ui.set_footer('') self.update()
def finish(self, spellname): utils.set_terminal_title("conjure-up {}".format(spellname)) utils.set_chosen_spell(spellname, os.path.join(app.argv.cache_dir, spellname)) download_local(os.path.join(app.config['spells-dir'], spellname), app.config['spell-dir']) utils.set_spell_metadata() StepModel.load_spell_steps() AddonModel.load_spell_addons() utils.setup_metadata_controller() return controllers.use('addons').render()
async def pre_bootstrap(self): """ runs pre bootstrap script if exists """ step = StepModel({}, filename='00_pre-bootstrap', name='pre-bootstrap') await step.run(self.msg_cb)
async def wait_for_applications(msg_cb): await events.DeploymentComplete.wait() msg = 'Waiting for deployment to settle.' app.log.info(msg) msg_cb(msg) # retry done check a few times to work around # https://bugs.launchpad.net/juju-wait/+bug/1680963 for i in range(3): try: step = StepModel({}, filename='00_deploy-done', name='Deployment Watcher') await utils.run_step(step, msg_cb) break except Exception as e: if i < 2 and 'Applications did not start successfully' in str(e): await asyncio.sleep(5) app.log.debug('Retrying 00_deploy-done: {}'.format(i)) continue raise events.ModelSettled.set() msg = 'Model settled.' app.log.info(msg) msg_cb(msg)
async def pre_deploy(msg_cb): """ runs pre deploy script if exists """ await events.ModelConnected.wait() step = StepModel({}, filename='00_pre-deploy', name='pre-deploy') await step.run(msg_cb) events.PreDeployComplete.set()
async def do_bootstrap(self): await self.pre_bootstrap() self.emit('Bootstrapping Juju controller.') track_event("Juju Bootstrap", "Started", "") cloud_with_region = app.provider.cloud if app.provider.region: cloud_with_region = '/'.join([app.provider.cloud, app.provider.region]) success = await juju.bootstrap(app.provider.controller, cloud_with_region, app.provider.model, credential=app.provider.credential) if not success: log_file = '{}-bootstrap.err'.format(app.provider.controller) log_file = Path(app.config['spell-dir']) / log_file err_log = log_file.read_text('utf8').splitlines() app.log.error("Error bootstrapping controller: " "{}".format(err_log)) app.sentry.context.merge({'extra': {'err_log': err_log[-400:]}}) raise Exception('Unable to bootstrap (cloud type: {})'.format( app.provider.cloud_type)) self.emit('Bootstrap complete.') track_event("Juju Bootstrap", "Done", "") await juju.login() # login to the newly created (default) model step = StepModel({}, filename='00_post-bootstrap', name='post-bootstrap') await step.run(self.msg_cb, 'Juju Post-Bootstrap') events.Bootstrapped.set()
def __init__(self, name): self.name = name self.path = Path(app.config['spell-dir']) / 'addons' / name self.metadata = self._read('metadata.yaml') self.bundle = self._read('bundle.yaml') self.steps = [ StepModel.load(step_path) for step_path in sorted((self.path / 'steps').glob('*.yaml')) ]
def build_widget(self): app.steps_data['name'] = { 'USERNAME': '******', 'PASSWORD': '', 'EMAIL': '', } super().build_widget() self.add_step( StepForm( app, StepModel( { 'description': 'Download Deis CLI', 'viewable': True, }, '', ''))) self.add_step( StepForm( app, StepModel( { 'description': 'Create Admin User', 'viewable': True, 'additional-input': [ { 'label': 'Username', 'key': 'USERNAME', 'type': 'text' }, { 'label': 'Password', 'key': 'PASSWORD', 'type': 'password' }, { 'label': 'Email', 'key': 'EMAIL', 'type': 'text' }, ], }, 'filename', 'name'))) return self.step_pile
def load_step(step_meta_path): step_meta_path = Path(step_meta_path) step_name = step_meta_path.stem step_ex_path = step_meta_path.parent / step_name if not step_ex_path.is_file(): raise ValidationError( 'Step {} has no implementation'.format(step_name)) elif not os.access(str(step_ex_path), os.X_OK): raise ValidationError('Step {} is not executable'.format(step_name)) step_metadata = yaml.load(step_meta_path.read_text()) model = StepModel(step_metadata, str(step_ex_path), step_name) return model
def render(self): for step_meta_path in self.step_metas: step_ex_path, ext = path.splitext(step_meta_path) if not path.isfile(step_ex_path) or \ not os.access(step_ex_path, os.X_OK): app.log.error( 'Unable to process step, missing {}'.format(step_ex_path)) continue step_metadata = {} with open(step_meta_path) as fp: step_metadata = yaml.load(fp.read()) model = StepModel(step_metadata, step_meta_path) model.path = step_ex_path app.log.debug("Running step: {}".format(model)) try: step_model, _ = common.do_step(model, None, utils.info) self.results[step_model.title] = step_model.result except Exception as e: utils.error("Failed to run {}: {}".format(model.path, e)) sys.exit(1) self.finish()
def __init__(self, name): self.name = name self.path = Path(app.config['spell-dir']) / 'addons' / name self.metadata = self._read('metadata.yaml') self.bundle = self._read('bundle.yaml') self.steps = [ StepModel.load(step_path, source=self.friendly_name, addon_name=name) for step_path in sorted((self.path / 'steps').glob('*')) if step_path.is_dir() ]
def load_step(step_meta_path): step_ex_path, ext = path.splitext(step_meta_path) short_path = '/'.join(step_ex_path.split('/')[-3:]) if not path.isfile(step_ex_path): raise ValidationError( 'Step {} has no implementation'.format(short_path)) elif not os.access(step_ex_path, os.X_OK): raise ValidationError('Step {} is not executable, make sure it has ' 'the executable bit set'.format(short_path)) with open(step_meta_path) as fp: step_metadata = yaml.load(fp.read()) model = StepModel(step_metadata, step_ex_path) return model
async def pre_bootstrap(self): """ runs pre bootstrap script if exists """ # Set provider type for post-bootstrap app.env['JUJU_PROVIDERTYPE'] = juju.get_cloud_types_by_name()[ app.current_cloud] app.env['JUJU_CONTROLLER'] = app.current_controller app.env['JUJU_MODEL'] = app.current_model app.env['CONJURE_UP_SPELLSDIR'] = app.argv.spells_dir step = StepModel({}, filename='00_pre-bootstrap', name='pre-bootstrap') await utils.run_step(step, self.msg_cb)
async def wait_for_applications(msg_cb): await events.DeploymentComplete.wait() msg = 'Waiting for deployment to settle.' app.log.info(msg) msg_cb(msg) step = StepModel({'title': 'Deployment Watcher'}, filename='00_deploy-done', name='00_deploy-done') await step.run(msg_cb) events.ModelSettled.set() msg = 'Model settled.' app.log.info(msg) msg_cb(msg)
async def pre_deploy(msg_cb): """ runs pre deploy script if exists """ await events.ModelConnected.wait() # Set provider type for post-bootstrap app.env['JUJU_PROVIDERTYPE'] = app.juju.client.info.provider_type # Set current credential name (localhost doesn't have one) app.env['JUJU_CREDENTIAL'] = app.current_credential or '' app.env['JUJU_CONTROLLER'] = app.current_controller app.env['JUJU_MODEL'] = app.current_model app.env['CONJURE_UP_SPELLSDIR'] = app.argv.spells_dir step = StepModel({}, filename='00_pre-deploy', name='pre-deploy') await utils.run_step(step, msg_cb) events.PreDeployComplete.set()
async def do_bootstrap(self, creds): if app.is_jaas: return await self.pre_bootstrap() self.emit('Bootstrapping Juju controller.') track_event("Juju Bootstrap", "Started", "") cloud_with_region = app.current_cloud if app.current_region: cloud_with_region = '/'.join( [app.current_cloud, app.current_region]) success = await juju.bootstrap(app.current_controller, cloud_with_region, app.current_model, credential=creds) if not success: log_file = '{}-bootstrap.err'.format(app.current_controller) log_file = Path(app.config['spell-dir']) / log_file err_log = log_file.read_text('utf8').splitlines() app.log.error("Error bootstrapping controller: " "{}".format(err_log)) app.sentry.context.merge({'extra': {'err_log': err_log}}) raise Exception('Unable to bootstrap (cloud type: {})'.format( app.current_cloud_type)) self.emit('Bootstrap complete.') track_event("Juju Bootstrap", "Done", "") await juju.login() # login to the newly created (default) model # Set provider type for post-bootstrap app.env['JUJU_PROVIDERTYPE'] = app.juju.client.info.provider_type app.env['JUJU_CONTROLLER'] = app.current_controller app.env['JUJU_MODEL'] = app.current_model step = StepModel({}, filename='00_post-bootstrap', name='post-bootstrap') await utils.run_step(step, self.msg_cb, 'Juju Post-Bootstrap') events.Bootstrapped.set()
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 os.environ['UNIT_STATE_DB'] = os.path.join(opts.cache_dir, '.state.db') app.state = unitdata.kv() 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("Juju version: {}, " "conjure-up version: {}".format(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() StepModel.load_spell_steps() AddonModel.load_spell_addons() 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() StepModel.load_spell_steps() AddonModel.load_spell_addons() 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() StepModel.load_spell_steps() AddonModel.load_spell_addons() app.env['CONJURE_UP_CACHEDIR'] = app.argv.cache_dir if app.argv.show_env: 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, transport=RequestsHTTPTransport, 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: cloud = None region = None if '/' in app.argv.cloud: parse_cli_cloud = app.argv.cloud.split('/') cloud, region = parse_cli_cloud app.log.debug("Region found {} for cloud {}".format( cloud, region)) else: cloud = app.argv.cloud cloud_types = juju.get_cloud_types_by_name() if cloud not in cloud_types: utils.error('Unknown cloud: {}'.format(cloud)) sys.exit(1) if app.endpoint_type in [None, EndpointType.LOCAL_SEARCH]: utils.error("Please specify a spell for headless mode.") sys.exit(1) app.provider = load_schema(cloud_types[cloud]) try: app.provider.load(cloud) except SchemaErrorUnknownCloud as e: utils.error(e) sys.exit(1) if region: app.provider.region = region 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)
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:]) opt_defaults = parse_options([]) # Load conjurefile, merge any overridding options from argv if not opts.conf_file: opts.conf_file = [] if pathlib.Path('~/.config/conjure-up.conf').expanduser().exists(): opts.conf_file.insert( 0, pathlib.Path('~/.config/conjure-up.conf').expanduser()) if (pathlib.Path('.') / 'Conjurefile').exists(): opts.conf_file.insert(0, pathlib.Path('.') / 'Conjurefile') for conf in opts.conf_file: if not conf.exists(): print("Unable to locate config {} for processing.".format( str(conf))) sys.exit(1) try: app.conjurefile = Conjurefile.load(opts.conf_file) except ValueError as e: print(str(e)) sys.exit(1) app.conjurefile.merge_argv(opts, opt_defaults) if app.conjurefile['gen-config']: Conjurefile.print_tpl() sys.exit(0) spell = os.path.basename(os.path.abspath(app.conjurefile['spell'])) if not os.path.isdir(app.conjurefile['cache-dir']): os.makedirs(app.conjurefile['cache-dir']) # Application Config kv_db = os.path.join(app.conjurefile['cache-dir'], '.state.db') app.state = KV(kv_db) app.env = os.environ.copy() app.env['KV_DB'] = kv_db app.config = {'metadata': None} app.log = setup_logging(app, os.path.join(app.conjurefile['cache-dir'], 'conjure-up.log'), app.conjurefile.get('debug', False)) # Make sure juju paths are setup juju.set_bin_path() juju.set_wait_path() app.no_track = app.conjurefile['no-track'] app.no_report = app.conjurefile['no-report'] # Grab current LXD and Juju versions app.log.debug("Juju version: {}, " "conjure-up version: {}".format( utils.juju_version(), VERSION)) # Setup proxy apply_proxy() app.session_id = os.getenv('CONJURE_TEST_SESSION_ID', str(uuid.uuid4())) spells_dir = app.conjurefile['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', 'master') if not app.conjurefile['no-sync']: if not os.path.exists(spells_dir): utils.info("No spells found, syncing from registry, please wait.") try: download_or_sync_registry( app.conjurefile['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()) addons_aliases_index_path = os.path.join(app.config['spells-dir'], 'addons-aliases.yaml') if os.path.exists(addons_aliases_index_path): with open(addons_aliases_index_path) as fp: app.addons_aliases = yaml.safe_load(fp.read()) spell_name = spell app.endpoint_type = detect_endpoint(app.conjurefile['spell']) if app.conjurefile['spell'] != consts.UNSPECIFIED_SPELL: app.spell_given = True # Check if spell is actually an addon addon = utils.find_addons_matching(app.conjurefile['spell']) if addon: app.log.debug("addon found, setting required spell") utils.set_chosen_spell(addon['spell'], os.path.join(app.conjurefile['cache-dir'], addon['spell'])) download_local(os.path.join(app.config['spells-dir'], addon['spell']), app.config['spell-dir']) utils.set_spell_metadata() StepModel.load_spell_steps() AddonModel.load_spell_addons() app.selected_addons = addon['addons'] app.alias_given = True controllers.setup_metadata_controller() app.endpoint_type = EndpointType.LOCAL_DIR elif app.endpoint_type == EndpointType.LOCAL_SEARCH: spells = utils.find_spells_matching(app.conjurefile['spell']) if len(spells) == 0: utils.error("Can't find a spell matching '{}'".format( app.conjurefile['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(app.conjurefile['cache-dir'], spell['key'])) download_local(os.path.join(app.config['spells-dir'], spell['key']), app.config['spell-dir']) utils.set_spell_metadata() StepModel.load_spell_steps() AddonModel.load_spell_addons() app.endpoint_type = EndpointType.LOCAL_DIR # download spell if necessary elif app.endpoint_type == EndpointType.LOCAL_DIR: if not os.path.isdir(app.conjurefile['spell']): utils.warning("Could not find spell {}".format( app.conjurefile['spell'])) sys.exit(1) if not os.path.exists(os.path.join(app.conjurefile['spell'], "metadata.yaml")): utils.warning("'{}' does not appear to be a spell. " "{}/metadata.yaml was not found.".format( app.conjurefile['spell'], app.conjurefile['spell'])) sys.exit(1) spell_name = os.path.basename(os.path.abspath(spell)) utils.set_chosen_spell(spell_name, path.join(app.conjurefile['cache-dir'], spell_name)) download_local(app.conjurefile['spell'], app.config['spell-dir']) utils.set_spell_metadata() StepModel.load_spell_steps() AddonModel.load_spell_addons() elif app.endpoint_type in [EndpointType.VCS, EndpointType.HTTP]: utils.set_chosen_spell(spell, path.join( app.conjurefile['cache-dir'], spell)) remote = get_remote_url(app.conjurefile['spell']) if remote is None: utils.warning("Can't guess URL matching '{}'".format( app.conjurefile['spell'])) sys.exit(1) download(remote, app.config['spell-dir'], True) utils.set_spell_metadata() StepModel.load_spell_steps() AddonModel.load_spell_addons() app.env['CONJURE_UP_CACHEDIR'] = app.conjurefile['cache-dir'] app.env['PATH'] = "/snap/bin:{}".format(app.env['PATH']) if app.conjurefile['show-env']: 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, transport=RequestsHTTPTransport, 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) # Enable charmstore querying app.juju.charmstore = CharmStore(app.loop) try: if app.conjurefile.is_valid: cloud = None region = None if '/' in app.conjurefile['cloud']: parse_cli_cloud = app.conjurefile['cloud'].split('/') cloud, region = parse_cli_cloud app.log.debug( "Region found {} for cloud {}".format(cloud, region)) else: cloud = app.conjurefile['cloud'] cloud_types = juju.get_cloud_types_by_name() if cloud not in cloud_types: utils.error('Unknown cloud: {}'.format(cloud)) sys.exit(1) if app.endpoint_type in [None, EndpointType.LOCAL_SEARCH]: utils.error("Please specify a spell for headless mode.") sys.exit(1) app.provider = load_schema(cloud_types[cloud]) try: app.provider.load(cloud) except errors.SchemaCloudError as e: utils.error(e) sys.exit(1) if region: app.provider.region = region 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() app.ui.set_footer('Press ? for help') EventLoop.build_loop(app.ui, STYLES, unhandled_input=events.unhandled_input, handle_mouse=False) 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)