How to create a JupyterLab instance in JupyterHub that isn't associated with an authenticated user?

I’m trying to make “rooms” that users get routed into. The “rooms” are pre-launched instances of JupyterLab. I am able to programmatically spawn the instances and I am able to programmatically configure the CHP in order to route requests the newly spawned instances; however the instances that I spawn are unable to communicate with the Hub presumably because they have not completed the OAuth with the Hub.

Anyhow, I am wondering if there is an approach to spawning JupyterLab instances that aren’t necessarily owned by a single user. In other words, I would like to spawn JupyterLab instances that have URLs like this: “https://example.org/user/the-name-of-the-room/lab?

My first question is: how programmatically do you want/need to launch them? If encoding them in jupyterhub configuration (i.e. they don’t change often) is satisfactory, I think the way to do it is via singleuser servers as a service. These use all the same auth and are the same server as

For example, the config:

c.JupyterHub.load_groups = {group_name: ['ellisonbg', 'willingc']}

# start the notebook server as a service
c.JupyterHub.services = [
    {
        'name': service_name,
        'url': f'http://127.0.0.1:{service_port}',
        'command': ['jupyterhub-singleuser', '--debug'],
    }
]

# This "role assignment" is what grants members of the group
# access to the service
c.JupyterHub.load_roles = [
    {
        "name": "shared-notebook",
        "groups": [group_name],
        "scopes": [f"access:services!service={service_name}"],
    },
]

does 3 things:

  1. create a service that runs jupyterhub-singleuser (this will automatically work with jupyterhub service auth, meaning any user with access:service!service=:name will have access to it)
  2. grant a group
  3. populate that group

If you repeat that in your config with one server, role, and group for each collection of users that should be assigned to a room, you will have servers at https://example.org/services/:service-name/lab that each group of users will have access to. You can do this with a for-loop through groups of users:


service_port = 10101
for room_name, user_list in room_dict.items():
    service_port += 1
    c.JupyterHub.load_groups.update({room_name: user_list})
    c.JupyterHub.services.append({
        'name': room_name,
        'url': f'http://127.0.0.1:{service_port}',
        'command': ['jupyterhub-singleuser', '--debug'],
    })
    c.JupyterHub.load_roles.append({
        "name": f"room-{room_name}",
        "groups": [room_name],
        "scopes": [f"access:services!service={room_name}"],
    }

(you can skip creating the groups and assign permissions directly to users in the role - this fine if you don’t need group membership to be mutable. Groups can change at runtime, roles and role assignments cannot.)

The example also shows how that config differs if the services are externally managed (e.g. in their own containers/pods).

3 Likes

This looks like what I am trying to do. I’m really grateful for the guidance. I look forward to trying to implement this soon - I will report back on how it goes. Thank you.

1 Like

I got it to work. Thank you very much for your guidance. I will post more on the details of how I got it to work with Fargate when I get time. Thank you.

1 Like

@adpatter do you use EKS with Fargate?
I’m trying to do so, but it seams that the scheduled doesn’t know how to communicate with the EKS cluster to request a fargate node.

Warning FailedScheduling 3m20s default-scheduler 0/1 nodes are available: 1 node(s) didn’t match Pod’s node affinity/selector