Example #1
0
def run_command_start(options):
    """
    Subcommand "crossbar start".
    """
    # do not allow to run more than one Crossbar.io instance
    # from the same Crossbar.io node directory
    #
    pid_data = check_is_running(options.cbdir)
    if pid_data:
        print(
            "Crossbar.io is already running from node directory {} (PID {}).".
            format(options.cbdir, pid_data['pid']))
        sys.exit(1)
    else:
        fp = os.path.join(options.cbdir, _PID_FILENAME)
        with open(fp, 'w') as fd:
            argv = options.argv
            options_dump = vars(options)
            del options_dump['func']
            del options_dump['argv']
            pid_data = {
                'pid': os.getpid(),
                'argv': argv,
                'options': options_dump
            }
            fd.write("{}\n".format(
                json.dumps(pid_data,
                           sort_keys=False,
                           indent=3,
                           separators=(',', ': '))))

    # we use an Autobahn utility to import the "best" available Twisted reactor
    #
    reactor = install_reactor(options.reactor, options.debug)

    # remove node PID file when reactor exits
    #
    def remove_pid_file():
        fp = os.path.join(options.cbdir, _PID_FILENAME)
        if os.path.isfile(fp):
            os.remove(fp)

    reactor.addSystemEventTrigger('after', 'shutdown', remove_pid_file)

    # start Twisted logging
    #
    from crossbar._logging import log_publisher, make_logger
    from crossbar._logging import start_logging, set_global_log_level

    set_global_log_level(options.loglevel)

    log = make_logger()

    if options.logdir:
        # We want to log to a file
        from crossbar._logging import make_legacy_daily_logfile_observer

        log_publisher.addObserver(
            make_legacy_daily_logfile_observer(options.logdir,
                                               options.loglevel))
    else:
        # We want to log to stdout/stderr.
        from crossbar._logging import make_stdout_observer
        from crossbar._logging import make_stderr_observer

        if options.loglevel == "none":
            # Do no logging!
            pass
        elif options.loglevel == "error":
            # Error: Only print errors to stderr.
            log_publisher.addObserver(
                make_stdout_observer(show_source=False,
                                     format=options.logformat))
            log_publisher.addObserver(
                make_stderr_observer(show_source=False,
                                     format=options.logformat))
        elif options.loglevel == "warn":
            # Print warnings+ to stderr.
            log_publisher.addObserver(
                make_stdout_observer(show_source=False,
                                     format=options.logformat))
            log_publisher.addObserver(
                make_stderr_observer(show_source=False,
                                     format=options.logformat))
        elif options.loglevel == "info":
            # Print info to stdout, warn+ to stderr
            log_publisher.addObserver(
                make_stdout_observer(show_source=False,
                                     format=options.logformat))
            log_publisher.addObserver(
                make_stderr_observer(show_source=False,
                                     format=options.logformat))
        elif options.loglevel == "debug":
            # Print debug+info to stdout, warn+ to stderr, with the class
            # source
            log_publisher.addObserver(
                make_stdout_observer(show_source=True,
                                     format=options.logformat))
            log_publisher.addObserver(
                make_stderr_observer(show_source=True,
                                     format=options.logformat))
        elif options.loglevel == "trace":
            # Print trace+, with the class source
            log_publisher.addObserver(
                make_stdout_observer(show_source=True,
                                     format=options.logformat,
                                     trace=True))
            log_publisher.addObserver(
                make_stderr_observer(show_source=True,
                                     format=options.logformat))
        else:
            assert False, "Shouldn't ever get here."

    # Actually start the logger.
    start_logging()

    for line in BANNER.splitlines():
        log.info(click.style(("{:>40}").format(line), fg='yellow', bold=True))

    bannerFormat = "{:>12} {:<24}"
    log.info(
        bannerFormat.format(
            "Version:",
            click.style(crossbar.__version__, fg='yellow', bold=True)))
    # log.info(bannerFormat.format("Python:", click.style(platform.python_implementation(), fg='yellow', bold=True)))
    # log.info(bannerFormat.format("Reactor:", click.style(qual(reactor.__class__).split('.')[-1], fg='yellow', bold=True)))
    log.info(
        bannerFormat.format("Started:",
                            click.style(utcnow(), fg='yellow', bold=True)))
    log.info()

    log.info("Starting from node directory {}".format(options.cbdir))

    # create and start Crossbar.io node
    #
    def start_crossbar():
        from crossbar.controller.node import Node
        node = Node(reactor, options)
        d = node.start()

        def on_error(err):
            log.error("Could not start node: {error}", error=err.value)
            if reactor.running:
                reactor.stop()

        d.addErrback(on_error)

    reactor.callWhenRunning(start_crossbar)

    try:
        log.info("Entering reactor event loop...")
        reactor.run()
    except Exception:
        log.failure("Could not start reactor: {log_failure.value}")
Example #2
0
def _startlog(options, reactor):
    """
    Start the logging in a way that all the subcommands can use it.
    """
    from crossbar._logging import start_logging, set_global_log_level, \
        globalLogPublisher

    loglevel = getattr(options, "loglevel", "info")
    logformat = getattr(options, "logformat", "none")
    colour = getattr(options, "colour", "auto")

    set_global_log_level(loglevel)

    # The log observers (things that print to stderr, file, etc)
    observers = []

    if getattr(options, "logtofile", False):
        # We want to log to a file
        from crossbar._logging import make_logfile_observer

        if not options.logdir:
            logdir = options.cbdir
        else:
            logdir = options.logdir

        logfile = os.path.join(logdir, "node.log")

        if loglevel in ["error", "warn", "info"]:
            show_source = False
        else:
            show_source = True

        observers.append(make_logfile_observer(logfile, show_source))
    else:
        # We want to log to stdout/stderr.
        from crossbar._logging import make_stdout_observer
        from crossbar._logging import make_stderr_observer

        if colour == "auto":
            if sys.__stdout__.isatty():
                colour = True
            else:
                colour = False
        elif colour == "true":
            colour = True
        else:
            colour = False

        if loglevel == "none":
            # Do no logging!
            pass
        elif loglevel in ["error", "warn", "info"]:
            # Print info to stdout, warn+ to stderr
            observers.append(
                make_stdout_observer(show_source=False,
                                     format=logformat,
                                     colour=colour))
            observers.append(
                make_stderr_observer(show_source=False,
                                     format=logformat,
                                     colour=colour))
        elif loglevel == "debug":
            # Print debug+info to stdout, warn+ to stderr, with the class
            # source
            observers.append(
                make_stdout_observer(show_source=True,
                                     format=logformat,
                                     colour=colour))
            observers.append(
                make_stderr_observer(show_source=True,
                                     format=logformat,
                                     colour=colour))
        elif loglevel == "trace":
            # Print trace+, with the class source
            observers.append(
                make_stdout_observer(show_source=True,
                                     format=logformat,
                                     trace=True,
                                     colour=colour))
            observers.append(
                make_stderr_observer(show_source=True,
                                     format=logformat,
                                     colour=colour))
        else:
            assert False, "Shouldn't ever get here."

    for observer in observers:
        globalLogPublisher.addObserver(observer)

        # Make sure that it goes away
        reactor.addSystemEventTrigger('after', 'shutdown',
                                      globalLogPublisher.removeObserver,
                                      observer)

    # Actually start the logger.
    start_logging()
Example #3
0
def run():
    """
    Entry point into (native) worker processes. This wires up stuff such that
    a worker instance is talking WAMP-over-stdio to the node controller.
    """
    import os
    import sys
    import platform
    import signal

    # Ignore SIGINT so we get consistent behavior on control-C versus
    # sending SIGINT to the controller process. When the controller is
    # shutting down, it sends TERM to all its children but ctrl-C
    # handling will send a SIGINT to all the processes in the group
    # (so then the controller sends a TERM but the child already or
    # will very shortly get a SIGINT as well). Twisted installs signal
    # handlers, but not for SIGINT if there's already a custom one
    # present.

    def ignore(sig, frame):
        log.debug("Ignoring SIGINT in worker.")
    signal.signal(signal.SIGINT, ignore)

    # create the top-level parser
    #
    import argparse
    parser = argparse.ArgumentParser()

    parser.add_argument('--reactor',
                        default=None,
                        choices=['select', 'poll', 'epoll', 'kqueue', 'iocp'],
                        help='Explicit Twisted reactor selection (optional).')

    parser.add_argument('--loglevel',
                        default="info",
                        choices=['none', 'error', 'warn', 'info', 'debug', 'trace'],
                        help='Initial log level.')

    parser.add_argument('-c',
                        '--cbdir',
                        type=str,
                        help="Crossbar.io node directory (required).")

    parser.add_argument('-n',
                        '--node',
                        type=str,
                        help='Crossbar.io node ID (required).')

    parser.add_argument('-w',
                        '--worker',
                        type=str,
                        help='Crossbar.io worker ID (required).')

    parser.add_argument('-r',
                        '--realm',
                        type=str,
                        help='Crossbar.io node (management) realm (required).')

    parser.add_argument('-t',
                        '--type',
                        choices=['router', 'container'],
                        help='Worker type (required).')

    parser.add_argument('--title',
                        type=str,
                        default=None,
                        help='Worker process title to set (optional).')

    options = parser.parse_args()

    # make sure logging to something else than stdio is setup _first_
    #
    from crossbar._logging import make_JSON_observer, cb_logging_aware, _stderr
    from crossbar._logging import make_logger, log_publisher, start_logging
    from crossbar._logging import set_global_log_level

    # Set the global log level
    set_global_log_level(options.loglevel)

    log = make_logger()

    # Print a magic phrase that tells the capturing logger that it supports
    # Crossbar's rich logging
    print(cb_logging_aware, file=_stderr)
    _stderr.flush()

    flo = make_JSON_observer(_stderr)
    log_publisher.addObserver(flo)
    start_logging()

    try:
        import setproctitle
    except ImportError:
        log.debug("Could not set worker process title (setproctitle not installed)")
    else:
        # set process title if requested to
        #
        if options.title:
            setproctitle.setproctitle(options.title)
        else:
            WORKER_TYPE_TO_TITLE = {
                'router': 'crossbar-worker [router]',
                'container': 'crossbar-worker [container]'
            }
            setproctitle.setproctitle(WORKER_TYPE_TO_TITLE[options.type].strip())

    # we use an Autobahn utility to import the "best" available Twisted reactor
    #
    from autobahn.twisted.choosereactor import install_reactor
    reactor = install_reactor(options.reactor)

    from twisted.python.reflect import qual
    log.info("Worker running under {python}-{reactor}",
             python=platform.python_implementation(),
             reactor=qual(reactor.__class__).split('.')[-1])

    options.cbdir = os.path.abspath(options.cbdir)
    os.chdir(options.cbdir)
    # log.msg("Starting from node directory {}".format(options.cbdir))

    from crossbar.worker.router import RouterWorkerSession
    from crossbar.worker.container import ContainerWorkerSession

    WORKER_TYPE_TO_CLASS = {
        'router': RouterWorkerSession,
        'container': ContainerWorkerSession
    }

    from autobahn.twisted.websocket import WampWebSocketServerProtocol

    class WorkerServerProtocol(WampWebSocketServerProtocol):

        def connectionLost(self, reason):
            try:
                # this log message is unlikely to reach the controller (unless
                # only stdin/stdout pipes were lost, but not stderr)
                log.warn("Connection to node controller lost.")
                WampWebSocketServerProtocol.connectionLost(self, reason)
            except:
                pass
            finally:
                # losing the connection to the node controller is fatal:
                # stop the reactor and exit with error
                log.info("No more controller connection; shutting down.")
                reactor.addSystemEventTrigger('after', 'shutdown', os._exit, 1)
                try:
                    reactor.stop()
                except ReactorNotRunning:
                    pass

    try:
        # create a WAMP application session factory
        #
        from autobahn.twisted.wamp import ApplicationSessionFactory
        from autobahn.wamp.types import ComponentConfig

        session_config = ComponentConfig(realm=options.realm, extra=options)
        session_factory = ApplicationSessionFactory(session_config)
        session_factory.session = WORKER_TYPE_TO_CLASS[options.type]

        # create a WAMP-over-WebSocket transport server factory
        #
        from autobahn.twisted.websocket import WampWebSocketServerFactory
        transport_factory = WampWebSocketServerFactory(session_factory, "ws://localhost", debug=False, debug_wamp=False)
        transport_factory.protocol = WorkerServerProtocol
        transport_factory.setProtocolOptions(failByDrop=False)

        # create a protocol instance and wire up to stdio
        #
        from twisted.python.runtime import platform as _platform
        from twisted.internet import stdio
        proto = transport_factory.buildProtocol(None)
        if _platform.isWindows():
            stdio.StandardIO(proto)
        else:
            stdio.StandardIO(proto, stdout=3)

        # now start reactor loop
        #
        if False:
            log.info("vmprof enabled.")

            import os
            import vmprof

            PROFILE_FILE = 'vmprof_{}.dat'.format(os.getpid())

            outfd = os.open(PROFILE_FILE, os.O_RDWR | os.O_CREAT | os.O_TRUNC)
            vmprof.enable(outfd, period=0.01)

            log.info("Entering event loop...")
            reactor.run()

            vmprof.disable()
        else:
            log.debug("Entering event loop...")
            reactor.run()

    except Exception as e:
        log.info("Unhandled exception: {}".format(e))
        if reactor.running:
            reactor.addSystemEventTrigger('after', 'shutdown', os._exit, 1)
            reactor.stop()
        else:
            sys.exit(1)
Example #4
0
def _startlog(options, reactor):
    """
    Start the logging in a way that all the subcommands can use it.
    """
    from crossbar._logging import start_logging, set_global_log_level
    from crossbar._logging import globalLogPublisher as log_publisher

    loglevel = getattr(options, "loglevel", "info")
    logformat = getattr(options, "logformat", "none")

    set_global_log_level(loglevel)

    # The log observers (things that print to stderr, file, etc)
    observers = []

    if getattr(options, "logtofile", False):
        # We want to log to a file
        from crossbar._logging import make_logfile_observer

        if not options.logdir:
            logdir = options.cbdir
        else:
            logdir = options.logdir

        logfile = os.path.join(logdir, "node.log")

        if loglevel in ["error", "warn", "info"]:
            show_source = False
        else:
            show_source = True

        observers.append(make_logfile_observer(logfile, show_source))
    else:
        # We want to log to stdout/stderr.
        from crossbar._logging import make_stdout_observer
        from crossbar._logging import make_stderr_observer

        if loglevel == "none":
            # Do no logging!
            pass
        elif loglevel in ["error", "warn", "info"]:
            # Print info to stdout, warn+ to stderr
            observers.append(make_stdout_observer(show_source=False,
                                                  format=logformat))
            observers.append(make_stderr_observer(show_source=False,
                                                  format=logformat))
        elif loglevel == "debug":
            # Print debug+info to stdout, warn+ to stderr, with the class
            # source
            observers.append(make_stdout_observer(show_source=True,
                                                  format=logformat))
            observers.append(make_stderr_observer(show_source=True,
                                                  format=logformat))
        elif loglevel == "trace":
            # Print trace+, with the class source
            observers.append(make_stdout_observer(show_source=True,
                                                  format=logformat,
                                                  trace=True))
            observers.append(make_stderr_observer(show_source=True,
                                                  format=logformat))
        else:
            assert False, "Shouldn't ever get here."

    for observer in observers:
        log_publisher.addObserver(observer)

        # Make sure that it goes away
        reactor.addSystemEventTrigger('after', 'shutdown',
                                      log_publisher.removeObserver, observer)

    # Actually start the logger.
    start_logging()
Example #5
0
def run_command_start(options):
    """
    Subcommand "crossbar start".
    """
    # do not allow to run more than one Crossbar.io instance
    # from the same Crossbar.io node directory
    #
    pid_data = check_is_running(options.cbdir)
    if pid_data:
        print("Crossbar.io is already running from node directory {} (PID {}).".format(options.cbdir, pid_data['pid']))
        sys.exit(1)
    else:
        fp = os.path.join(options.cbdir, _PID_FILENAME)
        with open(fp, 'w') as fd:
            argv = options.argv
            options_dump = vars(options)
            del options_dump['func']
            del options_dump['argv']
            pid_data = {
                'pid': os.getpid(),
                'argv': argv,
                'options': options_dump
            }
            fd.write("{}\n".format(json.dumps(pid_data, sort_keys=False, indent=3, separators=(',', ': '))))

    # we use an Autobahn utility to import the "best" available Twisted reactor
    #
    reactor = install_reactor(options.reactor, options.debug)

    # remove node PID file when reactor exits
    #
    def remove_pid_file():
        fp = os.path.join(options.cbdir, _PID_FILENAME)
        if os.path.isfile(fp):
            os.remove(fp)
    reactor.addSystemEventTrigger('after', 'shutdown', remove_pid_file)

    # start Twisted logging
    #
    from crossbar._logging import log_publisher, make_logger
    from crossbar._logging import start_logging, set_global_log_level

    set_global_log_level(options.loglevel)

    log = make_logger()

    if options.logdir:
        # We want to log to a file
        from crossbar._logging import make_legacy_daily_logfile_observer

        log_publisher.addObserver(
            make_legacy_daily_logfile_observer(options.logdir, options.loglevel))
    else:
        # We want to log to stdout/stderr.
        from crossbar._logging import make_stdout_observer
        from crossbar._logging import make_stderr_observer

        if options.loglevel == "none":
            # Do no logging!
            pass
        elif options.loglevel == "error":
            # Error: Only print errors to stderr.
            log_publisher.addObserver(make_stdout_observer(show_source=False, format=options.logformat))
            log_publisher.addObserver(make_stderr_observer(show_source=False, format=options.logformat))
        elif options.loglevel == "warn":
            # Print warnings+ to stderr.
            log_publisher.addObserver(make_stdout_observer(show_source=False, format=options.logformat))
            log_publisher.addObserver(make_stderr_observer(show_source=False, format=options.logformat))
        elif options.loglevel == "info":
            # Print info to stdout, warn+ to stderr
            log_publisher.addObserver(make_stdout_observer(show_source=False, format=options.logformat))
            log_publisher.addObserver(make_stderr_observer(show_source=False, format=options.logformat))
        elif options.loglevel == "debug":
            # Print debug+info to stdout, warn+ to stderr, with the class
            # source
            log_publisher.addObserver(make_stdout_observer(show_source=True, format=options.logformat))
            log_publisher.addObserver(make_stderr_observer(show_source=True, format=options.logformat))
        elif options.loglevel == "trace":
            # Print trace+, with the class source
            log_publisher.addObserver(make_stdout_observer(show_source=True, format=options.logformat, trace=True))
            log_publisher.addObserver(make_stderr_observer(show_source=True, format=options.logformat))
        else:
            assert False, "Shouldn't ever get here."

    # Actually start the logger.
    start_logging()

    for line in BANNER.splitlines():
        log.info(click.style(("{:>40}").format(line), fg='yellow', bold=True))

    bannerFormat = "{:>12} {:<24}"
    log.info(bannerFormat.format("Version:", click.style(crossbar.__version__, fg='yellow', bold=True)))
    # log.info(bannerFormat.format("Python:", click.style(platform.python_implementation(), fg='yellow', bold=True)))
    # log.info(bannerFormat.format("Reactor:", click.style(qual(reactor.__class__).split('.')[-1], fg='yellow', bold=True)))
    log.info(bannerFormat.format("Started:", click.style(utcnow(), fg='yellow', bold=True)))
    log.info()

    log.info("Starting from node directory {}".format(options.cbdir))

    # create and start Crossbar.io node
    #
    def start_crossbar():
        from crossbar.controller.node import Node
        node = Node(reactor, options)
        d = node.start()

        def on_error(err):
            log.error("Could not start node: {error}", error=err.value)
            if reactor.running:
                reactor.stop()
        d.addErrback(on_error)
    reactor.callWhenRunning(start_crossbar)

    try:
        log.info("Entering reactor event loop...")
        reactor.run()
    except Exception:
        log.failure("Could not start reactor: {log_failure.value}")
Example #6
0
def _startlog(options):
    """
    Start the logging in a way that all the subcommands can use it.
    """
    from crossbar._logging import log_publisher, start_logging
    from crossbar._logging import set_global_log_level

    loglevel = getattr(options, "loglevel", "info")
    logformat = getattr(options, "logformat", "none")

    set_global_log_level(loglevel)

    if getattr(options, "logtofile", False):
        # We want to log to a file
        from crossbar._logging import make_logfile_observer

        if not options.logdir:
            logdir = options.cbdir
        else:
            logdir = options.logdir

        logfile = os.path.join(logdir, "node.log")

        if loglevel in ["error", "warn", "info"]:
            show_source = False
        else:
            show_source = True

        log_publisher.addObserver(make_logfile_observer(logfile, show_source))
    else:
        # We want to log to stdout/stderr.
        from crossbar._logging import make_stdout_observer
        from crossbar._logging import make_stderr_observer

        if loglevel == "none":
            # Do no logging!
            pass
        elif loglevel in ["error", "warn", "info"]:
            # Print info to stdout, warn+ to stderr
            log_publisher.addObserver(make_stdout_observer(show_source=False,
                                                           format=logformat))
            log_publisher.addObserver(make_stderr_observer(show_source=False,
                                                           format=logformat))
        elif loglevel == "debug":
            # Print debug+info to stdout, warn+ to stderr, with the class
            # source
            log_publisher.addObserver(make_stdout_observer(show_source=True,
                                                           format=logformat))
            log_publisher.addObserver(make_stderr_observer(show_source=True,
                                                           format=logformat))
        elif loglevel == "trace":
            # Print trace+, with the class source
            log_publisher.addObserver(make_stdout_observer(show_source=True,
                                                           format=logformat,
                                                           trace=True))
            log_publisher.addObserver(make_stderr_observer(show_source=True,
                                                           format=logformat))
        else:
            assert False, "Shouldn't ever get here."

    # Actually start the logger.
    start_logging()