def stop(namespace=None): ''' Stops the Hypergolix daemon. ''' with Config.find() as config: pid_file = str(config.process.pid_file) daemoniker.send(pid_file, SIGTERM)
def stop(namespace=None): ''' Stops the Hypergolix daemon. ''' if namespace.pidfile is not None: raise RuntimeError('Server pidfile specification through CLI is no ' + 'longer supported. Edit hypergolix.yml ' + 'configuration file instead.') config = Config.find() daemoniker.send(str(config.server.pid_file), SIGTERM)
def test_find_cfg_from_env(self): with tempfile.TemporaryDirectory() as root: os.environ['HYPERGOLIX_HOME'] = root try: fake_config = pathlib.Path(root) / 'hypergolix.yml' # Create a fake file to pick up its existence fake_config.touch() config = Config.find() self.assertEqual(config.path, fake_config) finally: del os.environ['HYPERGOLIX_HOME']
def test_find_cfg_from_appdata(self): with tempfile.TemporaryDirectory() as root: try: oldappdata = os.environ['LOCALAPPDATA'] except KeyError: oldappdata = None os.environ['LOCALAPPDATA'] = root try: fake_config = pathlib.Path(root) / 'hypergolix.yml' # Create a fake file to pick up its existence fake_config.touch() config = Config.find() self.assertEqual(config.path, fake_config) finally: if oldappdata is None: del os.environ['LOCALAPPDATA'] else: os.environ['LOCALAPPDATA'] = oldappdata
def start(namespace=None): ''' Starts a Hypergolix daemon. ''' # Command arg support is deprecated. if namespace is not None: # Gigantic error trap if ((namespace.host is not None) | (namespace.port is not None) | (namespace.debug is not None) | (namespace.traceur is not None) | (namespace.pidfile is not None) | (namespace.logdir is not None) | (namespace.cachedir is not None) | (namespace.chdir is not None) | (namespace.verbosity is not None)): raise RuntimeError('Server configuration through CLI is no ' + 'longer supported. Edit hypergolix.yml ' + 'configuration file instead.') with Daemonizer() as (is_setup, daemonizer): # Get our config path in setup, so that we error out before attempting # to daemonize (if anything is wrong). if is_setup: config = Config.find() config_path = config.path chdir = config_path.parent pid_file = config.server.pid_file else: config_path = None pid_file = None chdir = None # Daemonize. is_parent, config_path = daemonizer( str(pid_file), config_path, chdir = str(chdir), explicit_rescript = '-m hypergolix.service' ) ##################### # PARENT EXITS HERE # ##################### config = Config.load(config_path) _ensure_dir_exists(config.server.ghidcache) _ensure_dir_exists(config.server.logdir) debug = _default_to(config.server.debug, False) verbosity = _default_to(config.server.verbosity, 'info') logutils.autoconfig( tofile = True, logdirname = config.server.logdir, logname = 'hgxserver', loglevel = verbosity ) logger.debug('Parsing config...') host = _cast_host(config.server.host) rps = RemotePersistenceServer( config.server.ghidcache, host, config.server.port, reusable_loop = False, threaded = False, debug = debug ) logger.debug('Starting health check...') # Start a health check healthcheck_server, healthcheck_thread = _serve_healthcheck() healthcheck_thread.start() logger.debug('Starting signal handler...') def signal_handler(signum): logger.info('Caught signal. Exiting.') healthcheck_server.shutdown() rps.stop_threadsafe_nowait() # Normally I'd do this within daemonization, but in this case, we need to # wait to have access to the handler. sighandler = SignalHandler1( str(config.server.pid_file), sigint = signal_handler, sigterm = signal_handler, sigabrt = signal_handler ) sighandler.start() logger.info('Starting remote persistence server...') rps.start()
def do_setup(): ''' Does initial setup of the daemon BEFORE daemonizing. ''' try: config = Config.find() except ConfigMissing: print('Welcome to Hypergolix!') print('No existing configuration found; creating a new one.') config = Config.wherever() # We do need to wrap this, so that we actually store a new config (and # so that we actually coerce the defaults) with config: user_id = config.user.user_id fingerprint = config.user.fingerprint root_secret = config.user.root_secret # Convert the path to a str pid_file = str(config.process.pid_file) if bool(user_id) ^ bool(fingerprint): raise ConfigIncomplete('Invalid config. Config must declare both ' + 'user_id and fingerprint, or neither.') # We have no root secret, so we need to get a password and then inflate # it. if not root_secret: # We have an existing account, so do a single prompt. if user_id: account_entity = user_id password = _enter_password() # We have no existing account, so do a double prompt (and then # generate keys) and then inflate the password. else: password = _create_password() print('Generating a new set of private keys. This may take ' + 'a while.') account_entity = FirstParty() fingerprint = account_entity.ghid account_entity = account_entity._serialize() print('Private keys generated.') print('Expanding password using scrypt. This may take a while.') root_secret = _expand_password( salt_ghid = fingerprint, password = password ) # We have a root secret... else: print('Using stored secret.') # ...and an existing account if user_id: account_entity = user_id # ...but need a new account else: print('Generating a new set of private keys. This may take ' + 'a while.') account_entity = FirstParty() print('Private keys generated.') account_entity = account_entity._serialize() return config.path, pid_file, account_entity, root_secret