예제 #1
0
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)
예제 #2
0
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)
예제 #3
0
 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']
예제 #4
0
 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
예제 #5
0
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()
예제 #6
0
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