Ejemplo n.º 1
0
def main():
    pprint.pprint(dict(os.environ), stream=sys.stderr)

    if os.getenv('JUPYTERHUB_SERVICE_URL'):
        url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
        app = web.Application(
            [
                (r'.*/env', EnvHandler),
                (r'.*/api/(.*)', APIHandler),
                (r'.*/whoami/?', WhoAmIHandler),
                (r'.*/owhoami/?', OWhoAmIHandler),
                (r'.*/oauth_callback', HubOAuthCallbackHandler),
                (r'.*', EchoHandler),
            ],
            cookie_secret=os.urandom(32),
        )

        ssl_context = None
        key = os.environ.get('JUPYTERHUB_SSL_KEYFILE') or ''
        cert = os.environ.get('JUPYTERHUB_SSL_CERTFILE') or ''
        ca = os.environ.get('JUPYTERHUB_SSL_CLIENT_CA') or ''

        if key and cert and ca:
            ssl_context = make_ssl_context(key,
                                           cert,
                                           cafile=ca,
                                           check_hostname=False)

        server = httpserver.HTTPServer(app, ssl_options=ssl_context)
        server.listen(url.port, url.hostname)
    try:
        ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        print('\nInterrupted')
Ejemplo n.º 2
0
def main():
    pprint.pprint(dict(os.environ), stream=sys.stderr)

    if os.getenv('JUPYTERHUB_SERVICE_URL'):
        url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
        app = web.Application(
            [
                (r'.*/env', EnvHandler),
                (r'.*/api/(.*)', APIHandler),
                (r'.*/whoami/?', WhoAmIHandler),
                (r'.*/owhoami/?', OWhoAmIHandler),
                (r'.*/oauth_callback', HubOAuthCallbackHandler),
                (r'.*', EchoHandler),
            ],
            cookie_secret=os.urandom(32),
        )

        ssl_context = None
        key = os.environ.get('JUPYTERHUB_SSL_KEYFILE') or ''
        cert = os.environ.get('JUPYTERHUB_SSL_CERTFILE') or ''
        ca = os.environ.get('JUPYTERHUB_SSL_CLIENT_CA') or ''

        if key and cert and ca:
            ssl_context = make_ssl_context(key, cert, cafile=ca, check_hostname=False)

        server = httpserver.HTTPServer(app, ssl_options=ssl_context)
        server.listen(url.port, url.hostname)
    try:
        ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        print('\nInterrupted')
Ejemplo n.º 3
0
 def ssl_context(self):
     if self.keyfile and self.certfile and self.cafile:
         return make_ssl_context(self.keyfile,
                                 self.certfile,
                                 cafile=self.cafile,
                                 check_hostname=False)
     else:
         return None
Ejemplo n.º 4
0
def configure_http_client():
    keyfile = os.environ.get('JUPYTERHUB_SSL_KEYFILE', '')
    certfile = os.environ.get('JUPYTERHUB_SSL_CERTFILE', '')
    client_ca = os.environ.get('JUPYTERHUB_SSL_CLIENT_CA', '')

    if keyfile == '' and certfile == '' and client_ca == '':
        return

    ssl_context = make_ssl_context(keyfile, certfile, cafile=client_ca)
    httpclient.AsyncHTTPClient.configure(None,
                                         defaults={"ssl_options": ssl_context})
Ejemplo n.º 5
0
    async def poll(self):
        """Poll the spawned process to see if it is still running and reachable

        If the process is still running, and we can connect to the remote
        singleuser server over the tunnel, we return None. If it is not
        running, or unreachable we return the exit code of the process if we
        have access to it, or 0 otherwise.
        """

        status = await super().poll()

        if status is not None:
            return status
        elif not os.path.exists(self.ssh_socket):
            # tunnel is closed or non-existent
            return 0
        else:
            protocol = "http" if not self.user.settings["internal_ssl"] \
                       else "https"
            url = "{protocol}://{ip}:{port}".format(
                        protocol=protocol,
                        ip=(self.ip or '127.0.0.1'),
                        port=self.port
                  )
            key = self.user.settings.get('internal_ssl_key')
            cert = self.user.settings.get('internal_ssl_cert')
            ca = self.user.settings.get('internal_ssl_ca')
            ctx = make_ssl_context(key, cert, cafile=ca)
            try:
                reachable = await wait_for_http_server(url, ssl_context=ctx)
            except Exception as e:
                if isinstance(e, TimeoutError):
                    e.reason = 'timeout'
                    self.log.warning(
                        "Unable to reach {user}'s server for 10 seconds. "
                        "Giving up: {err}".format(
                            user=self.user.name,
                            err=e
                        ),
                    )
                    return 1
                else:
                    e.reason = 'error'
                    self.log.warning(
                        "Error reaching {user}'s server: {err}".format(
                            user=self.user.name,
                            err=e
                        )
                    )
                    return 2
            else:
                return None if reachable else 0
Ejemplo n.º 6
0
    async def poll(self):
        """Poll the spawned process to see if it is still running and reachable

        If the process is still running, and we can connect to the remote
        singleuser server over the tunnel, we return None. If it is not
        running, or unreachable we return the exit code of the process if we
        have access to it, or 0 otherwise.
        """
        status = await super().poll()

        if status is not None:
            if status == 255 and not self._stopping:
                self._stopping = True
                await self.stop()
            return status
        elif not os.path.exists(self.ssh_socket) and not self._started:
            # tunnel is closed or non-existent
            return 0
        else:
            if self.user.settings["internal_ssl"]:
                protocol = "https"
                key = self.user.settings.get("internal_ssl_key")
                cert = self.user.settings.get("internal_ssl_cert")
                ca = self.user.settings.get("internal_ssl_ca")
                ctx = make_ssl_context(key, cert, cafile=ca)
            else:
                protocol = "http"
                ctx = None
            ip = self.ip or "127.0.0.1"
            url = f"{protocol}://{ip}:{self.port}"
            try:
                reachable = await wait_for_http_server(url, ssl_context=ctx)
            except Exception as e:
                if isinstance(e, TimeoutError):
                    e.reason = "timeout"
                    self.log.warning(
                        f"Unable to reach {self.user.name}'s server for 10 seconds. "
                        f"Giving up: {e}", )
                    return 1
                else:
                    e.reason = "error"
                    self.log.warning(
                        f"Error reaching {self.user.name}'s server: {e}")
                    return 2
            else:
                return None if reachable else 0
    async def start(self):
        """Start the whole thing.
           Overridden to make service.start() asynchronous."""

        self.io_loop = loop = IOLoop.current()

        if self.subapp:
            self.subapp.start()
            loop.stop()
            return

        if self.generate_config:
            self.write_config_file()
            loop.stop()
            return

        if self.generate_certs:
            self.load_config_file(self.config_file)
            if not self.internal_ssl:
                self.log.warning(
                    "You'll need to enable `internal_ssl` "
                    "in the `jupyterhub_config` file to use "
                    "these certs."
                )
                self.internal_ssl = True
            self.init_internal_ssl()
            self.log.info(
                "Certificates written to directory `{}`".format(
                    self.internal_certs_location
                )
            )
            loop.stop()
            return

        # start the proxy
        if self.proxy.should_start:
            try:
                await self.proxy.start()
            except Exception:
                self.log.critical("Failed to start proxy", exc_info=True)
                self.exit(1)
        else:
            self.log.info("Not starting proxy")

        # verify that we can talk to the proxy before listening.
        # avoids delayed failure if we can't talk to the proxy
        await self.proxy.get_all_routes()

        ssl_context = make_ssl_context(
            self.internal_ssl_key,
            self.internal_ssl_cert,
            cafile=self.internal_ssl_ca,
            check_hostname=False,
        )

        # start the webserver
        self.http_server = tornado.httpserver.HTTPServer(
            self.tornado_application,
            ssl_options=ssl_context,
            xheaders=True,
            trusted_downstream=self.trusted_downstream_ips,
        )
        bind_url = urlparse(self.hub.bind_url)
        try:
            if bind_url.scheme.startswith('unix+'):
                from tornado.netutil import bind_unix_socket

                socket = bind_unix_socket(unquote(bind_url.netloc))
                self.http_server.add_socket(socket)
            else:
                ip = bind_url.hostname
                port = bind_url.port
                if not port:
                    if bind_url.scheme == 'https':
                        port = 443
                    else:
                        port = 80
                self.http_server.listen(port, address=ip)
            self.log.info("Hub API listening on %s", self.hub.bind_url)
            if self.hub.url != self.hub.bind_url:
                self.log.info("Private Hub API connect url %s", self.hub.url)
        except Exception:
            self.log.error("Failed to bind hub to %s", self.hub.bind_url)
            raise

        # start the service(s)
        for service_name, service in self._service_map.items():
            msg = (
                '%s at %s' % (service_name, service.url)
                if service.url
                else service_name
            )
            if service.managed:
                self.log.info("Starting managed service %s", msg)
                try:
                    await service.start()
                except Exception:
                    self.log.critical(
                        "Failed to start service %s", service_name, exc_info=True
                    )
                    self.exit(1)
            else:
                self.log.info("Adding external service %s", msg)

            if service.url:
                tries = 10 if service.managed else 1
                for i in range(tries):
                    try:
                        ssl_context = make_ssl_context(
                            self.internal_ssl_key,
                            self.internal_ssl_cert,
                            cafile=self.internal_ssl_ca,
                        )
                        await Server.from_orm(service.orm.server).wait_up(
                            http=True, timeout=1, ssl_context=ssl_context
                        )
                    except TimeoutError:
                        if service.managed:
                            status = await service.spawner.poll()
                            if status is not None:
                                self.log.error(
                                    "Service %s exited with status %s",
                                    service_name,
                                    status,
                                )
                                break
                    else:
                        break
                else:
                    self.log.error(
                        "Cannot connect to %s service %s at %s. Is it running?",
                        service.kind,
                        service_name,
                        service.url,
                    )

        await self.proxy.check_routes(self.users, self._service_map)

        if self.service_check_interval and any(
            s.url for s in self._service_map.values()
        ):
            pc = PeriodicCallback(
                self.check_services_health, 1e3 * self.service_check_interval
            )
            pc.start()

        if self.last_activity_interval:
            pc = PeriodicCallback(
                self.update_last_activity, 1e3 * self.last_activity_interval
            )
            self.last_activity_callback = pc
            pc.start()

        self.log.info("JupyterHub is now running at %s", self.proxy.public_url)
        # Use atexit for Windows, it doesn't have signal handling support
        if os.name == "nt":
            atexit.register(self.atexit)
        # register cleanup on both TERM and INT
        self.init_signal()
        self._start_future.set_result(None)