Esempio n. 1
0
def construct_boot_info(
        app_identifier: str, component_types: Tuple[Type[BaseComponentAPI],
                                                    ...],
        sub_configs: Sequence[Type[BaseAppConfig]]) -> BootPrologueData:
    if is_prerelease():
        # this modifies the asyncio logger, but will be overridden by any custom settings below
        enable_warnings_by_default()

    configure_parsers(parser, subparser, component_types)

    args = parse_and_validate_cli()

    common_log_level = resolve_common_log_level_or_error(args)

    trinity_config = load_trinity_config_from_parser_args(
        parser, args, app_identifier, sub_configs)

    ensure_data_dir_is_initialized(trinity_config)
    handlers, min_log_level, logger_levels = install_logging(
        args, trinity_config, common_log_level)

    boot_info = BootInfo(
        args=args,
        trinity_config=trinity_config,
        min_log_level=min_log_level,
        logger_levels=logger_levels,
        profile=bool(args.profile),
    )

    validate_component_cli(component_types, boot_info)

    return boot_info, handlers
def boot_info(trinity_config):
    return BootInfo(
        args=Namespace(),
        trinity_config=trinity_config,
        profile=False,
        min_log_level=logging.DEBUG,
        logger_levels={},
    )
Esempio n. 3
0
def boot_info(trinity_config):
    return BootInfo(
        args=Namespace(),
        trinity_config=trinity_config,
        profile=False,
        child_process_log_level=logging.INFO,
        logger_levels={},
    )
Esempio n. 4
0
def _setup_standalone_component(
    component_type: Union[Type['TrioIsolatedComponent'],
                          Type['AsyncioIsolatedComponent']],
    app_identifier: str,
) -> Tuple[Union['TrioIsolatedComponent', 'AsyncioIsolatedComponent'], Tuple[
        str, ...]]:
    if app_identifier == APP_IDENTIFIER_ETH1:
        app_cfg: Type[BaseAppConfig] = Eth1AppConfig
    elif app_identifier == APP_IDENTIFIER_BEACON:
        app_cfg = BeaconAppConfig
    else:
        raise ValueError("Unknown app identifier: %s", app_identifier)

    # Require a root dir to be specified as we don't want to mess with the default one.
    for action in parser._actions:
        if action.dest == 'trinity_root_dir':
            action.required = True
            break

    component_type.configure_parser(parser, subparser)
    parser.add_argument(
        '--connect-to-endpoints',
        help=
        "A list of event bus IPC files for components we should connect to",
        nargs='+',
        default=tuple(),
    )
    args = parser.parse_args()
    # FIXME: Figure out a way to avoid having to set this.
    args.sync_mode = SYNC_FULL
    args.enable_metrics = False

    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)s: %(message)s',
                        datefmt='%H:%M:%S')
    if args.log_levels is not None:
        for name, level in args.log_levels.items():
            if name is None:
                name = ''
            get_logger(name).setLevel(level)

    trinity_config = TrinityConfig.from_parser_args(args, app_identifier,
                                                    (app_cfg, ))
    trinity_config.trinity_root_dir.mkdir(exist_ok=True)
    if not is_data_dir_initialized(trinity_config):
        initialize_data_dir(trinity_config)
    boot_info = BootInfo(
        args=args,
        trinity_config=trinity_config,
        min_log_level=None,
        logger_levels=None,
        profile=False,
    )
    return component_type(boot_info), args.connect_to_endpoints
Esempio n. 5
0
def main_entry(trinity_boot: BootFn,
               app_identifier: str,
               component_types: Tuple[Type[BaseComponentAPI], ...],
               sub_configs: Sequence[Type[BaseAppConfig]]) -> None:
    if is_prerelease():
        # this modifies the asyncio logger, but will be overridden by any custom settings below
        enable_warnings_by_default()

    for component_cls in component_types:
        component_cls.configure_parser(parser, subparser)

    argcomplete.autocomplete(parser)

    args = parser.parse_args()

    if not args.genesis and args.network_id not in PRECONFIGURED_NETWORKS:
        parser.error(
            f"Unsupported network id: {args.network_id}. To use a network besides "
            "mainnet or ropsten, you must supply a genesis file with a flag, like "
            "`--genesis path/to/genesis.json`, also you must specify a data "
            "directory with `--data-dir path/to/data/directory`"
        )

    # The `common_log_level` is derived from `--log-level <Level>` / `-l <Level>` without
    # specifying any module. If present, it is used for both `stderr` and `file` logging.
    common_log_level = args.log_levels and args.log_levels.get(None)
    has_ambigous_logging_config = ((
        common_log_level is not None and
        args.stderr_log_level is not None
    ) or (
        common_log_level is not None and
        args.file_log_level is not None
    ))

    if has_ambigous_logging_config:
        parser.error(
            f"""\n
            Ambiguous logging configuration: The `--log-level (-l)` flag sets the
            log level for both file and stderr logging.
            To configure different log level for file and stderr logging,
            remove the `--log-level` flag and use `--stderr-log-level` and/or
            `--file-log-level` separately.
            Alternatively, remove the `--stderr-log-level` and/or `--file-log-level`
            flags to share one single log level across both handlers.
            """
        )

    try:
        trinity_config = TrinityConfig.from_parser_args(args, app_identifier, sub_configs)
    except AmbigiousFileSystem:
        parser.error(TRINITY_AMBIGIOUS_FILESYSTEM_INFO)

    if not is_data_dir_initialized(trinity_config):
        # TODO: this will only work as is for chains with known genesis
        # parameters.  Need to flesh out how genesis parameters for custom
        # chains are defined and passed around.
        try:
            initialize_data_dir(trinity_config)
        except AmbigiousFileSystem:
            parser.error(TRINITY_AMBIGIOUS_FILESYSTEM_INFO)
        except MissingPath as e:
            parser.error(
                "\n"
                f"It appears that {e.path} does not exist. "
                "Trinity does not attempt to create directories outside of its root path. "
                "Either manually create the path or ensure you are using a data directory "
                "inside the XDG_TRINITY_ROOT path"
            )

    # +---------------+
    # | LOGGING SETUP |
    # +---------------+

    # Setup logging to stderr
    stderr_logger_level = (
        args.stderr_log_level
        if args.stderr_log_level is not None
        else (common_log_level if common_log_level is not None else logging.INFO)
    )
    handler_stderr = setup_stderr_logging(stderr_logger_level)

    # Setup file based logging
    file_logger_level = (
        args.file_log_level
        if args.file_log_level is not None
        else (common_log_level if common_log_level is not None else logging.DEBUG)
    )
    handler_file = setup_file_logging(trinity_config.logfile_path, file_logger_level)

    # Set the individual logger levels that have been specified.
    logger_levels = {} if args.log_levels is None else args.log_levels
    set_logger_levels(logger_levels)

    # get the root logger and set it to the level of the stderr logger.
    logger = logging.getLogger()
    logger.setLevel(stderr_logger_level)

    # This prints out the ASCII "trinity" header in the terminal
    display_launch_logs(trinity_config)

    # Setup the log listener which child processes relay their logs through
    log_listener = IPCListener(handler_stderr, handler_file)

    # Determine what logging level child processes should use.
    child_process_log_level = min(
        stderr_logger_level,
        file_logger_level,
        *logger_levels.values(),
    )

    boot_info = BootInfo(
        args=args,
        trinity_config=trinity_config,
        child_process_log_level=child_process_log_level,
        logger_levels=logger_levels,
        profile=bool(args.profile),
    )

    # Let the components do runtime validation
    for component_cls in component_types:
        component_cls.validate_cli(boot_info)

    # Components can provide a subcommand with a `func` which does then control
    # the entire process from here.
    if hasattr(args, 'func'):
        args.func(args, trinity_config)
        return

    if hasattr(args, 'munge_func'):
        args.munge_func(args, trinity_config)

    runtime_component_types = tuple(
        component_cls
        for component_cls in component_types
        if issubclass(component_cls, ComponentAPI)
    )

    with log_listener.run(trinity_config.logging_ipc_path):

        processes = trinity_boot(boot_info)

        loop = asyncio.get_event_loop()

        def kill_trinity_with_reason(reason: str) -> None:
            kill_trinity_gracefully(
                trinity_config,
                logger,
                processes,
                reason=reason
            )

        component_manager_service = ComponentManager(
            boot_info,
            runtime_component_types,
            kill_trinity_with_reason,
        )
        manager = AsyncioManager(component_manager_service)

        loop.add_signal_handler(
            signal.SIGTERM,
            manager.cancel,
            'SIGTERM',
        )
        loop.add_signal_handler(
            signal.SIGINT,
            component_manager_service.shutdown,
            'CTRL+C',
        )

        try:
            loop.run_until_complete(manager.run())
        except BaseException as err:
            logger.error("Error during trinity run: %r", err)
            raise
        finally:
            kill_trinity_with_reason(component_manager_service.reason)
            if trinity_config.trinity_tmp_root_dir:
                shutil.rmtree(trinity_config.trinity_root_dir)
Esempio n. 6
0
async def run_standalone_component(
    component: Union[Type['TrioIsolatedComponent'],
                     Type['AsyncioIsolatedComponent']],
    app_identifier: str,
) -> None:
    from trinity.extensibility.trio import TrioIsolatedComponent  # noqa: F811
    from trinity.extensibility.asyncio import AsyncioIsolatedComponent  # noqa: F811
    if issubclass(component, TrioIsolatedComponent):
        endpoint_type: Union[Type[TrioEndpoint],
                             Type[AsyncioEndpoint]] = TrioEndpoint
    elif issubclass(component, AsyncioIsolatedComponent):
        endpoint_type = AsyncioEndpoint
    else:
        raise ValueError("Unknown component type: %s", type(component))

    if app_identifier == APP_IDENTIFIER_ETH1:
        app_cfg: Type[BaseAppConfig] = Eth1AppConfig
    elif app_identifier == APP_IDENTIFIER_BEACON:
        app_cfg = BeaconAppConfig
    else:
        raise ValueError("Unknown app identifier: %s", app_identifier)

    # Require a root dir to be specified as we don't want to mess with the default one.
    for action in parser._actions:
        if action.dest == 'trinity_root_dir':
            action.required = True
            break

    component.configure_parser(parser, subparser)
    parser.add_argument(
        '--connect-to-endpoints',
        help=
        "A list of event bus IPC files for components we should connect to",
        nargs='+',
        default=tuple(),
    )
    args = parser.parse_args()
    # FIXME: Figure out a way to avoid having to set this.
    args.sync_mode = SYNC_FULL

    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)s: %(message)s',
                        datefmt='%H:%M:%S')
    if args.log_levels is not None:
        for name, level in args.log_levels.items():
            get_logger(name).setLevel(level)

    trinity_config = TrinityConfig.from_parser_args(args, app_identifier,
                                                    (app_cfg, ))
    trinity_config.trinity_root_dir.mkdir(exist_ok=True)
    if not is_data_dir_initialized(trinity_config):
        initialize_data_dir(trinity_config)
    boot_info = BootInfo(
        args=args,
        trinity_config=trinity_config,
        child_process_log_level=None,
        logger_levels=None,
        profile=False,
    )
    conn_config = ConnectionConfig.from_name(component.get_endpoint_name(),
                                             trinity_config.ipc_dir)

    async with endpoint_type.serve(conn_config) as event_bus:
        for endpoint in args.connect_to_endpoints:
            path = pathlib.Path(endpoint)
            if not path.is_socket():
                raise ValueError("Invalid IPC path: {path}")
            connection_config = ConnectionConfig(name=path.stem, path=path)
            logger.info("Attempting to connect to eventbus endpoint at %s",
                        connection_config)
            await event_bus.connect_to_endpoints(connection_config)
        await component.do_run(boot_info, event_bus)