Initial version.

(c) Copyright IBM Corp. 2016
This commit is contained in:
Justin Tyberg 2016-04-14 15:00:15 -04:00
parent e974a8f0b9
commit 73163c76b9
15 changed files with 604 additions and 63 deletions

5
.dockerignore Normal file
View File

@ -0,0 +1,5 @@
.git
.gitignore
examples/
internal/
README.md

27
.env Normal file
View File

@ -0,0 +1,27 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# Use this file to set default values for environment variables specified in
# docker-compose configuration file. docker-compose will substitute these
# values for environment variables in the configuration file IF the variables
# are not set in the shell environment.
# To override these values, set the shell environment variables.
# Name of Docker machine
DOCKER_MACHINE_NAME=jupyterhub
# Name of Docker network
DOCKER_NETWORK_NAME=jupyterhub-network
# Single-user Jupyter Notebook server container image
DOCKER_CONTAINER_IMAGE=jupyter/scipy-notebook:2d878db5cbff
# Docker run command to use when spawning single-user containers
DOCKER_SPAWN_CMD=start-singleuser.sh
# Name of JupyterHub container data volume
DATA_VOLUME_HOST=jupyterhub-data
# Data volume container mount point
DATA_VOLUME_CONTAINER=/data

65
.gitignore vendored
View File

@ -1,62 +1,3 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#Ipython Notebook
.ipynb_checkpoints
secrets/
userlist
.DS_Store

19
Dockerfile.jupyterhub Normal file
View File

@ -0,0 +1,19 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
FROM jupyter/jupyterhub:master
# Install dockerspawner and its dependencies
RUN /opt/conda/bin/pip install \
-e git+https://github.com/jupyter/jupyterhub@62a5e9dbce86cbb8992def81600ff9881d515935#egg=jupyterhub \
-e git+https://github.com/jupyter/oauthenticator@011f6ea25c6bafca087d94a6c73d24dcbb0bf80e#egg=oauthenticator \
-e git+https://github.com/jupyter/dockerspawner@3c5e36bc96a252a04bb7700fdb009bd572996f3a#egg=dockerspawner
# Copy TLS certificate and key
ENV SSL_CERT /srv/jupyterhub/secrets/jupyterhub.cer
ENV SSL_KEY /srv/jupyterhub/secrets/jupyterhub.key
COPY ./secrets/*.cer $SSL_CERT
COPY ./secrets/*.key $SSL_KEY
RUN chmod 700 /srv/jupyterhub/secrets && \
chmod 600 /srv/jupyterhub/secrets/*
COPY ./userlist /srv/jupyterhub/userlist

151
README.md
View File

@ -1,2 +1,151 @@
# jupyterhub-deploy-docker
Reference deployment of JupyterHub with docker
This repository provides a reference deployment of [JupyterHub](https://github.com/jupyter/jupyterhub), a multi-user [Jupyter Notebook](http://jupyter.org/) environment, on a **single host** using [Docker](https://docs.docker.com).
This deployment:
* Runs the [JupyterHub components](https://jupyterhub.readthedocs.org/en/latest/getting-started.html#overview) in a Docker container on the host
* Uses [DockerSpawner](https://github.com/jupyter/dockerspawner) to spawn single-user Jupyter Notebook servers in separate Docker containers on the same host
* Persists JupyterHub data in a Docker volume on the host
* Persists user notebook directories in Docker volumes on the host
* Uses [OAuthenticator](https://github.com/jupyter/oauthenticator) and [GitHub OAuth](https://developer.github.com/v3/oauth/) to authenticate users
![JupyterHub single host Docker deployment](internal/jupyterhub-docker.png)
## Use Cases
Possible use cases for this deployment may include, but are not limited to:
* A JupyterHub demo environment that you can spin up relatively quickly.
* A multi-user Jupyter Notebook environment for small classes, teams, or departments.
## Disclaimer
This deployment is **NOT** intended for a production environment.
## Prerequisites
* This deployment uses Docker for all the things. It assumes that you wiil be using [Docker Machine](https://docs.docker.com/machine/overview/) and [Docker Compose](https://docs.docker.com/compose/overview/) on a local workstation or laptop to create, build, and run Docker images on a remote host. It requires [Docker Toolbox](https://www.docker.com/products/docker-toolbox) 1.11.0 or higher. See the [installation instructions](https://docs.docker.com/engine/installation/) for your environment.
* This example configures JupyterHub for HTTPS connections (the default). As such, you must provide TLS certificate chain and key files to the JupyterHub server. If you do not have your own certificate chain and key, you can either create self-signed versions, or obtain real ones from [Let's Encrypt](https://letsencrypt.org) (see the [letsencrypt example](examples/letsencrypt/README.md) for instructions).
## Create a Docker Machine
Use [Docker Machine](https://docs.docker.com/machine/) to provision a new host, or to connect to an existing one.
This example assumes that a remote host already exists at IP address `10.0.0.10`, and that you can perform password-less login to this host from your local workstation or laptop using a private SSH key.
To create a Docker machine that will install and configure the Docker daemon on an existing host (note that Docker Machine will upgrade the Docker daemon on the host if it is already installed):
```
# Use the generic driver to create a Docker machine that
# controls the Docker daemon on an existing host
export DRIVER_OPTS="--driver generic \
--generic-ip-address 10.0.0.10 \
--generic-ssh-key /path/to/private/ssh/key"
# Create a machine named jupyterhub
docker-machine create $DRIVER_OPTS jupyterhub
# Activate the machine
eval "$(docker-machine env jupyterhub)"
```
Docker Machine can also provision new hosts using one of it's [supported drivers](https://docs.docker.com/machine/drivers/). When provisioning a host, Docker Machine will automatically generate TLS certificate and key files and use them to authenticate with the remote Docker daemon.
## Create a Docker Network
Create a Docker network for inter-container communication. The benefits of using a Docker network are:
* container isolation - only the containers on the network can access one another
* name resolution - Docker daemon runs an embedded DNS server to provide automatic service discovery for containers connected to user-defined networks. This allows us to access containers on the same network by name.
Here we create a Docker network named `jupyterhub-network`. Later, we will configure the JupyterHub and single-user Jupyter Notebook containers to run attached to this network.
```
docker network create jupyterhub-network
```
## Setup GitHub Authentication
This deployment uses GitHub OAuth to authenticate users. It requires that you create a [GitHub application](https://github.com/settings/applications/new). You will need to specify an OAuth callback URL in the following form:
```
https://<myhost.mydomain>/hub/oauth_callback
```
You must pass the secrets that GitHub provides for your application to JupyterHub at runtime. You can do this by setting the `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, and `OAUTH_CALLBACK_URL` environment variables when you run the JupyterHub container, or you can add them to the `.env` file in the root directory of this repository. For example,
```
GITHUB_CLIENT_ID=<github_client_id>
GITHUB_CLIENT_SECRET=<github_client_secret>
OAUTH_CALLBACK_URL=https://<myhost.mydomain>/hub/oauth_callback
```
## Build the JupyterHub Docker image
Configure JupyterHub and build it into a Docker image.
1. Copy your TLS certificate and key to a directory named `secrets` within this repository directory. These will be added to the Docker image at build time.
```
mkdir -p secrets
cp jupyterhub.cer jupyterhub.key secrets/
```
1. Create a `userlist` file with a list of authorized users. At a minimum, this file should contain a single admin user. The username should be a GitHub username. For example:
```
jtyberg admin
```
The admin user will have the ability to add more users in the JupyterHub admin console.
1. Build the JupyterHub Docker image. For convenience, this repo provides a `hub.sh` script that wraps [docker-compose](https://docs.docker.com/compose/reference/), so you can run it with the docker-compose [command line arguments](https://docs.docker.com/compose/reference/overview/). To build the JupyterHub image on the active Docker machine host, run:
```
./hub.sh build
```
## Create a JupyterHub Data Volume
Create a Docker volume to persist JupyterHub data. This volume will reside on the host machine. Using a volume allows user lists, cookies, etc., to persist across JupyterHub container restarts.
```
docker volume create --name jupyterhub-data
```
## Pull the Jupyter Notebook Image
Pull the Jupyter Notebook Docker image that you would like JupyterHub to spawn for each user.
Note: Even though Docker will pull the image to the host the first time a user container is spawned, JupyterHub may timeout if the image is large, so it's better to do it beforehand.
This deployment uses the [jupyter/scipy-notebook](https://hub.docker.com/r/jupyter/scipy-notebook/) Docker image, which is built from the `scipy-notebook` [Docker stacks](https://github.com/jupyter/docker-stacks).
Note that the Docker stacks `*-notebook` images tagged `2d878db5cbff` include the `start-singleuser.sh` script required to start a single-user instance of the Notebook server that is compatible with JupyterHub.
```
docker pull jupyter/scipy-notebook:2d878db5cbff
```
## Run the JupyterHub container
Run the JupyterHub container on the host.
To run the JupyterHub container in detached mode:
```
./hub.sh up -d
```
Once the container is running, you should be able to navigate to the JupyterHub console at
```
https://myhost.mydomain
```
To bring down the JupyterHub container:
```
./hub.sh down
```

52
docker-compose.yml Normal file
View File

@ -0,0 +1,52 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# JupyterHub docker-compose configuration file
version: "2"
services:
hub:
build:
context: .
dockerfile: Dockerfile.jupyterhub
image: jupyterhub
container_name: jupyterhub
volumes:
# Bind Docker binary from host machine so we can invoke Docker commands
# from inside container
- "/usr/local/bin/docker:/usr/local/bin/docker:ro"
# Bind Docker TLS certs from host machine so we can authenticate with the
# daemon on the host (DOCKER_HOST should be set to host's IP)
- "/etc/docker:/etc/docker:ro"
# Bind Docker volume on host for JupyterHub database and cookie secrets
- "data:${DATA_VOLUME_CONTAINER}"
ports:
- "443:443"
environment:
# Pass DOCKER_HOST to container to allow it to connect to daemon on host
DOCKER_HOST: ${DOCKER_HOST}
# Locations of TLS certificate and key needed to auth with daemon on host
DOCKER_TLS_CERT: "/etc/docker/server.pem"
DOCKER_TLS_KEY: "/etc/docker/server-key.pem"
# All containers will join this network
DOCKER_NETWORK_NAME: ${DOCKER_NETWORK_NAME}
# JupyterHub will spawn this image for users
DOCKER_CONTAINER_IMAGE: ${DOCKER_CONTAINER_IMAGE}
# Using this run command (optional)
DOCKER_SPAWN_CMD: ${DOCKER_SPAWN_CMD}
# Required to authenticate users using GitHub OAuth
GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET}
OAUTH_CALLBACK_URL: ${OAUTH_CALLBACK_URL}
command: >
jupyterhub -f /srv/jupyterhub/jupyterhub_config.py
volumes:
data:
external:
name: ${DATA_VOLUME_HOST}
networks:
default:
external:
name: ${DOCKER_NETWORK_NAME}

View File

@ -0,0 +1,21 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# Pin to version of notebook image that includes start-singleuser.sh script
FROM jupyter/scipy-notebook:2d878db5cbff
# Install packages in default Python 3 environment
RUN pip install \
beautifulsoup4==4.4.*
# Install packages in Python 2 environment
RUN $CONDA_DIR/envs/python2/bin/pip install \
beautifulsoup4==4.4.*
# Use custom startup script
USER root
COPY docker-entrypoint.sh /srv/docker-entrypoint.sh
ENTRYPOINT ["tini", "--", "/srv/docker-entrypoint.sh"]
CMD ["start-singleuser.sh"]
USER jovyan

View File

@ -0,0 +1,28 @@
# Custom Jupyter Notebook Server Image
This is an example of using a custom Jupyter Notebook server Docker image with JupyterHub. The `Dockerfile` builds from the `jupyter/scipy-notebook` image, but customizes the image in the following ways:
* installs an additional Python package to make it available to notebooks
* uses a custom entrypoint script that copies sample notebooks to the user's notebook directory before executing the run command that was provided to the container
## Build the Image
Build and tag the image using the `Dockerfile` in this directory.
```
docker build -t my-custom-notebook .
```
## Run JupyterHub Container
To have JupyterHub spawn the `my-custom-notebook` image for single-user Notebook servers, set the `DOCKER_CONTAINER_IMAGE` environment variable to the image name when you run the JupyterHub container. For example, run the following **from the root directory** of this repository:
```
export DOCKER_CONTAINER_IMAGE=my-custom-notebook
# bring down the JupyterHub container, if running
./hub.sh down
# bring it back up
./hub.sh up -d
```

View File

@ -0,0 +1,20 @@
#!/bin/bash
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
set -e
# If the run command is the default, do some initialization first
if [ "$(which "$1")" = "/usr/local/bin/start-singleuser.sh" ]; then
# Clone sample notebooks to user's notebook directory. Assume $NB_USER's work
# directory if notebook directory not explicitly set. `git clone` will fail
# if target directory already exists and is not empty, which likely means
# that we've already done it, so just ignore.
: ${NOTEBOOK_DIR:=/home/$NB_USER/work}
git clone https://gist.github.com/parente/facb555dfbae28e817e0 \
--depth 1 \
"$NOTEBOOK_DIR/notebook_count" || true
fi
# Run the command provided
exec "$@"

View File

@ -0,0 +1,47 @@
# Let's Encrypt
This example includes a Docker Compose configuration file that you can use to deploy [JupyterHub](https://github.com/jupyter/jupyterhub) with TLS certificate and key files generated by [Let's Encrypt](https://letsencrypt.org).
The `docker-compose.yml` configuration file in this example extends the JupyterHub service defined in the `docker-compose.yml` file in the root directory of this repository.
When you run the JupyterHub Docker container using the configuration file in this directory, Docker mounts an additional volume containing the Let's Encrypt TLS certificate and key files, and overrides the `SSL_CERT` and `SSL_KEY` environment variables to point to these files.
## Create a secrets volume
This example stores the Let's Encrypt TLS certificate and key files in a Docker volume, and mounts the volume to the JupyterHub container at runtime.
Create a volume to store the certificate and key files.
```
# Activate Docker machine where JupyterHub will run
eval "$(docker-machine env jupyterhub)"
docker volume create --name jupyterhub-secrets
```
## Generate Let's Encrypt certificate and key
Run the `letsencrypt.sh` script to create a TLS full-chain certificate and key.
The script downloads and runs the `letsencrypt` Docker image to create a full-chain certificate and private key, and stores the files in a Docker volume. You must provide a valid, routable, fully-qualified domain name (you must own it), and you must activate the Docker machine host that the domain points to before you run this script. You must also provide a valid email address and the name of the volume you created above.
_Notes:_ The script hard codes several `letsencrypt` options, one of which automatically agrees to the Let's Encrypt Terms of Service.
```
# Activate Docker machine where JupyterHub will run
eval "$(docker-machine env jupyterhub)"
./letsencrypt.sh \
--domain myhost.mydomain \
--email me@mydomain \
--volume jupyterhub-secrets
```
## Run JupyterHub container
To run the JupyterHub container using the configuration in this directory, run the `hub.sh` script **from the root directory** of this repository and specify the `docker-compose.yml` file in this directory. Set the `SECRETS_VOLUME` environment variable to the name of the Docker volume containing the TLS certificate and key files.
```
SECRETS_VOLUME=jupyterhub-secrets \
./hub.sh -f examples/letsencrypt/docker-compose.yml up -d
```

View File

@ -0,0 +1,38 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# JupyterHub docker-compose configuration that uses Let's Encrypt TLS
# certificate and key.
# Extends the JupyterHub configuration in the root directory of this repository.
# Mounts an additional secrets volume that stores the Let's Encrypt TLS
# certificate and key files, and overrides the `SSL_CERT` and `SSL_KEY`
# environment variables to point to these files.
version: "2"
services:
hub:
extends: # hub service in repository root directory
file: ../../docker-compose.yml
service: hub
volumes:
- "secrets:/etc/letsencrypt"
environment:
SSL_KEY: "/etc/letsencrypt/privkey.pem"
SSL_CERT: "/etc/letsencrypt/cert.pem"
# Explicitly declare volume and network dependencies
# (they cannot be extended)
volumes:
data:
external:
name: ${DATA_VOLUME_HOST}
secrets:
external:
name: ${SECRETS_VOLUME}
networks:
default:
external:
name: ${DOCKER_NETWORK_NAME}

View File

@ -0,0 +1,84 @@
#!/bin/bash
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# Wrapper script that runs https://letsencrypt.org Docker container to generate
# a certificate for a single domain and store it in a Docker volume.
set -e
USAGE="
Usage: `basename $0` --domain FQDN --email EMAIL --volume SECRETS_VOLUME
[--staging]
"
while [[ $# > 0 ]]
do
key="$1"
case $key in
--domain)
FQDN="$2"
shift # past argument
;;
--email)
EMAIL="$2"
shift # past argument
;;
--volume)
SECRETS_VOLUME="$2"
shift # past argument
;;
--staging)
CERT_SERVER=--staging
;;
*) # unknown option
;;
esac
shift # past argument or value
done
if [ -z "${FQDN:+x}" ]; then
echo "ERROR: Must provide --domain option or set FQDN environment varable"
echo "$USAGE" && exit 1
fi
if [ -z "${EMAIL:+x}" ]; then
echo "ERROR: Must provide --email option set EMAIL environment varable"
echo "$USAGE" && exit 1
fi
if [ -z "${SECRETS_VOLUME:+x}" ]; then
echo "ERROR: Must provide --volume option or set SECRETS_VOLUME environment varable"
echo "$USAGE" && exit 1
fi
# letsencrypt certificate server type (default is production).
# Set `CERT_SERVER=--staging` for staging.
: ${CERT_SERVER=''}
# Generate the cert and save it to the Docker volume
docker run --rm -it \
-p 80:80 \
-v $SECRETS_VOLUME:/etc/letsencrypt \
quay.io/letsencrypt/letsencrypt:latest \
certonly \
--non-interactive \
--keep-until-expiring \
--standalone \
--standalone-supported-challenges http-01 \
--agree-tos \
--force-renewal \
--domain "$FQDN" \
--email "$EMAIL" \
$CERT_SERVER
# Set permissions so nobody can read the cert and key.
# Also symlink the certs into the root of the /etc/letsencrypt
# directory so that the FQDN doesn't have to be known later.
docker run --rm -it \
-v $SECRETS_VOLUME:/etc/letsencrypt \
--entrypoint=/bin/bash \
quay.io/letsencrypt/letsencrypt:latest \
-c "find /etc/letsencrypt/* -maxdepth 1 -type l -delete && \
ln -s /etc/letsencrypt/live/$FQDN/* /etc/letsencrypt/ && \
find /etc/letsencrypt -type d -exec chmod 755 {} +"

29
hub.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# Wrapper script around docker-compose
set -e
for i in "$@" ; do
if [[ "$i" == "up" ]]; then
# Check for required environment variables on startup
if [ -z ${GITHUB_CLIENT_ID:+x} ]; then
echo "ERROR: Must set GITHUB_CLIENT_ID environment variable"; exit 1;
fi
if [ -z ${GITHUB_CLIENT_SECRET:+x} ]; then
echo "ERROR: Must set GITHUB_CLIENT_SECRET environment variable"; exit 1;
fi
if [ -z ${OAUTH_CALLBACK_URL:+x} ]; then
echo "ERROR: Must set OAUTH_CALLBACK_URL environment variable"; exit 1;
fi
# Set DOCKER_HOST to daemon of target machine
DOCKER_MACHINE_URL=$(docker-machine url $(docker-machine active))
# Strip the protocol from the url
DOCKER_HOST="${DOCKER_MACHINE_URL#*//*}"
fi
done
exec docker-compose "$@"

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

81
jupyterhub_config.py Normal file
View File

@ -0,0 +1,81 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
# Configuration file for JupyterHub
import os
c = get_config()
# We rely on environment variables to configure JupyterHub so that we
# avoid having to rebuild the JupyterHub container every time we change a
# configuration parameter.
# Spawn single-user servers as Docker containers
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
# Spawn containers from this image
c.DockerSpawner.container_image = os.environ['DOCKER_CONTAINER_IMAGE']
# JupyterHub requires a single-user instance of the Notebook server, so we
# default to using the `start-singleuser.sh` script included in the
# jupyter/docker-stacks *-notebook images as the Docker run command when
# spawning containers. Optionally, you can override the Docker run command
# using the DOCKER_SPAWN_CMD environment variable.
spawn_cmd = os.environ.get('DOCKER_SPAWN_CMD', "start-singleuser.sh")
c.DockerSpawner.extra_create_kwargs.update({ 'command': spawn_cmd })
# Connect containers to this Docker network
network_name = os.environ['DOCKER_NETWORK_NAME']
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.network_name = network_name
# Pass the network name as argument to spawned containers
c.DockerSpawner.extra_host_config = { 'network_mode': network_name }
c.DockerSpawner.extra_start_kwargs = { 'network_mode': network_name }
# Explicitly set notebook directory because we'll be mounting a host volume to
# it. Most jupyter/docker-stacks *-notebook images run the Notebook server as
# user `jovyan`, and set the notebook directory to `/home/jovyan/work`.
# We follow the same convention.
c.DockerSpawner.notebook_dir = '/home/jovyan/work'
# Mount the real user's Docker volume on the host to the notebook user's
# notebook directory in the container
c.DockerSpawner.volumes = { '{username}': '/home/jovyan/work' }
c.DockerSpawner.extra_create_kwargs.update({ 'volume_driver': 'local' })
# Remove containers once they are stopped
c.DockerSpawner.remove_containers = True
# Specify paths to TLS certificate and key used to authenticate to Docker
# daemon at DOCKER_HOST
c.DockerSpawner.tls_cert = os.environ['DOCKER_TLS_CERT']
c.DockerSpawner.tls_key = os.environ['DOCKER_TLS_KEY']
# For debugging arguments passed to spawned containers
c.DockerSpawner.debug = True
# User containers will access hub by container name on the Docker network
c.JupyterHub.hub_ip = 'jupyterhub'
c.JupyterHub.hub_port = 8080
# TLS config
c.JupyterHub.port = 443
c.JupyterHub.ssl_key = os.environ['SSL_KEY']
c.JupyterHub.ssl_cert = os.environ['SSL_CERT']
# Authenticate users with GitHub OAuth
c.JupyterHub.authenticator_class = 'oauthenticator.GitHubOAuthenticator'
c.GitHubOAuthenticator.oauth_callback_url = os.environ['OAUTH_CALLBACK_URL']
# Persist hub data on volume mounted inside container
data_dir = os.environ.get('DATA_VOLUME_CONTAINER', '/data')
c.JupyterHub.db_url = os.path.join('sqlite:///', data_dir, 'jupyterhub.sqlite')
c.JupyterHub.cookie_secret_file = os.path.join(data_dir,
'jupyterhub_cookie_secret')
# Whitlelist users and admins
c.Authenticator.whitelist = whitelist = set()
c.Authenticator.admin_users = admin = set()
c.JupyterHub.admin_access = True
pwd = os.path.dirname(__file__)
with open(os.path.join(pwd, 'userlist')) as f:
for line in f:
if not line:
continue
parts = line.split()
name = parts[0]
whitelist.add(name)
if len(parts) > 1 and parts[1] == 'admin':
admin.add(name)