예제 #1
0
def public_url(app, user_or_service=None, path=''):
    """Return the full, public base URL (including prefix) of the given JupyterHub instance."""
    if user_or_service:
        if app.subdomain_host:
            host = user_or_service.host
        else:
            host = public_host(app)
        prefix = user_or_service.prefix
    else:
        host = public_host(app)
        prefix = Server.from_url(app.proxy.public_url).base_url
    if path:
        return host + ujoin(prefix, path)
    else:
        return host + prefix
예제 #2
0
    def start(self):
        # start tensorboard
        yield self.start_tb_proxy()

        public_server = Server.from_url(self.public_url)
        api_server = Server.from_url(self.api_url)
        env = os.environ.copy()
        env['CONFIGPROXY_AUTH_TOKEN'] = self.auth_token
        cmd = self.command + [
            '--ip',
            public_server.ip,
            '--port',
            str(public_server.port),
            '--api-ip',
            api_server.ip,
            '--api-port',
            str(api_server.port),
            '--error-target',
            url_path_join(self.hub.url, 'error'),
        ]
        if self.app.subdomain_host:
            cmd.append('--host-routing')
        if self.debug:
            cmd.extend(['--log-level', 'debug'])
        if self.ssl_key:
            cmd.extend(['--ssl-key', self.ssl_key])
        if self.ssl_cert:
            cmd.extend(['--ssl-cert', self.ssl_cert])
        if self.app.statsd_host:
            cmd.extend([
                '--statsd-host', self.app.statsd_host, '--statsd-port',
                str(self.app.statsd_port), '--statsd-prefix',
                self.app.statsd_prefix + '.chp'
            ])
        # Warn if SSL is not used
        if ' --ssl' not in ' '.join(cmd):
            self.log.warning(
                "Running JupyterHub without SSL."
                "  I hope there is SSL termination happening somewhere else..."
            )
        self.log.info("Starting proxy @ %s", public_server.bind_url)
        self.log.debug("Proxy cmd: %s", cmd)
        shell = os.name == 'nt'
        try:
            self.proxy_process = Popen(cmd,
                                       env=env,
                                       start_new_session=True,
                                       shell=shell)
        except FileNotFoundError as e:
            self.log.error(
                "Failed to find proxy %r\n"
                "The proxy can be installed with `npm install -g configurable-http-proxy`"
                % self.command)
            raise

        def _check_process():
            status = self.proxy_process.poll()
            if status is not None:
                e = RuntimeError("Proxy failed to start with exit code %i" %
                                 status)
                # py2-compatible `raise e from None`
                e.__cause__ = None
                raise e

        for server in (public_server, api_server):
            for i in range(10):
                _check_process()
                try:
                    yield server.wait_up(1)
                except TimeoutError:
                    continue
                else:
                    break
            yield server.wait_up(1)
        _check_process()
        self.log.debug("Proxy started and appears to be up")
        pc = PeriodicCallback(self.check_running,
                              1e3 * self.check_running_interval)
        pc.start()
예제 #3
0
def public_host(app):
    """Return the public *host* (no URL prefix) of the given JupyterHub instance."""
    if app.subdomain_host:
        return app.subdomain_host
    else:
        return Server.from_url(app.proxy.public_url).host
예제 #4
0
def public_host(app):
    """Return the public *host* (no URL prefix) of the given JupyterHub instance."""
    if app.subdomain_host:
        return app.subdomain_host
    else:
        return Server.from_url(app.proxy.public_url).host
def test_ip_port(ip, port, attrs):
    s = Server(ip=ip, port=port, base_url='/x/')
    for attr, value in attrs.items():
        assert getattr(s, attr) == value
def test_bind_url(bind_url, attrs):
    s = Server(bind_url=bind_url, base_url='/x/')
    for attr, value in attrs.items():
        assert getattr(s, attr) == value
예제 #7
0
 def start(self):
     self.server = Server.from_url("http://127.0.0.1:%i" %
                                   randint(1025, 65535))
예제 #8
0
    async def check_routes(self, user_dict, service_dict, routes=None):
        """Check that all users are properly routed on the proxy."""
        start = time.perf_counter()  # timer starts here when user is created
        for user in user_dict.values():
            if user.authenticator.multiple_instances:
                await user.authenticator.update_mem(user,
                                                    "Proxy - check_routes")
        if not routes:
            self.log.debug("Fetching routes to check")
            routes = await self.get_all_routes()
        # log info-level that we are starting the route-checking
        # this may help diagnose performance issues,
        # as we are about
        self.log.debug("Checking routes")
        user_routes = {
            path
            for path, r in routes.items() if 'user' in r['data']
        }
        futures = []

        good_routes = {self.app.hub.routespec}

        hub = self.hub
        if self.app.hub.routespec not in routes:
            futures.append(self.add_hub_route(hub))
        else:
            route = routes[self.app.hub.routespec]
            if route['target'] != hub.host:
                self.log.warning("Updating default route %s → %s",
                                 route['target'], hub.host)
                futures.append(self.add_hub_route(hub))
        for user in user_dict.values():
            for name, spawner in user.spawners.items():
                if spawner.ready:
                    spec = spawner.proxy_spec
                    good_routes.add(spec)
                    if spec not in user_routes:
                        self.log.warning("Adding missing route for %s (%s)",
                                         spec, spawner.server)
                        futures.append(self.add_user(user, name))
                    else:
                        route = routes[spec]
                        if route['target'] != spawner.server.host:
                            self.log.warning(
                                "Updating route for %s (%s → %s)",
                                spec,
                                route['target'],
                                spawner.server,
                            )
                            futures.append(self.add_user(user, name))
                elif spawner.pending:
                    # don't consider routes stale if the spawner is in any pending event
                    # wait until after the pending state clears before taking any actions
                    # they could be pending deletion from the proxy!
                    good_routes.add(spawner.proxy_spec)

        # check service routes
        service_routes = {
            r['data']['service']: r
            for r in routes.values() if 'service' in r['data']
        }
        for service in service_dict.values():
            if service.server is None:
                continue
            good_routes.add(service.proxy_spec)
            if service.name not in service_routes:
                self.log.warning("Adding missing route for %s (%s)",
                                 service.name, service.server)
                futures.append(self.add_service(service))
            else:
                route = service_routes[service.name]
                if route['target'] != service.server.host:
                    self.log.warning(
                        "Updating route for %s (%s → %s)",
                        route['routespec'],
                        route['target'],
                        service.server.host,
                    )
                    futures.append(self.add_service(service))

        # Now delete the routes that shouldn't be there
        for routespec in routes:
            if routespec not in good_routes:
                route_as_list = list(filter(None, routespec.split('/')))
                route_user = None
                route_servername = None
                spawn_skip = False
                try:
                    #self.log.debug("Route as List: {}".format(route_as_list))
                    if route_as_list[0] == 'integration':
                        if route_as_list[1] == 'hub':
                            if route_as_list[2] == 'api':
                                if route_as_list[3] in [
                                        'cancel', 'jobstatus', 'token',
                                        'uxnotification'
                                ]:
                                    route_user = route_as_list[4]
                                    route_servername = route_as_list[5]
                                elif route_as_list[3] == 'users':
                                    route_user = route_as_list[4]
                                    route_servername = route_as_list[6]
                            elif route_as_list[
                                    2] == 'spawn-pending' or route_as_list[
                                        2] == 'spawn':
                                route_user = route_as_list[3]
                                route_servername = route_as_list[4]
                                spawn_skip = True
                        elif route_as_list[1] in ['user', 'spawn']:
                            route_user = route_as_list[2]
                            route_servername = route_as_list[3]
                            try:
                                # skip /tree and /lab , that's the routes we want to deny for dashboards
                                if route_as_list[1] == 'user' and route_as_list[
                                        4] not in ['lab', 'tree']:
                                    spawn_skip = True
                            except:
                                spawn_skip = True
                    else:
                        if route_as_list[0] == 'hub':
                            if route_as_list[1] == 'api':
                                if route_as_list[2] in [
                                        'cancel', 'jobstatus', 'token',
                                        'uxnotification'
                                ]:
                                    route_user = route_as_list[3]
                                    route_servername = route_as_list[4]
                                elif route_as_list[2] == 'users':
                                    route_user = route_as_list[3]
                                    route_servername = route_as_list[5]
                            elif route_as_list[
                                    1] == 'spawn-pending' or route_as_list[
                                        1] == 'spawn':
                                route_user = route_as_list[2]
                                route_servername = route_as_list[3]
                                spawn_skip = True
                        elif route_as_list[0] in ['user', 'spawn']:
                            route_user = route_as_list[1]
                            route_servername = route_as_list[2]
                            try:
                                # skip /tree and /lab , that's the routes we want to deny for dashboards
                                if route_as_list[0] == 'user' and route_as_list[
                                        4] not in ['lab', 'tree']:
                                    spawn_skip = True
                            except:
                                spawn_skip = True
                except:
                    self.log.debug("Err: {}".format(traceback.format_exc()))
                    route_user = None
                    route_servername = None
                    pass
                delete = False
                db_spawner = None
                if route_user:
                    db_user = self.db.query(
                        orm.User).filter(orm.User.name == route_user).first()
                    if db_user:
                        self.db.refresh(db_user)
                        db_spawner = self.db.query(orm.Spawner).filter(
                            orm.Spawner.user_id == db_user.id).filter(
                                orm.Spawner.name == route_servername).first()
                        if db_spawner:
                            self.db.refresh(db_spawner)
                        if (not spawn_skip) and (not db_spawner
                                                 or not db_spawner.server_id):
                            delete = True
                    else:
                        delete = True
                else:
                    delete = True
                if delete:
                    self.log.debug("Deleting stale route %s", routespec)
                    futures.append(self.delete_route(routespec))
                else:
                    if db_spawner:
                        db_server = self.db.query(orm.Server).filter(
                            orm.Server.id == db_spawner.server_id).first()
                        if db_server:
                            self.db.refresh(db_server)
                        if route_user and user_dict.get(
                                route_user) and db_server:
                            self.log.debug("Add Server to memory spawner %s",
                                           routespec)
                            user_dict.get(route_user).spawners[
                                db_spawner.name].server = Server(
                                    orm_server=db_server)
        await gen.multi(futures)
        stop = time.perf_counter()  # timer stops here when user is deleted
        CHECK_ROUTES_DURATION_SECONDS.observe(stop - start)  # histogram metric