async def shutdown_watcher(): app.log.info('Watching for shutdown') try: await Shutdown.wait() except asyncio.CancelledError: pass app.log.info('Shutting down') if app.headless: utils.warning('Shutting down') else: app.ui.show_shutdown_message() try: if app.juju.authenticated: app.log.info('Disconnecting model') await app.juju.client.disconnect() app.log.info('Disconnected') if not app.headless: EventLoop.remove_alarms() for task in asyncio.Task.all_tasks(app.loop): # cancel all other tasks if getattr(task, '_coro', None) is not shutdown_watcher: task.cancel() app.loop.stop() except Exception: app.log.exception('Error in cleanup code') raise
def main(): with open(maas_data) as fp: maas_machines = json.load(fp) machine_view = maas_machines ui = MachineUI(machine_view) EventLoop.build_loop(ui, STYLES, unhandled_input=unhandled_input) EventLoop.run()
def main(): opts = parse_options(sys.argv[1:]) config = Config('bundle-placer', opts.__dict__) config.save() setup_logger(cfg_path=config.cfg_path) log = logging.getLogger('bundleplacer') log.debug(opts.__dict__) log.info("Editing file: {}".format(opts.bundle_filename)) if opts.maas_ip and opts.maas_cred: creds = dict(api_host=opts.maas_ip, api_key=opts.maas_cred) maas, maas_state = connect_to_maas(creds) else: maas_state = FakeMaasState() placement_controller = PlacementController(config=config, maas_state=maas_state) mainview = PlacerView(placement_controller, config) ui = PlacerUI(mainview) def unhandled_input(key): if key in ['q', 'Q']: raise urwid.ExitMainLoop() EventLoop.build_loop(ui, STYLES, unhandled_input=unhandled_input) mainview.loop = EventLoop.loop mainview.update() EventLoop.run()
def _handle_exception(self, tag, exc): if app.showing_error: return app.showing_error = True track_exception(exc.args[0]) app.ui.show_exception_message(exc) EventLoop.remove_alarms()
def finish(self, step_model, step_widget, done=False): """ handles processing step with input data Arguments: step_model: step_model returned from widget done: if True continues on to the summary view """ if done: EventLoop.remove_alarms() return controllers.use('summary').render(self.results) # Set next button focus here now that the step is complete. self.view.steps.popleft() if len(self.view.steps) > 0: next_step = self.view.steps[0] next_step.generate_additional_input() self.view.step_pile.focus_position = self.view.step_pile.focus_position + 1 # noqa else: app.log.debug("End of step list setting the view " "summary button in focus.") index = self.view.current_summary_button_index app.log.debug("Next focused button: {}".format(index)) self.view.step_pile.focus_position = index future = async .submit( partial(common.do_step, step_model, step_widget, app.ui.set_footer, gui=True), partial(self.__handle_exception, 'E002')) future.add_done_callback(self.get_result)
def finish(self, step_model, step_widget, done=False): """ handles processing step with input data Arguments: step_model: step_model returned from widget done: if True continues on to the summary view """ if done: EventLoop.remove_alarms() return controllers.use('summary').render(self.results) # Set next button focus here now that the step is complete. self.view.steps.popleft() if len(self.view.steps) > 0: next_step = self.view.steps[0] next_step.generate_additional_input() self.view.step_pile.focus_position = self.view.step_pile.focus_position + 1 # noqa else: app.log.debug( "End of step list setting the view " "summary button in focus.") index = self.view.current_summary_button_index app.log.debug("Next focused button: {}".format(index)) self.view.step_pile.focus_position = index future = async.submit(partial(common.do_step, step_model, step_widget, app.ui.set_footer, gui=True), partial(self.__handle_exception, 'E002')) future.add_done_callback(self.get_result)
async def shutdown_watcher(): app.log.info('Watching for shutdown') try: try: await Shutdown.wait() except asyncio.CancelledError: pass app.log.info('Shutting down') if app.headless: utils.warning('Shutting down') # Store application configuration state await app.save() if app.juju.authenticated: app.log.info('Disconnecting model') await app.juju.client.disconnect() app.log.info('Disconnected') if not app.headless: EventLoop.remove_alarms() for task in asyncio.Task.all_tasks(app.loop): # cancel all other tasks coro = getattr(task, '_coro', None) cr_code = getattr(coro, 'cr_code', None) if cr_code is not shutdown_watcher.__code__: app.log.debug('Cancelling pending task: {}'.format(task)) task.cancel() await asyncio.sleep(0.1) # give tasks a chance to see the cancel except Exception as e: app.log.exception('Error in cleanup code: {}'.format(e)) app.loop.stop()
def show_exception_message(self, ex): errmsg = str(ex) errmsg += ("\n\n" "Review log messages at ~/.cache/conjure-up/conjure-up.log " "If appropriate, please submit a bug here: " "https://github.com/conjure-up/conjure-up/issues/new") async .shutdown() EventLoop.remove_alarms() self.frame.body = ErrorView(errmsg) app.log.debug("Showing dialog for exception: {}".format(ex))
def show(self): def _stop(key): if key in ['q', 'Q']: raise ExitMainLoop() app.notrack = True app.noreport = True app.ui = ConjureUI() EventLoop.build_loop(app.ui, STYLES, unhandled_input=_stop) super().show() EventLoop.run()
def update(self, *args, **kwargs): if self.pv is None: self.pv = PlacementView( display_controller=self, placement_controller=self.placement_controller, config=self.config, do_deploy_cb=self.done_cb) self.set_header( title="Bundle Editor" ) self.set_body(self.pv) self.pv.update() EventLoop.set_alarm_in(1, self.update)
def show_exception_message(self, ex): _cache_dir = Path(app.argv.cache_dir) / 'conjure-up.log' errmsg = str(ex) errmsg += ("\n\n Review log messages at {} " "If appropriate, please submit a bug here: " "https://github.com/conjure-up/conjure-up/issues/new". format(_cache_dir)) async .shutdown() EventLoop.remove_alarms() self.frame.body = ErrorView(errmsg) # ensure error is shown, even if exception was inside urwid EventLoop.redraw_screen() app.log.debug("Showing dialog for exception: {}".format(ex))
def __handle_bootstrap_done(self, future): app.log.debug("handle bootstrap") result = future.result() if result.returncode < 0: # bootstrap killed via user signal, we're quitting return if result.returncode > 0: err = result.stderr.read().decode() app.log.error(err) return self.__handle_exception(Exception("error ")) utils.pollinate(app.session_id, 'J004') EventLoop.remove_alarms() app.ui.set_footer('Bootstrap complete...') self.__post_bootstrap_exec()
def __handle_bootstrap_done(self, future): app.log.debug("handle bootstrap") result = future.result() if result.returncode < 0: # bootstrap killed via user signal, we're quitting return if result.returncode > 0: err = result.stderr.read().decode() app.log.error(err) return self.__handle_exception(Exception("error ")) utils.pollinate(app.session_id, 'J004') EventLoop.remove_alarms() app.ui.set_footer('Bootstrap complete...') juju.switch_controller(app.current_controller) self.__post_bootstrap_exec()
def main(): opts = parse_options(sys.argv[1:]) if os.geteuid() == 0: utils.info("") utils.info("This should _not_ be run as root or with sudo.") utils.info("") sys.exit(1) if not os.path.isdir(opts.cache_dir): os.makedirs(opts.cache_dir) # Application Config app.config = {'metadata': None} app.argv = opts app.log = setup_logging(app, os.path.join(opts.cache_dir, 'conjure-down.log'), opts.debug) # Make sure juju paths are setup juju.set_bin_path() app.env = os.environ.copy() app.loop = asyncio.get_event_loop() app.loop.add_signal_handler(signal.SIGINT, events.Shutdown.set) app.loop.create_task(events.shutdown_watcher()) app.loop.create_task(_start()) try: if app.argv.controller and app.argv.model: app.headless = True app.ui = None app.env['CONJURE_UP_HEADLESS'] = "1" app.loop.run_forever() else: app.ui = ConjureUI() EventLoop.build_loop(app.ui, STYLES, unhandled_input=events.unhandled_input) EventLoop.run() finally: # explicitly close aysncio 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()
def do_commit(self, sender): """Commit changes to shadow assignments, constraints, and pins""" app.metadata_controller.bundle.machines = self._machines self.controller.clear_assignments(self.application) for juju_machine_id, al in self.shadow_assignments.items(): for application, atype in al: assert application == self.application self.controller.add_assignment(self.application, juju_machine_id, atype) for j_m_id, m in self.shadow_pins.items(): self.controller.set_machine_pin(j_m_id, m) self.controller.handle_sub_view_done() if self.alarm: EventLoop.remove_alarm(self.alarm)
def show_readme(self): _, rows = EventLoop.screen_size() cur_spell = self.selected_spell spellname = cur_spell['name'] spelldir = cur_spell['spell-dir'] brmv = BundleReadmeView(self.app.metadata_controller, spellname, spelldir, self.hide_readme, int(rows * .75)) self.app.ui.set_header("Spell Readme") self.app.ui.set_body(brmv)
def do_commit(self, sender): """Commit changes to shadow assignments, constraints, and pins""" app.metadata_controller.bundle.machines = self._machines self.controller.clear_assignments(self.application) for juju_machine_id, al in self.shadow_assignments.items(): for application, atype in al: assert application == self.application self.controller.add_assignment(self.application, juju_machine_id, atype) self.controller.clear_machine_pins() for j_m_id, m in self.shadow_pins.items(): self.controller.set_machine_pin(j_m_id, m) self.controller.handle_sub_view_done() if self.alarm: EventLoop.remove_alarm(self.alarm)
def finish(self, needs_lxd_setup=False, lxdnetwork=None, back=False): """ Processes the new LXD setup and loads the controller to finish bootstrapping the model. Arguments: back: if true loads previous controller needs_lxd_setup: if true prompt user to run lxd init """ if back: return controllers.use('clouds').render() if needs_lxd_setup: EventLoop.remove_alarms() EventLoop.exit(1) if lxdnetwork is None: return app.ui.show_exception_message( Exception("Unable to configure LXD network bridge.")) formatted_network = self.__format_input(lxdnetwork) app.log.debug("LXD Config {}".format(formatted_network)) out = self.__format_conf(formatted_network) with NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as tempf: app.log.debug("Saving LXD config to {}".format(tempf.name)) utils.spew(tempf.name, out) sh = utils.run('sudo mv {} /etc/default/lxd-bridge'.format( tempf.name), shell=True) if sh.returncode > 0: return app.ui.show_exception_message( Exception("Problem saving config: {}".format( sh.stderr.decode('utf8')))) app.log.debug("Restarting lxd-bridge") utils.run("sudo systemctl restart lxd-bridge.service", shell=True) utils.pollinate(app.session_id, 'L002') controllers.use('newcloud').render( cloud='localhost', bootstrap=True)
def finish(self, needs_lxd_setup=False, lxdnetwork=None, back=False): """ Processes the new LXD setup and loads the controller to finish bootstrapping the model. Arguments: back: if true loads previous controller needs_lxd_setup: if true prompt user to run lxd init """ if back: return controllers.use('clouds').render() if needs_lxd_setup: EventLoop.remove_alarms() EventLoop.exit(1) if lxdnetwork is None: return app.ui.show_exception_message( Exception("Unable to configure LXD network bridge.")) formatted_network = self.__format_input(lxdnetwork) app.log.debug("LXD Config {}".format(formatted_network)) out = self.__format_conf(formatted_network) with NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as tempf: app.log.debug("Saving LXD config to {}".format(tempf.name)) utils.spew(tempf.name, out) sh = run('sudo mv {} /etc/default/lxd-bridge'.format( tempf.name), shell=True) if sh.returncode > 0: return app.ui.show_exception_message( Exception("Problem saving config: {}".format( sh.stderr.decode('utf8')))) app.log.debug("Restarting lxd-bridge") run("sudo systemctl restart lxd-bridge.service", shell=True) utils.pollinate(app.session_id, 'L002') controllers.use('newcloud').render( cloud='localhost', bootstrap=True)
def __handle_bootstrap_done(self, future): app.log.debug("handle bootstrap") result = future.result() if result.returncode < 0: # bootstrap killed via user signal, we're quitting return if result.returncode > 0: pathbase = os.path.join(app.config['spell-dir'], '{}-bootstrap').format( app.current_controller) with open(pathbase + ".err") as errf: err = "\n".join(errf.readlines()) app.log.error(err) e = Exception("Bootstrap error: {}".format(err)) return self.__handle_exception(e) track_event("Juju Bootstrap", "Done", "") EventLoop.remove_alarms() app.ui.set_footer('Bootstrap complete...') self.__post_bootstrap_exec()
def finish(self, step_model, step_widget, done=False): """ handles processing step with input data Arguments: step_model: step_model returned from widget done: if True continues on to the summary view """ if done: EventLoop.remove_alarms() return controllers.use('summary').render(self.results) if utils.is_linux() and step_model.needs_sudo: password = None if step_widget.sudo_input: password = step_widget.sudo_input.value if not step_model.can_sudo(password): step_widget.set_error( 'Sudo failed. Please check your password and ensure that ' 'your sudo timeout is not set to zero.') step_widget.show_button() return step_widget.clear_error() # Set next button focus here now that the step is complete. self.view.steps.popleft() if len(self.view.steps) > 0: next_step = self.view.steps[0] next_step.generate_additional_input() self.view.step_pile.focus_position = self.view.step_pile.focus_position + 1 # noqa future = async.submit(partial(common.do_step, step_model, step_widget, app.ui.set_footer, gui=True), partial(self.__handle_exception, 'E002')) if future: future.add_done_callback(self.get_result)
def main(): opts = parse_options(sys.argv[1:]) if os.geteuid() == 0: utils.info("") utils.info("This should _not_ be run as root or with sudo.") utils.info("") sys.exit(1) if not os.path.isdir(opts.cache_dir): os.makedirs(opts.cache_dir) # Application Config app.config = {'metadata': None} app.argv = opts app.log = setup_logging("conjure-down", os.path.join(opts.cache_dir, 'conjure-down.log'), opts.debug) app.env = os.environ.copy() if app.argv.controller and app.argv.model: app.headless = True app.ui = None app.env['CONJURE_UP_HEADLESS'] = "1" _start() app.ui = ConjureUI() EventLoop.build_loop(app.ui, STYLES, unhandled_input=unhandled_input) EventLoop.set_alarm_in(0.05, _start) EventLoop.run()
def keypress(self, size, key): rv = super().keypress(size, key) if key in ['tab', 'shift tab']: self._swap_focus() self.handle_focus_changed() if key in ['r'] and self.selected_spell_w is not None: _, rows = EventLoop.screen_size() cur_spell = self.selected_spell_w.spell spellname = cur_spell['name'] spelldir = cur_spell['spell-dir'] brmv = BundleReadmeView(self.app.metadata_controller, spellname, spelldir, self.handle_readme_done, int(rows * .75)) self.app.ui.set_header("Spell Readme") self.app.ui.set_body(brmv) return rv
def keypress(self, size, key): rv = super().keypress(size, key) if key in ["tab", "shift tab"]: self._swap_focus() self.handle_focus_changed() if key in ["r"] and self.selected_spell_w is not None: _, rows = EventLoop.screen_size() cur_spell = self.selected_spell_w.spell spellname = cur_spell["name"] spelldir = cur_spell["spell-dir"] brmv = BundleReadmeView( self.app.metadata_controller, spellname, spelldir, self.handle_readme_done, int(rows * 0.75) ) self.app.ui.set_header("Spell Readme") self.app.ui.set_body(brmv) return rv
def finish(self): EventLoop.remove_alarms() EventLoop.exit(0)
def cancel(self, btn): EventLoop.exit(0)
def do_cancel(self, sender): self.controller.handle_sub_view_done() if self.alarm: EventLoop.remove_alarm(self.alarm)
def __refresh(self, *args): self.view.refresh_nodes() EventLoop.set_alarm_in(1, self.__refresh)
def __handle_destroy_done(self, future): if not future.exception(): app.ui.set_footer("") return controllers.use('destroy').render() EventLoop.remove_alarms()
def main(): with open(juju_data) as fp: juju_state = json.load(fp) ui = ServiceUI(juju_state) EventLoop.build_loop(ui, STYLES, unhandled_input=unhandled_input) EventLoop.run()
def finish(): EventLoop.remove_alarms()
def cancel(self, button): EventLoop.exit(0)
def __refresh(self, *args): self.view.redraw_kitt() self.alarm_handle = EventLoop.set_alarm_in( 1, self.__refresh)
def main(): if os.getenv("BUNDLE_EDITOR_TESTING"): test_args = True else: test_args = False opts = parse_options(sys.argv[1:], test_args) config = Config('bundle-placer', opts.__dict__) config.save() setup_logger(cfg_path=config.cfg_path) log = logging.getLogger('bundleplacer') log.debug(opts.__dict__) log.info("Editing file: {}".format(opts.bundle_filename)) if opts.maas_ip and opts.maas_cred: creds = dict(api_host=opts.maas_ip, api_key=opts.maas_cred) maas, maas_state = connect_to_maas(creds) elif 'fake_maas' in opts and opts.fake_maas: maas = None maas_state = FakeMaasState() else: maas = None maas_state = None try: placement_controller = PlacementController(config=config, maas_state=maas_state) except Exception as e: print("Error: " + e.args[0]) return def cb(): if maas: maas.tag_name(maas.nodes) bw = BundleWriter(placement_controller) if opts.out_filename: outfn = opts.out_filename else: outfn = opts.bundle_filename if os.path.exists(outfn): shutil.copy2(outfn, outfn + '~') bw.write_bundle(outfn) async.shutdown() raise urwid.ExitMainLoop() has_maas = (maas_state is not None) mainview = PlacerView(placement_controller, config, cb, has_maas=has_maas) ui = PlacerUI(mainview) def unhandled_input(key): if key in ['q', 'Q']: async.shutdown() raise urwid.ExitMainLoop() EventLoop.build_loop(ui, STYLES, unhandled_input=unhandled_input) mainview.loop = EventLoop.loop mainview.update() EventLoop.run()
def unhandled_input(self, key): if key in ['q', 'Q']: EventLoop.exit(0)
def main(): opts = parse_options(sys.argv[1:]) opt_defaults = parse_options([]) if os.geteuid() == 0: utils.info("") utils.info("This should _not_ be run as root or with sudo.") utils.info("") sys.exit(1) if not os.path.isdir(opts.cache_dir): os.makedirs(opts.cache_dir) # Application Config app.config = {'metadata': None} # 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) app.conjurefile = Conjurefile.load(opts.conf_file) app.conjurefile.merge_argv(opts, opt_defaults) app.log = setup_logging(app, os.path.join(opts.cache_dir, 'conjure-down.log'), opts.debug) app.no_track = app.conjurefile['no-track'] app.no_report = app.conjurefile['no-report'] app.env = os.environ.copy() # Make sure juju paths are setup juju.set_bin_path() app.loop = asyncio.get_event_loop() app.loop.add_signal_handler(signal.SIGINT, events.Shutdown.set) app.loop.create_task(events.shutdown_watcher()) app.loop.create_task(_start()) try: if app.conjurefile['controller'] and app.conjurefile['model']: app.headless = True app.ui = None app.env['CONJURE_UP_HEADLESS'] = "1" app.loop.run_forever() else: app.ui = ConjureUI() EventLoop.build_loop(app.ui, STYLES, unhandled_input=events.unhandled_input) EventLoop.run() finally: # explicitly close aysncio 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()
def finish(self, *args): if self.alarm_handle: EventLoop.remove_alarm(self.alarm_handle) return controllers.use('deploystatus').render()
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 __handle_exception(self, tag, exc): utils.pollinate(app.session_id, tag) EventLoop.remove_alarms() app.ui.show_exception_message(exc)
def update(self, *args, **kwargs): self.pv.update() EventLoop.set_alarm_in(1, self.update)
def unhandled_input(key): if key in ['q', 'Q']: async.shutdown() EventLoop.exit(0)
def finish(self, future): if not future.exception(): return controllers.use('steps').render() EventLoop.remove_alarms()
def update(self, *args): for w in self.all_step_widgets: w.update() EventLoop.set_alarm_in(1, self.update)
def update(self, *args): self.update_now() self.alarm = EventLoop.set_alarm_in(1, self.update)
def cancel(self, button): pollinate(app.session_id, 'UC') EventLoop.exit(0)
def enqueue_search(self): if self.search_delay_alarm: EventLoop.remove_alarm(self.search_delay_alarm) self.search_delay_alarm = EventLoop.set_alarm_in(0.5, self.really_search)
from conjureup import async from conjureup.app_config import app from ubuntui.ev import EventLoop import macumba import errno class ConjureUI(Frame): def show_exception_message(self, ex): if isinstance(ex, async.ThreadCancelledException): pass elif isinstance(ex, macumba.errors.ServerError): errmsg = ex.args[1] elif hasattr(ex, 'errno') and ex.errno == errno.ENOENT: # handle oserror errmsg = ex.args[1] else: errmsg = ex.args[0] errmsg += ("\n\n" "Review log messages at /var/log/conjure-up/combined.log " "If appropriate, please submit a bug here: " "https://bugs.launchpad.net/conjure-up/+filebug") self.frame.body = ErrorView(errmsg) app.log.exception("Showing dialog for exception:") EventLoop.remove_alarms() def show_error_message(self, msg): self.frame.body = ErrorView(msg)
def unhandled_input(key): if key in ['q', 'Q']: Shutdown.set() if key in ['R']: EventLoop.redraw_screen()
def main(): 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) if os.geteuid() == 0: utils.info("") utils.info("This should _not_ be run as root or with sudo.") utils.info("") sys.exit(1) # Application Config app.config = {'metadata': None} app.argv = opts app.log = setup_logging("conjure-up/{}".format(spell), os.path.join(opts.cache_dir, 'conjure-up.log'), opts.debug) # Setup proxy apply_proxy() app.session_id = os.getenv('CONJURE_TEST_SESSION_ID', '{}/{}'.format( spell, str(uuid.uuid4()))) global_config_filename = app.argv.global_config_file if not os.path.exists(global_config_filename): # fallback to source tree location global_config_filename = os.path.join(os.path.dirname(__file__), "../etc/conjure-up.conf") if not os.path.exists(global_config_filename): utils.error("Could not find {}.".format(global_config_filename)) sys.exit(1) with open(global_config_filename) as fp: global_conf = yaml.safe_load(fp.read()) app.global_config = global_conf spells_dir = app.argv.spells_dir if not os.path.exists(spells_dir): spells_dir = os.path.join(os.path.dirname(__file__), "../spells") app.config['spells-dir'] = spells_dir spells_index_path = os.path.join(app.config['spells-dir'], 'spells-index.yaml') 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: print("found spell {}".format(spells[0])) utils.set_chosen_spell(spell_name, os.path.join(opts.cache_dir, spell_name)) download_local(os.path.join(app.config['spells-dir'], spell_name), 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) 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() if app.argv.status_only: if not juju.model_available(): utils.error("Attempted to access the status screen without " "an available Juju model.\n" "Please select a model using 'juju switch' or " "create a new controller using 'juju bootstrap'.") sys.exit(1) app.env = os.environ.copy() app.env['CONJURE_UP_SPELL'] = spell_name if app.argv.cloud: if app.endpoint_type in [None, EndpointType.LOCAL_SEARCH]: utils.error("Please specify a spell for headless mode.") sys.exit(1) app.headless = True app.ui = None app.env['CONJURE_UP_HEADLESS'] = "1" _start() else: app.ui = ConjureUI() EventLoop.build_loop(app.ui, STYLES, unhandled_input=unhandled_input) EventLoop.set_alarm_in(0.05, _start) EventLoop.run()
def start(self): EventLoop.build_loop(self.common['ui'], STYLES, unhandled_input=self.unhandled_input) EventLoop.set_alarm_in(0.05, self._start) EventLoop.run()
def main(): 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) if os.geteuid() == 0: utils.info("") utils.info("This should _not_ be run as root or with sudo.") utils.info("") sys.exit(1) # Application Config app.config = {'metadata': None} app.argv = opts app.log = setup_logging("conjure-up/{}".format(spell), os.path.join(opts.cache_dir, 'conjure-up.log'), opts.debug) # Setup proxy apply_proxy() app.session_id = os.getenv('CONJURE_TEST_SESSION_ID', str(uuid.uuid4())) global_config_filename = app.argv.global_config_file if not os.path.exists(global_config_filename): # fallback to source tree location global_config_filename = os.path.join(os.path.dirname(__file__), "../etc/conjure-up.conf") if not os.path.exists(global_config_filename): utils.error("Could not find {}.".format(global_config_filename)) sys.exit(1) with open(global_config_filename) as fp: global_conf = yaml.safe_load(fp.read()) app.global_config = global_conf spells_dir = app.argv.spells_dir app.config['spells-dir'] = spells_dir spells_registry_branch = os.getenv('CONJUREUP_REGISTRY_BRANCH', 'master') if not os.path.exists(spells_dir): utils.info("No spells found, syncing from registry, please wait.") download_or_sync_registry( app.global_config['registry']['repo'], spells_dir, branch=spells_registry_branch) else: app.log.debug("Refreshing spell registry") download_or_sync_registry( app.global_config['registry']['repo'], spells_dir, update=True, branch=spells_registry_branch) spells_index_path = os.path.join(app.config['spells-dir'], 'spells-index.yaml') 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])) spell = spells[0] 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 = os.environ.copy() app.env['CONJURE_UP_CACHEDIR'] = app.argv.cache_dir app.env['CONJURE_UP_SPELL'] = spell_name 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() if app.argv.cloud: if app.endpoint_type in [None, EndpointType.LOCAL_SEARCH]: utils.error("Please specify a spell for headless mode.") sys.exit(1) app.headless = True app.ui = None app.env['CONJURE_UP_HEADLESS'] = "1" _start() else: app.ui = ConjureUI() EventLoop.build_loop(app.ui, STYLES, unhandled_input=unhandled_input) EventLoop.set_alarm_in(0.05, _start) EventLoop.run()
def _handle_exception(self, tag, exc): track_exception(exc.args[0]) app.ui.show_exception_message(exc) self.showing_error = True EventLoop.remove_alarms()