def configure_unified_logger(args): ''' If we want to run a single unified logger for the entire test, set that up here. Note that these logs will be in addition to those created naturally during hypergolix operation (which will live within each app's respective hgx_root) ''' from hypergolix import logutils if args.logdir: logutils.autoconfig(tofile=True, logdirname=args.logdir, loglevel=args.verbosity) else: logutils.autoconfig(tofile=False, loglevel=args.verbosity)
def configure_unified_logger(args): ''' If we want to run a single unified logger for the entire test, set that up here. Note that these logs will be in addition to those created naturally during hypergolix operation (which will live within each app's respective hgx_root) ''' from hypergolix import logutils if args.logdir: logutils.autoconfig( tofile = True, logdirname = args.logdir, loglevel = args.verbosity ) else: logutils.autoconfig( tofile = False, loglevel = args.verbosity )
# Test object discarding # ----------- joint2.hgx_discard_threadsafe() self.assertFalse(joint2._isalive_3141592) self.assertEqual( len(self.ipccore._update_listeners.get_any(dispatchable2.ghid)), 1 ) self.assertFalse(dispatchable2.deleted) # Test object discarding # ----------- dispatchable1 = self.oracle.objs[obj1.hgx_ghid] obj1.hgx_delete_threadsafe() self.assertTrue(dispatchable1.deleted) self.assertFalse(obj1._isalive_3141592) # -------------------------------------------------------------------- # Comment this out if no interactivity desired # # Start an interactive IPython interpreter with local namespace, but # # suppress all IPython-related warnings. # with warnings.catch_warnings(): # warnings.simplefilter('ignore') # IPython.embed() if __name__ == "__main__": from hypergolix import logutils logutils.autoconfig('debug') unittest.main()
) ) # With an unknown author with self.assertRaises(InvalidIdentity): await_coroutine_threadsafe( coro = self.lawyer.validate_garq(req3), loop = self.nooploop._loop ) class LawyerCoreTest(GenericLawyerTest, unittest.TestCase): ''' Test the core lawyer-ness. ''' def setUp(self): self.librarian = LibrarianCore.__fixture__() self.lawyer = LawyerCore() self.lawyer.assemble(self.librarian) if __name__ == "__main__": from hypergolix import logutils logutils.autoconfig(loglevel='debug') # from hypergolix.utils import TraceLogger # with TraceLogger(interval=10): # unittest.main() unittest.main()
'port': 5358, 'tls': False, }, debug = True, aengel = cls.aengel, ) cls.remote2 = Autocomms( autoresponder_class = PersisterBridgeClient, connector_class = WSBasicClient, connector_kwargs = { 'host': 'localhost', 'port': 5358, 'tls': False, }, debug = True, aengel = cls.aengel, ) @classmethod def tearDownClass(cls): cls.aengel.stop() if __name__ == "__main__": from hypergolix import logutils logutils.autoconfig() # from hypergolix.utils import TraceLogger # with TraceLogger(interval=10): # unittest.main() unittest.main()
argv = cmd_str.split() argv.append('--root') argv.append(str(cfg_path)) with _NoSTDOUT(), self.assertWarns(DeprecationWarning): ingest_args(argv) config = Config.load(cfg_path) # THE PROBLEM HERE IS NOT JUST COERCE DEFAULTS! config.py, # in its handle_args section, is passing in default values # that are interfering with everything else. self.assertEqual(config, cmd_result) # Don't need the temp dir for this; un-context to escape permissions for cmd_str in failing_commands: with self.subTest(cmd_str): argv = cmd_str.split() argv.append('--root') argv.append(str(root)) # Note that argparse will always push usage to stderr in a # suuuuuuper annoying way if we don't suppress it. with self.assertRaises(SystemExit), _NoSTDERR(), _NoSTDOUT(): ingest_args(argv) if __name__ == "__main__": from hypergolix import logutils logutils.autoconfig() unittest.main()
def app_core(user_id, password, startup_logger, aengel=None, _scrypt_hardness=None, hgx_root=None, enable_logs=True): ''' This is where all of the UX goes for the service itself. From here, we build a credential, then a bootstrap, and then persisters, IPC, etc. Expected defaults: host: 'localhost' port: 7770 tls: True ipc_port: 7772 debug: False logfile: None verbosity: 'warning' traceur: False ''' if startup_logger is not None: # At some point, this will need to restore the module logger, but for # now it really doesn't make any difference whatsoever effective_logger = startup_logger else: effective_logger = logger with Config(hgx_root) as config: # Convert paths to strs cache_dir = str(config.cache_dir) log_dir = str(config.log_dir) if user_id is None: user_id = config.user_id debug = config.debug_mode verbosity = config.log_verbosity ipc_port = config.ipc_port remotes = config.remotes if enable_logs: logutils.autoconfig( tofile = True, logdirname = log_dir, loglevel = verbosity, logname = 'hgxapp' ) if not aengel: aengel = Aengel() core = AgentBootstrap(aengel=aengel, debug=debug, cache_dir=cache_dir) core.assemble() # In this case, we have no existing user_id. if user_id is None: user_id = core.bootstrap_zero( password = password, _scrypt_hardness = _scrypt_hardness ) effective_logger.critical( 'Identity created. Your user ID is ' + str(user_id) + '. You ' + 'will need your user ID to log in to Hypergolix from another ' + 'machine, or if your Hypergolix configuration file is corrupted ' + 'or lost.' ) with Config(hgx_root) as config: config.fingerprint = core.whoami config.user_id = user_id # Hey look, we have an existing user. else: core.bootstrap( user_id = user_id, password = password, _scrypt_hardness = _scrypt_hardness, ) effective_logger.info('Login successful.') # Add all of the remotes to a namespace preserver persisters = [] for remote in remotes: try: persister = Autocomms( autoresponder_name = 'remrecli', autoresponder_class = PersisterBridgeClient, connector_name = 'remwscli', connector_class = WSBasicClient, connector_kwargs = { 'host': remote.host, 'port': remote.port, 'tls': remote.tls, }, debug = debug, aengel = aengel, ) except CancelledError: effective_logger.error( 'Error while connecting to upstream remote at ' + remote.host + ':' + str(remote.port) + '. Connection will ' + 'only be reattempted after restarting Hypergolix.' ) else: core.salmonator.add_upstream_remote(persister) persisters.append(persister) # Finally, add the ipc system core.ipccore.add_ipc_server( 'wslocal', WSBasicServer, host = 'localhost', port = ipc_port, tls = False, debug = debug, aengel = aengel, threaded = True, thread_name = _generate_threadnames('ipc-ws')[0], ) return persisters, core, aengel
def start(namespace=None): ''' Starts a Hypergolix daemon. ''' # Command args coming in. if namespace is not None: host = namespace.host port = namespace.port debug = namespace.debug traceur = namespace.traceur chdir = namespace.chdir # Convert log dir to absolute if defined if namespace.logdir is not None: log_dir = str(pathlib.Path(namespace.logdir).absolute()) else: log_dir = namespace.log_dir # Convert cache dir to absolute if defined if namespace.cachedir is not None: cache_dir = str(pathlib.Path(namespace.cachedir).absolute()) else: cache_dir = namespace.cache_dir verbosity = namespace.verbosity # Convert pid path to absolute (must be defined) pid_path = str(pathlib.Path(namespace.pidfile).absolute()) # Daemonizing, we still need these to be defined to avoid NameErrors else: host = None port = None debug = None traceur = None chdir = None log_dir = None cache_dir = None verbosity = None pid_path = None with Daemonizer() as (is_setup, daemonizer): # Daemonize. Don't strip cmd-line arguments, or we won't know to # continue with startup ( is_parent, host, port, debug, traceur, log_dir, cache_dir, verbosity, pid_path ) = daemonizer( pid_path, host, port, debug, traceur, log_dir, cache_dir, verbosity, pid_path, chdir=chdir, # Don't strip these, because otherwise we won't know to resume # daemonization strip_cmd_args=False) if not is_parent: # Do signal handling within the Daemonizer so that the parent knows # it was correctly init'd sighandler = SignalHandler1(pid_path) sighandler.start() ##################### # PARENT EXITS HERE # ##################### verbosity = _cast_verbosity(verbosity, debug, traceur) if log_dir is not None: logutils.autoconfig(tofile=True, logdirname=log_dir, logname='hgxremote', loglevel=verbosity) logger.debug('Starting remote persistence server...') host = _cast_host(host) remote, server = _hgx_server(host, port, cache_dir, debug, traceur) logger.info('Remote persistence server successfully started.') # Wait indefinitely until signal caught. # TODO: literally anything smarter than this. try: while True: time.sleep(.5) except SIGTERM: logger.info('Caught SIGTERM. Exiting.') del remote del server
'"debug" -> most verbose, ' '"info" -> somewhat verbose, ' '"warning" -> default python verbosity, ' '"error" -> quiet.', ) parser.add_argument('unittest_args', nargs='*') args, unittest_args = parser.parse_known_args() # Do logging config and stuff from hypergolix import logutils if args.logdir: logutils.autoconfig( tofile = True, logdirname = args.logdir, loglevel = args.verbosity ) else: logutils.autoconfig( tofile = False, loglevel = args.verbosity ) # Dammit unittest using argparse # sys.argv[1:] = args.unittest_args from trashtest import * if args.traceur: # This diagnoses deadlocks from hypergolix.utils import TraceLogger
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 run_daemon(cfg_path, pid_file, parent_port, account_entity, root_secret): ''' Start the actual Hypergolix daemon. ''' # Start reporting to our parent about how stuff is going. parent_signaller = _StartupReporter(parent_port) startup_logger = parent_signaller.start() try: config = Config.load(cfg_path) # Convert paths to strs and make sure the dirs exist cache_dir = str(config.process.ghidcache) log_dir = str(config.process.logdir) _ensure_dir_exists(config.process.ghidcache) _ensure_dir_exists(config.process.logdir) debug = _default_to(config.instrumentation.debug, False) verbosity = _default_to(config.instrumentation.verbosity, 'info') logutils.autoconfig( tofile = True, logdirname = log_dir, loglevel = verbosity, logname = 'hgxapp' ) ipc_port = config.process.ipc_port remotes = config.remotes # Look to see if we have an existing user_id to determine behavior save_cfg = not bool(config.user.user_id) hgxcore = _DaemonCore( cache_dir = cache_dir, ipc_port = ipc_port, reusable_loop = False, threaded = False, debug = debug, cfg_path = cfg_path, save_cfg = save_cfg, boot_logger = parent_signaller ) for remote in remotes: hgxcore.add_remote( connection_cls = WSBeatingConn, host = remote.host, port = remote.port, tls = remote.tls ) account = Account( user_id = account_entity, root_secret = root_secret, hgxcore = hgxcore ) hgxcore.account = account # We need a signal handler for that. def signal_handler(signum): logger.info('Caught signal. Exiting.') hgxcore.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( pid_file, sigint = signal_handler, sigterm = signal_handler, sigabrt = signal_handler ) sighandler.start() startup_logger.info('Booting Hypergolix...') hgxcore.start() except Exception: startup_logger.error('Failed to start Hypergolix:\n' + ''.join(traceback.format_exc())) raise finally: # This is idempotent, so no worries if we already called it parent_signaller.stop()