Compare commits

..

4 Commits

Author SHA1 Message Date
Min RK
e94f5e043a release 0.9.3 2018-09-12 09:46:02 +02:00
Min RK
5456fb6356 remove spurious print from keepalive code
and send keepalive every 8 seconds

to protect against possibly aggressive proxies dropping connections after 10 seconds of inactivity
2018-09-12 09:46:02 +02:00
Min RK
fb75b9a392 write needs no await 2018-09-11 16:42:29 +02:00
Min RK
90d341e6f7 changelog for 0.9.3
Mainly small fixes, but the token page could be completely broken

This release will include the spawner.handler addition,
but not the oauthlib change currently in master
2018-09-11 16:42:21 +02:00
219 changed files with 5339 additions and 13225 deletions

View File

@@ -19,57 +19,3 @@ jobs:
name: smoke test jupyterhub
command: |
docker run --rm -it jupyterhub/jupyterhub jupyterhub --help
docs:
# This is the base environment that Circle will use
docker:
- image: circleci/python:3.6-stretch
steps:
# Get our data and merge with upstream
- run: sudo apt-get update
- checkout
# Update our path
- run: echo "export PATH=~/.local/bin:$PATH" >> $BASH_ENV
# Restore cached files to speed things up
- restore_cache:
keys:
- cache-pip
# Install the packages needed to build our documentation
- run:
name: Install NodeJS
command: |
# From https://github.com/nodesource/distributions/blob/master/README.md#debinstall
curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash -
sudo apt-get install -y nodejs
- run:
name: Install dependencies
command: |
python3 -m pip install --user -r dev-requirements.txt
python3 -m pip install --user -r docs/requirements.txt
sudo npm install -g configurable-http-proxy
sudo python3 -m pip install --editable .
# Cache some files for a speedup in subsequent builds
- save_cache:
key: cache-pip
paths:
- ~/.cache/pip
# Build the docs
- run:
name: Build docs to store
command: |
cd docs
make html
# Tell Circle to store the documentation output in a folder that we can access later
- store_artifacts:
path: docs/build/html/
destination: html
# Tell CircleCI to use this workflow when it builds the site
workflows:
version: 2
default:
jobs:
- build
- docs

View File

@@ -1,5 +1,4 @@
[run]
parallel = True
branch = False
omit =
jupyterhub/tests/*

View File

@@ -10,12 +10,13 @@
# E402: module level import not at top of file
# I100: Import statements are in the wrong order
# I101: Imported names are in the wrong order. Should be
ignore = E, C, W, F401, F403, F811, F841, E402, I100, I101, D400
builtins = c, get_config
ignore = E, C, W, F401, F403, F811, F841, E402, I100, I101
exclude =
.cache,
.github,
docs,
examples,
jupyterhub/alembic*,
onbuild,
scripts,

View File

@@ -1,39 +1,37 @@
---
name: Issue report
name: Bug report
about: Create a report to help us improve
---
<!---
Hi! Thanks for using JupyterHub.
If you are reporting an issue with JupyterHub, please use the GitHub search feature to check if your issue has been asked already. If it has, please add your comments to the existing issue.
Some tips:
- Running `jupyter troubleshoot` from the command line, if possible, and posting
its output would also be helpful.
- Running JupyterHub in `--debug` mode (`jupyterhub --debug`) can also be helpful for troubleshooting.
--->
If you are reporting an issue with JupyterHub, please use the [GitHub issue](https://github.com/jupyterhub/jupyterhub/issues) search feature to check if your issue has been asked already. If it has, please add your comments to the existing issue.
**Describe the bug**
A clear and concise description of what the bug is.
<!---Add description here--->
**To Reproduce**
<!---
Please share the steps to reproduce the behavior:
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
--->
**Expected behavior**
<!---
A clear and concise description of what you expected to happen.
--->
**Compute Information**
- Operating System
- JupyterHub Version [e.g. 22]
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
- Running `jupyter troubleshoot` from the command line, if possible, and posting
its output would also be helpful.
- Running in `--debug` mode can also be helpful for troubleshooting.

View File

@@ -1,22 +1,7 @@
---
name: Installation and configuration questions
name: Installation and configuration issues
about: Installation and configuration assistance
---
<!---
If you are reading this message, you have probably already searched the existing
GitHub issues for JupyterHub. If you haven't tried a search, we encourage you to do so.
If you are unsure where to ask your question (Jupyter, JupyterHub, JupyterLab, etc.),
please ask on our [Discourse Q&A channel](https://discourse.jupyter.org/c/questions).
If you have a quick question about JupyterHub installation or configuratation, you
may ask on the [JupyterHub gitter channel](https://gitter.im/jupyterhub/jupyterhub).
:sunny: Please be patient. We are volunteers and will address your question when we are able. :sunny:
If after trying the above steps, you still have an in-depth installation or
configuration question, such as a possible bug, please file an issue below and include
any relevant details.
--->
If you are having issues with installation or configuration, you may ask for help on the JupyterHub gitter channel or file an issue here.

2
.gitignore vendored
View File

@@ -21,8 +21,6 @@ share/jupyterhub/static/css/style.min.css.map
*.egg-info
MANIFEST
.coverage
.coverage.*
htmlcov
.idea/
.pytest_cache
pip-wheel-metadata

View File

@@ -1,20 +0,0 @@
repos:
- repo: https://github.com/asottile/reorder_python_imports
rev: v1.8.0
hooks:
- id: reorder-python-imports
language_version: python3.6
- repo: https://github.com/ambv/black
rev: 19.10b0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
- id: end-of-file-fixer
- id: check-json
- id: check-yaml
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: requirements-txt-fixer
- id: flake8

View File

@@ -8,15 +8,15 @@ python:
- nightly
env:
global:
- ASYNC_TEST_TIMEOUT=15
- MYSQL_HOST=127.0.0.1
- MYSQL_TCP_PORT=13306
services:
- postgresql
- postgres
- docker
# installing dependencies
before_install:
- set -e
- nvm install 6; nvm use 6
- npm install
- npm install -g configurable-http-proxy
@@ -26,61 +26,34 @@ before_install:
unset MYSQL_UNIX_PORT
DB=mysql bash ci/docker-db.sh
DB=mysql bash ci/init-db.sh
# FIXME: mysql-connector-python 8.0.16 incorrectly decodes bytes to str
# ref: https://bugs.mysql.com/bug.php?id=94944
pip install 'mysql-connector-python==8.0.11'
pip install 'mysql-connector<2.2'
elif [[ $JUPYTERHUB_TEST_DB_URL == postgresql* ]]; then
psql -c "CREATE USER $PGUSER WITH PASSWORD '$PGPASSWORD';" -U postgres
DB=postgres bash ci/init-db.sh
pip install psycopg2-binary
fi
install:
- pip install --upgrade pip
- pip install --upgrade --pre -r dev-requirements.txt .
- pip install --pre -r dev-requirements.txt .
- pip freeze
# running tests
script:
- |
# run tests
if [[ -z "$TEST" ]]; then
pytest -v --maxfail=2 --cov=jupyterhub jupyterhub/tests
fi
- |
# run autoformat
if [[ "$TEST" == "lint" ]]; then
pre-commit run --all-files
fi
set -e
pytest -v --maxfail=2 --cov=jupyterhub jupyterhub/tests
- |
# build docs
if [[ "$TEST" == "docs" ]]; then
pushd docs
pip install --upgrade -r requirements.txt
pip install --upgrade alabaster_jupyterhub
make html
popd
fi
pushd docs
pip install -r requirements.txt
make html
popd
after_success:
- codecov
after_failure:
- |
# point to auto-lint-fix
if [[ "$TEST" == "lint" ]]; then
echo "You can install pre-commit hooks to automatically run formatting"
echo "on each commit with:"
echo " pre-commit install"
echo "or you can run by hand on staged files with"
echo " pre-commit run"
echo "or after-the-fact on already committed files with"
echo " pre-commit run --all-files"
fi
matrix:
fast_finish: true
include:
- python: 3.6
env: TEST=lint
- python: 3.6
env: TEST=docs
- python: 3.6
env: JUPYTERHUB_TEST_SUBDOMAIN_HOST=http://localhost.jovyan.org:8000
- python: 3.6
@@ -88,13 +61,8 @@ matrix:
- JUPYTERHUB_TEST_DB_URL=mysql+mysqlconnector://root@127.0.0.1:$MYSQL_TCP_PORT/jupyterhub
- python: 3.6
env:
- PGUSER=jupyterhub
- PGPASSWORD=hub[test/:?
# password in url is url-encoded (urllib.parse.quote($PGPASSWORD, safe=''))
- JUPYTERHUB_TEST_DB_URL=postgresql://jupyterhub:hub%5Btest%2F%3A%3F@127.0.0.1/jupyterhub
- JUPYTERHUB_TEST_DB_URL=postgresql://postgres@127.0.0.1/jupyterhub
- python: 3.7
dist: xenial
- python: 3.8
if: tag IS present
allow_failures:
- python: nightly

View File

@@ -1,131 +1,98 @@
# Contributing to JupyterHub
# Contributing
Welcome! As a [Jupyter](https://jupyter.org) project,
you can follow the [Jupyter contributor guide](https://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html).
Make sure to also follow [Project Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md)
for a friendly and welcoming collaborative environment.
## Setting up a development environment
JupyterHub requires Python >= 3.5 and nodejs.
As a Python project, a development install of JupyterHub follows standard practices for the basics (steps 1-2).
Welcome! As a [Jupyter](https://jupyter.org) project, we follow the [Jupyter contributor guide](https://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html).
1. clone the repo
```bash
git clone https://github.com/jupyterhub/jupyterhub
```
2. do a development install with pip
## Set up your development system
```bash
cd jupyterhub
python3 -m pip install --editable .
```
3. install the development requirements,
which include things like testing tools
```bash
python3 -m pip install -r dev-requirements.txt
```
4. install configurable-http-proxy with npm:
```bash
npm install -g configurable-http-proxy
```
5. set up pre-commit hooks for automatic code formatting, etc.
```bash
pre-commit install
```
You can also invoke the pre-commit hook manually at any time with
```bash
pre-commit run
```
## Contributing
JupyterHub has adopted automatic code formatting so you shouldn't
need to worry too much about your code style.
As long as your code is valid,
the pre-commit hook should take care of how it should look.
You can invoke the pre-commit hook by hand at any time with:
For a development install, clone the [repository](https://github.com/jupyterhub/jupyterhub)
and then install from source:
```bash
pre-commit run
git clone https://github.com/jupyterhub/jupyterhub
cd jupyterhub
npm install -g configurable-http-proxy
pip3 install -r dev-requirements.txt -e .
```
which should run any autoformatting on your code
and tell you about any errors it couldn't fix automatically.
You may also install [black integration](https://github.com/ambv/black#editor-integration)
into your text editor to format code automatically.
### Troubleshooting a development install
If you have already committed files before setting up the pre-commit
hook with `pre-commit install`, you can fix everything up using
`pre-commit run --all-files`. You need to make the fixing commit
yourself after that.
If the `pip3 install` command fails and complains about `lessc` being
unavailable, you may need to explicitly install some additional JavaScript
dependencies:
## Testing
npm install
It's a good idea to write tests to exercise any new features,
or that trigger any bugs that you have fixed to catch regressions.
This will fetch client-side JavaScript dependencies necessary to compile CSS.
You can run the tests with:
You may also need to manually update JavaScript and CSS after some development
updates, with:
```bash
pytest -v
python3 setup.py js # fetch updated client-side js
python3 setup.py css # recompile CSS from LESS sources
```
in the repo directory. If you want to just run certain tests,
check out the [pytest docs](https://pytest.readthedocs.io/en/latest/usage.html)
for how pytest can be called.
For instance, to test only spawner-related things in the REST API:
## Running the test suite
We use [pytest](http://doc.pytest.org/en/latest/) for running tests.
1. Set up a development install as described above.
2. Set environment variable for `ASYNC_TEST_TIMEOUT` to 15 seconds:
```bash
pytest -v -k spawn jupyterhub/tests/test_api.py
export ASYNC_TEST_TIMEOUT=15
```
The tests live in `jupyterhub/tests` and are organized roughly into:
3. Run tests.
1. `test_api.py` tests the REST API
2. `test_pages.py` tests loading the HTML pages
To run all the tests:
and other collections of tests for different components.
When writing a new test, there should usually be a test of
similar functionality already written and related tests should
be added nearby.
```bash
pytest -v jupyterhub/tests
```
The fixtures live in `jupyterhub/tests/conftest.py`. There are
fixtures that can be used for JupyterHub components, such as:
To run an individual test file (i.e. `test_api.py`):
- `app`: an instance of JupyterHub with mocked parts
- `auth_state_enabled`: enables persisting auth_state (like authentication tokens)
- `db`: a sqlite in-memory DB session
- `io_loop`: a Tornado event loop
- `event_loop`: a new asyncio event loop
- `user`: creates a new temporary user
- `admin_user`: creates a new temporary admin user
- single user servers
- `cleanup_after`: allows cleanup of single user servers between tests
- mocked service
- `MockServiceSpawner`: a spawner that mocks services for testing with a short poll interval
- `mockservice`: mocked service with no external service url
- `mockservice_url`: mocked service with a url to test external services
```bash
pytest -v jupyterhub/tests/test_api.py
```
And fixtures to add functionality or spawning behavior:
### Troubleshooting tests
- `admin_access`: grants admin access
- `no_patience`: sets slow-spawning timeouts to zero
- `slow_spawn`: enables the SlowSpawner (a spawner that takes a few seconds to start)
- `never_spawn`: enables the NeverSpawner (a spawner that will never start)
- `bad_spawn`: enables the BadSpawner (a spawner that fails immediately)
- `slow_bad_spawn`: enables the SlowBadSpawner (a spawner that fails after a short delay)
If you see test failures because of timeouts, you may wish to increase the
`ASYNC_TEST_TIMEOUT` used by the
[pytest-tornado-plugin](https://github.com/eugeniy/pytest-tornado/blob/c79f68de2222eb7cf84edcfe28650ebf309a4d0c/README.rst#markers)
from the default of 5 seconds:
To read more about fixtures check out the
[pytest docs](https://docs.pytest.org/en/latest/fixture.html)
for how to use the existing fixtures, and how to create new ones.
```bash
export ASYNC_TEST_TIMEOUT=15
```
When in doubt, feel free to ask.
If you see many test errors and failures, double check that you have installed
`configurable-http-proxy`.
## Building the Docs locally
1. Install the development system as described above.
2. Install the dependencies for documentation:
```bash
python3 -m pip install -r docs/requirements.txt
```
3. Build the docs:
```bash
cd docs
make clean
make html
```
4. View the docs:
```bash
open build/html/index.html
```

View File

@@ -21,82 +21,40 @@
# your jupyterhub_config.py will be added automatically
# from your docker directory.
# https://github.com/tianon/docker-brew-ubuntu-core/commit/d4313e13366d24a97bd178db4450f63e221803f1
ARG BASE_IMAGE=ubuntu:bionic-20191029@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d
FROM $BASE_IMAGE AS builder
USER root
FROM ubuntu:18.04
LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
# install nodejs, utf8 locale, set CDN because default httpredir is unreliable
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& apt-get install -yq --no-install-recommends \
ca-certificates \
locales \
python3-dev \
python3-pip \
python3-pycurl \
nodejs \
npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get -y install wget git bzip2 && \
apt-get purge && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ENV LANG C.UTF-8
# copy only what we need to avoid unnecessary rebuilds
COPY package.json \
pyproject.toml \
README.md \
requirements.txt \
setup.py \
/src/jupyterhub/
COPY jupyterhub/ /src/jupyterhub/jupyterhub
COPY share/ /src/jupyterhub/share
# install Python + NodeJS with conda
RUN wget -q https://repo.continuum.io/miniconda/Miniconda3-4.5.1-Linux-x86_64.sh -O /tmp/miniconda.sh && \
echo '0c28787e3126238df24c5d4858bd0744 */tmp/miniconda.sh' | md5sum -c - && \
bash /tmp/miniconda.sh -f -b -p /opt/conda && \
/opt/conda/bin/conda install --yes -c conda-forge \
python=3.6 sqlalchemy tornado jinja2 traitlets requests pip pycurl \
nodejs configurable-http-proxy && \
/opt/conda/bin/pip install --upgrade pip && \
rm /tmp/miniconda.sh
ENV PATH=/opt/conda/bin:$PATH
ADD . /src/jupyterhub
WORKDIR /src/jupyterhub
RUN python3 -m pip install --upgrade setuptools pip wheel
RUN python3 -m pip wheel -v --wheel-dir wheelhouse .
FROM $BASE_IMAGE
USER root
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -yq --no-install-recommends \
ca-certificates \
curl \
gnupg \
locales \
python3-pip \
python3-pycurl \
nodejs \
npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV SHELL=/bin/bash \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8 \
LANGUAGE=en_US.UTF-8
RUN locale-gen $LC_ALL
# always make sure pip is up to date!
RUN python3 -m pip install --no-cache --upgrade setuptools pip
RUN npm install -g configurable-http-proxy@^4.2.0 \
&& rm -rf ~/.npm
# install the wheels we built in the first stage
COPY --from=builder /src/jupyterhub/wheelhouse /tmp/wheelhouse
RUN python3 -m pip install --no-cache /tmp/wheelhouse/*
RUN pip install . && \
rm -rf $PWD ~/.cache ~/.npm
RUN mkdir -p /srv/jupyterhub/
WORKDIR /srv/jupyterhub/
EXPOSE 8000
LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
LABEL org.jupyter.service="jupyterhub"
CMD ["jupyterhub"]

1
PULL_REQUEST_TEMPLATE.md Normal file
View File

@@ -0,0 +1 @@

View File

@@ -12,12 +12,11 @@
[![PyPI](https://img.shields.io/pypi/v/jupyterhub.svg)](https://pypi.python.org/pypi/jupyterhub)
[![Documentation Status](https://readthedocs.org/projects/jupyterhub/badge/?version=latest)](https://jupyterhub.readthedocs.org/en/latest/?badge=latest)
[![Documentation Status](http://readthedocs.org/projects/jupyterhub/badge/?version=0.7.2)](https://jupyterhub.readthedocs.io/en/0.7.2/?badge=0.7.2)
[![Build Status](https://travis-ci.org/jupyterhub/jupyterhub.svg?branch=master)](https://travis-ci.org/jupyterhub/jupyterhub)
[![Circle CI](https://circleci.com/gh/jupyterhub/jupyterhub.svg?style=shield&circle-token=b5b65862eb2617b9a8d39e79340b0a6b816da8cc)](https://circleci.com/gh/jupyterhub/jupyterhub)
[![codecov.io](https://codecov.io/github/jupyterhub/jupyterhub/coverage.svg?branch=master)](https://codecov.io/github/jupyterhub/jupyterhub?branch=master)
[![GitHub](https://img.shields.io/badge/issue_tracking-github-blue.svg)](https://github.com/jupyterhub/jupyterhub/issues)
[![Discourse](https://img.shields.io/badge/help_forum-discourse-blue.svg)](https://discourse.jupyter.org/c/jupyterhub)
[![Gitter](https://img.shields.io/badge/social_chat-gitter-blue.svg)](https://gitter.im/jupyterhub/jupyterhub)
[![Google Group](https://img.shields.io/badge/google-group-blue.svg)](https://groups.google.com/forum/#!forum/jupyter)
With [JupyterHub](https://jupyterhub.readthedocs.io) you can create a
**multi-user Hub** which spawns, manages, and proxies multiple instances of the
@@ -145,12 +144,12 @@ To start the Hub on a specific url and port ``10.0.1.2:443`` with **https**:
### Authenticators
| Authenticator | Description |
| ---------------------------------------------------------------------------- | ------------------------------------------------- |
| PAMAuthenticator | Default, built-in authenticator |
| [OAuthenticator](https://github.com/jupyterhub/oauthenticator) | OAuth + JupyterHub Authenticator = OAuthenticator |
| [ldapauthenticator](https://github.com/jupyterhub/ldapauthenticator) | Simple LDAP Authenticator Plugin for JupyterHub |
| [kerberosauthenticator](https://github.com/jupyterhub/kerberosauthenticator) | Kerberos Authenticator Plugin for JupyterHub |
| Authenticator | Description |
| --------------------------------------------------------------------------- | ------------------------------------------------- |
| PAMAuthenticator | Default, built-in authenticator |
| [OAuthenticator](https://github.com/jupyterhub/oauthenticator) | OAuth + JupyterHub Authenticator = OAuthenticator |
| [ldapauthenticator](https://github.com/jupyterhub/ldapauthenticator) | Simple LDAP Authenticator Plugin for JupyterHub |
| [kdcAuthenticator](https://github.com/bloomberg/jupyterhub-kdcauthenticator)| Kerberos Authenticator Plugin for JupyterHub |
### Spawners
@@ -162,7 +161,6 @@ To start the Hub on a specific url and port ``10.0.1.2:443`` with **https**:
| [sudospawner](https://github.com/jupyterhub/sudospawner) | Spawn single-user servers without being root |
| [systemdspawner](https://github.com/jupyterhub/systemdspawner) | Spawn single-user notebook servers using systemd |
| [batchspawner](https://github.com/jupyterhub/batchspawner) | Designed for clusters using batch scheduling software |
| [yarnspawner](https://github.com/jupyterhub/yarnspawner) | Spawn single-user notebook servers distributed on a Hadoop cluster |
| [wrapspawner](https://github.com/jupyterhub/wrapspawner) | WrapSpawner and ProfilesSpawner enabling runtime configuration of spawners |
## Docker
@@ -206,9 +204,6 @@ and the [`CONTRIBUTING.md`](CONTRIBUTING.md). The `CONTRIBUTING.md` file
explains how to set up a development installation, how to run the test suite,
and how to contribute to documentation.
For a high-level view of the vision and next directions of the project, see the
[JupyterHub community roadmap](docs/source/contributing/roadmap.md).
### A note about platform support
JupyterHub is supported on Linux/Unix based systems.
@@ -242,9 +237,6 @@ our JupyterHub [Gitter](https://gitter.im/jupyterhub/jupyterhub) channel.
- [Documentation for JupyterHub's REST API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/jupyterhub/master/docs/rest-api.yml#/default)
- [Documentation for Project Jupyter](http://jupyter.readthedocs.io/en/latest/index.html) | [PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)
- [Project Jupyter website](https://jupyter.org)
- [Project Jupyter community](https://jupyter.org/community)
JupyterHub follows the Jupyter [Community Guides](https://jupyter.readthedocs.io/en/latest/community/content-community.html).
---

View File

@@ -1,16 +1,19 @@
#!/usr/bin/env python
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
"""
bower-lite
Since Bower's on its way out,
stage frontend dependencies from node_modules into components
"""
import json
import os
import shutil
from os.path import join
import shutil
HERE = os.path.abspath(os.path.dirname(__file__))

View File

@@ -2,7 +2,7 @@
# source this file to setup postgres and mysql
# for local testing (as similar as possible to docker)
set -eu
set -e
export MYSQL_HOST=127.0.0.1
export MYSQL_TCP_PORT=${MYSQL_TCP_PORT:-13306}
@@ -40,15 +40,6 @@ for i in {1..60}; do
done
$CHECK
case "$DB" in
"mysql")
;;
"postgres")
# create the user
psql --user postgres -c "CREATE USER $PGUSER WITH PASSWORD '$PGPASSWORD';"
;;
*)
esac
echo -e "
Set these environment variables:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# initialize jupyterhub databases for testing
set -eu
set -e
MYSQL="mysql --user root --host $MYSQL_HOST --port $MYSQL_TCP_PORT -e "
PSQL="psql --user postgres -c "
@@ -21,7 +21,7 @@ esac
set -x
for SUFFIX in '' _upgrade_072 _upgrade_081 _upgrade_094; do
for SUFFIX in '' _upgrade_072 _upgrade_081; do
$SQL "DROP DATABASE jupyterhub${SUFFIX};" 2>/dev/null || true
$SQL "CREATE DATABASE jupyterhub${SUFFIX} ${EXTRA_CREATE:-};"
$SQL "CREATE DATABASE jupyterhub${SUFFIX} ${EXTRA_CREATE};"
done

View File

@@ -1,20 +1,14 @@
-r requirements.txt
mock
beautifulsoup4
codecov
cryptography
pytest-cov
pytest-tornado
pytest>=3.3
notebook
requests-mock
virtualenv
# temporary pin of attrs for jsonschema 0.3.0a1
# seems to be a pip bug
attrs>=17.4.0
beautifulsoup4
codecov
coverage
cryptography
html5lib # needed for beautifulsoup
mock
notebook
pre-commit
pytest-asyncio
pytest-cov
pytest>=3.3
requests-mock
# blacklist urllib3 releases affected by https://github.com/urllib3/urllib3/issues/1683
# I *think* this should only affect testing, not production
urllib3!=1.25.4,!=1.25.5
virtualenv

View File

@@ -7,3 +7,5 @@ ENV LANG=en_US.UTF-8
USER nobody
CMD ["jupyterhub"]

View File

@@ -12,9 +12,10 @@ Dockerfile.alpine contains base image for jupyterhub. It does not work independ
* start configurable-http-proxy in another container
* specify CONFIGPROXY_AUTH_TOKEN env in both containers
* put both containers on the same network (e.g. docker network create jupyterhub; docker run ... --net jupyterhub)
* put both containers on the same network (e.g. docker create network jupyterhub; docker run ... --net jupyterhub)
* tell jupyterhub where CHP is (e.g. c.ConfigurableHTTPProxy.api_url = 'http://chp:8001')
* tell jupyterhub not to start the proxy itself (c.ConfigurableHTTPProxy.should_start = False)
* Use dummy authenticator for ease of testing. Update following in jupyterhub_config file
- c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator'
- c.DummyAuthenticator.password = "your strong password"

View File

@@ -4,17 +4,19 @@ name: jhub_docs
channels:
- conda-forge
dependencies:
- pip
- nodejs
- python=3.6
- alembic
- jinja2
- pamela
- recommonmark==0.6.0
- requests
- sqlalchemy>=1
- tornado>=5.0
- traitlets>=4.1
- sphinx>=1.7
- pip:
- -r requirements.txt
- python-oauth2
- recommonmark==0.4.0
- async_generator
- prometheus_client
- attrs>=17.4.0

View File

@@ -1,10 +1,5 @@
# ReadTheDocs uses the `environment.yaml` so make sure to update that as well
# if you change this file
-r ../requirements.txt
alabaster_jupyterhub
autodoc-traits
git+https://github.com/pandas-dev/pandas-sphinx-theme.git@master
recommonmark==0.5.0
sphinx-copybutton
sphinx-jsonschema
sphinx>=1.7
recommonmark==0.4.0

View File

@@ -1,4 +1,4 @@
# see me at: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#/default
# see me at: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/jupyterhub/master/docs/rest-api.yml#/default
swagger: '2.0'
info:
title: JupyterHub
@@ -7,7 +7,7 @@ info:
license:
name: BSD-3-Clause
schemes:
[http, https]
- [http, https]
securityDefinitions:
token:
type: apiKey
@@ -89,7 +89,7 @@ paths:
post:
summary: Create multiple users
parameters:
- name: body
- name: data
in: body
required: true
schema:
@@ -147,7 +147,7 @@ paths:
in: path
required: true
type: string
- name: body
- name: data
in: body
required: true
description: Updated user info. At least one key to be updated (name or admin) is required.
@@ -176,63 +176,6 @@ paths:
responses:
'204':
description: The user has been deleted
/users/{name}/activity:
post:
summary:
Notify Hub of activity for a given user.
description:
Notify the Hub of activity by the user,
e.g. accessing a service or (more likely)
actively using a server.
parameters:
- name: name
description: username
in: path
required: true
type: string
- name: body
in: body
schema:
type: object
properties:
last_activity:
type: string
format: date-time
description: |
Timestamp of last-seen activity for this user.
Only needed if this is not activity associated
with using a given server.
servers:
description: |
Register activity for specific servers by name.
The keys of this dict are the names of servers.
The default server has an empty name ('').
type: object
properties:
'<server name>':
description: |
Activity for a single server.
type: object
required:
- last_activity
properties:
last_activity:
type: string
format: date-time
description: |
Timestamp of last-seen activity on this server.
example:
last_activity: '2019-02-06T12:54:14Z'
servers:
'':
last_activity: '2019-02-06T12:54:14Z'
gpu:
last_activity: '2019-02-06T12:54:14Z'
responses:
'401':
$ref: '#/responses/Unauthorized'
'404':
description: No such user
/users/{name}/server:
post:
summary: Start a user's single-user notebook server
@@ -242,16 +185,6 @@ paths:
in: path
required: true
type: string
- name: options
description: |
Spawn options can be passed as a JSON body
when spawning via the API instead of spawn form.
The structure of the options
will depend on the Spawner's configuration.
in: body
required: false
schema:
type: object
responses:
'201':
description: The user's notebook server has started
@@ -284,16 +217,6 @@ paths:
in: path
required: true
type: string
- name: options
description: |
Spawn options can be passed as a JSON body
when spawning via the API instead of spawn form.
The structure of the options
will depend on the Spawner's configuration.
in: body
required: false
schema:
type: object
responses:
'201':
description: The user's notebook named-server has started
@@ -312,26 +235,12 @@ paths:
in: path
required: true
type: string
- name: remove
description: |
Whether to fully remove the server, rather than just stop it.
Removing a server deletes things like the state of the stopped server.
in: body
required: false
schema:
type: boolean
responses:
'204':
description: The user's notebook named-server has stopped
'202':
description: The user's notebook named-server has not yet stopped as it is taking a while to stop
/users/{name}/tokens:
parameters:
- name: name
description: username
in: path
required: true
type: string
get:
summary: List tokens for the user
responses:
@@ -341,43 +250,25 @@ paths:
type: array
items:
$ref: '#/definitions/Token'
'401':
$ref: '#/responses/Unauthorized'
'404':
description: No such user
post:
summary: Create a new token for the user
parameters:
- name: token_params
in: body
- name: expires_in
type: number
required: false
schema:
type: object
properties:
expires_in:
type: number
description: lifetime (in seconds) after which the requested token will expire.
note:
type: string
description: A note attached to the token for future bookkeeping
in: body
description: lifetime (in seconds) after which the requested token will expire.
- name: note
type: string
required: false
in: body
description: A note attached to the token for future bookkeeping
responses:
'201':
description: The newly created token
schema:
$ref: '#/definitions/Token'
'400':
description: Body must be a JSON dict or empty
/users/{name}/tokens/{token_id}:
parameters:
- name: name
description: username
in: path
required: true
type: string
- name: token_id
in: path
required: true
type: string
get:
summary: Get the model for a token by id
responses:
@@ -391,13 +282,12 @@ paths:
'204':
description: The token has been deleted
/user:
get:
summary: Return authenticated user's model
responses:
'200':
description: The authenticated user's model is returned.
schema:
$ref: '#/definitions/User'
summary: Return authenticated user's model
description:
parameters:
responses:
'200':
description: The authenticated user's model is returned.
/groups:
get:
summary: List groups
@@ -455,7 +345,7 @@ paths:
in: path
required: true
type: string
- name: body
- name: data
in: body
required: true
description: The users to add to the group
@@ -480,7 +370,7 @@ paths:
in: path
required: true
type: string
- name: body
- name: data
in: body
required: true
description: The users to remove from the group
@@ -538,7 +428,7 @@ paths:
summary: Notify the Hub about a new proxy
description: Notifies the Hub of a new proxy to use.
parameters:
- name: body
- name: data
in: body
required: true
description: Any values that have changed for the new proxy. All keys are optional.
@@ -570,15 +460,14 @@ paths:
Logging in via this method is only available when the active Authenticator
accepts passwords (e.g. not OAuth).
parameters:
- name: credentials
- name: username
in: body
schema:
type: object
properties:
username:
type: string
password:
type: string
required: false
type: string
- name: password
in: body
required: false
type: string
responses:
'200':
description: The new API token
@@ -594,10 +483,10 @@ paths:
get:
summary: Identify a user or service from an API token
parameters:
- name: token
in: path
required: true
type: string
- name: token
in: path
required: true
type: string
responses:
'200':
description: The user or service identified by the API token
@@ -608,14 +497,14 @@ paths:
summary: Identify a user from a cookie
description: Used by single-user notebook servers to hand off cookie authentication to the Hub
parameters:
- name: cookie_name
in: path
required: true
type: string
- name: cookie_value
in: path
required: true
type: string
- name: cookie_name
in: path
required: true
type: string
- name: cookie_value
in: path
required: true
type: string
responses:
'200':
description: The user identified by the cookie
@@ -650,11 +539,6 @@ paths:
in: query
required: true
type: string
responses:
'200':
description: Success
'400':
description: OAuth2Error
/oauth2/token:
post:
summary: Request an OAuth2 token
@@ -666,27 +550,27 @@ paths:
parameters:
- name: client_id
description: The client id
in: formData
in: form
required: true
type: string
- name: client_secret
description: The client secret
in: formData
in: form
required: true
type: string
- name: grant_type
description: The grant type (always 'authorization_code')
in: formData
in: form
required: true
type: string
- name: code
description: The code provided by the authorization redirect
in: formData
in: form
required: true
type: string
- name: redirect_uri
description: The redirect url
in: formData
in: form
required: true
type: string
responses:
@@ -705,28 +589,14 @@ paths:
post:
summary: Shutdown the Hub
parameters:
- name: body
- name: proxy
in: body
schema:
type: object
properties:
proxy:
type: boolean
description: Whether the proxy should be shutdown as well (default from Hub config)
servers:
type: boolean
description: Whether users' notebook servers should be shutdown as well (default from Hub config)
responses:
'202':
description: Shutdown successful
'400':
description: Unexpeced value for proxy or servers
# Descriptions of common responses
responses:
NotFound:
description: The specified resource was not found
Unauthorized:
description: Authentication/Authorization error
type: boolean
description: Whether the proxy should be shutdown as well (default from Hub config)
- name: servers
in: body
type: boolean
description: Whether users' notebook servers should be shutdown as well (default from Hub config)
definitions:
User:
type: object
@@ -754,10 +624,11 @@ definitions:
format: date-time
description: Timestamp of last-seen activity from the user
servers:
type: array
type: object
description: The active servers for this user.
items:
$ref: '#/definitions/Server'
schema:
$ref: '#/definitions/Server'
Server:
type: object
properties:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,30 @@
{% extends '!page.html' %}
{# Custom template for page.html
Alabaster theme does not provide blocks for prev/next at bottom of each page.
This is _in addition_ to the prev/next in the sidebar. The "Prev/Next" text
or symbols are handled by CSS classes in _static/custom.css
#}
{% macro prev_next(prev, next, prev_title='', next_title='') %}
{%- if prev %}
<a class='left-prev' href="{{ prev.link|e }}" title="{{ _('previous chapter')}}">{{ prev_title or prev.title }}</a>
{%- endif %}
{%- if next %}
<a class='right-next' href="{{ next.link|e }}" title="{{ _('next chapter')}}">{{ next_title or next.title }}</a>
{%- endif %}
<div style='clear:both;'></div>
{% endmacro %}
{% block body %}
<div class='prev-next-top'>
{{ prev_next(prev, next, 'Previous', 'Next') }}
</div>
{{super()}}
<div class='prev-next-bottom'>
{{ prev_next(prev, next) }}
</div>
{% endblock %}

View File

@@ -1,159 +0,0 @@
.. _admin/upgrading:
====================
Upgrading JupyterHub
====================
JupyterHub offers easy upgrade pathways between minor versions. This
document describes how to do these upgrades.
If you are using :ref:`a JupyterHub distribution <index/distributions>`, you
should consult the distribution's documentation on how to upgrade. This
document is if you have set up your own JupyterHub without using a
distribution.
It is long because is pretty detailed! Most likely, upgrading
JupyterHub is painless, quick and with minimal user interruption.
Read the Changelog
==================
The `changelog <../changelog.html>`_ contains information on what has
changed with the new JupyterHub release, and any deprecation warnings.
Read these notes to familiarize yourself with the coming changes. There
might be new releases of authenticators & spawners you are using, so
read the changelogs for those too!
Notify your users
=================
If you are using the default configuration where ``configurable-http-proxy``
is managed by JupyterHub, your users will see service disruption during
the upgrade process. You should notify them, and pick a time to do the
upgrade where they will be least disrupted.
If you are using a different proxy, or running ``configurable-http-proxy``
independent of JupyterHub, your users will be able to continue using notebook
servers they had already launched, but will not be able to launch new servers
nor sign in.
Backup database & config
========================
Before doing an upgrade, it is critical to back up:
#. Your JupyterHub database (sqlite by default, or MySQL / Postgres
if you used those). If you are using sqlite (the default), you
should backup the ``jupyterhub.sqlite`` file.
#. Your ``jupyterhub_config.py`` file.
#. Your user's home directories. This is unlikely to be affected directly by
a JupyterHub upgrade, but we recommend a backup since user data is very
critical.
Shutdown JupyterHub
===================
Shutdown the JupyterHub process. This would vary depending on how you
have set up JupyterHub to run. Most likely, it is using a process
supervisor of some sort (``systemd`` or ``supervisord`` or even ``docker``).
Use the supervisor specific command to stop the JupyterHub process.
Upgrade JupyterHub packages
===========================
There are two environments where the ``jupyterhub`` package is installed:
#. The *hub environment*, which is where the JupyterHub server process
runs. This is started with the ``jupyterhub`` command, and is what
people generally think of as JupyterHub.
#. The *notebook user environments*. This is where the user notebook
servers are launched from, and is probably custom to your own
installation. This could be just one environment (different from the
hub environment) that is shared by all users, one environment
per user, or same environment as the hub environment. The hub
launched the ``jupyterhub-singleuser`` command in this environment,
which in turn starts the notebook server.
You need to make sure the version of the ``jupyterhub`` package matches
in both these environments. If you installed ``jupyterhub`` with pip,
you can upgrade it with:
.. code-block:: bash
python3 -m pip install --upgrade jupyterhub==<version>
Where ``<version>`` is the version of JupyterHub you are upgrading to.
If you used ``conda`` to install ``jupyterhub``, you should upgrade it
with:
.. code-block:: bash
conda install -c conda-forge jupyterhub==<version>
Where ``<version>`` is the version of JupyterHub you are upgrading to.
You should also check for new releases of the authenticator & spawner you
are using. You might wish to upgrade those packages too along with JupyterHub,
or upgrade them separately.
Upgrade JupyterHub database
===========================
Once new packages are installed, you need to upgrade the JupyterHub
database. From the hub environment, in the same directory as your
``jupyterhub_config.py`` file, you should run:
.. code-block:: bash
jupyterhub upgrade-db
This should find the location of your database, and run necessary upgrades
for it.
SQLite database disadvantages
-----------------------------
SQLite has some disadvantages when it comes to upgrading JupyterHub. These
are:
- ``upgrade-db`` may not work, and you may need delete your database
and start with a fresh one.
- ``downgrade-db`` **will not** work if you want to rollback to an
earlier version, so backup the ``jupyterhub.sqlite`` file before
upgrading
What happens if I delete my database?
-------------------------------------
Losing the Hub database is often not a big deal. Information that
resides only in the Hub database includes:
- active login tokens (user cookies, service tokens)
- users added via JupyterHub UI, instead of config files
- info about running servers
If the following conditions are true, you should be fine clearing the
Hub database and starting over:
- users specified in config file, or login using an external
authentication provider (Google, GitHub, LDAP, etc)
- user servers are stopped during upgrade
- don't mind causing users to login again after upgrade
Start JupyterHub
================
Once the database upgrade is completed, start the ``jupyterhub``
process again.
#. Log-in and start the server to make sure things work as
expected.
#. Check the logs for any errors or deprecation warnings. You
might have to update your ``jupyterhub_config.py`` file to
deal with any deprecated options.
Congratulations, your JupyterHub has been upgraded!

View File

@@ -13,3 +13,4 @@ Module: :mod:`jupyterhub.app`
-------------------
.. autoconfigurable:: JupyterHub

View File

@@ -26,7 +26,3 @@ Module: :mod:`jupyterhub.auth`
.. autoconfigurable:: PAMAuthenticator
:class:`DummyAuthenticator`
---------------------------
.. autoconfigurable:: DummyAuthenticator

View File

@@ -1,8 +1,8 @@
.. _api-index:
##############
JupyterHub API
##############
##################
The JupyterHub API
##################
:Release: |release|
:Date: |today|

View File

@@ -20,3 +20,4 @@ Module: :mod:`jupyterhub.proxy`
.. autoconfigurable:: ConfigurableHTTPProxy
:members: debug, auth_token, check_running_interval, api_url, command

View File

@@ -14,3 +14,4 @@ Module: :mod:`jupyterhub.services.service`
.. autoconfigurable:: Service
:members: name, admin, url, api_token, managed, kind, command, cwd, environment, user, oauth_client_id, server, prefix, proxy_spec

View File

@@ -38,3 +38,4 @@ Module: :mod:`jupyterhub.services.auth`
--------------------------------
.. autoclass:: HubOAuthCallbackHandler

View File

@@ -13,9 +13,10 @@ Module: :mod:`jupyterhub.spawner`
----------------
.. autoconfigurable:: Spawner
:members: options_from_form, poll, start, stop, get_args, get_env, get_state, template_namespace, format_string, create_certs, move_certs
:members: options_from_form, poll, start, stop, get_args, get_env, get_state, template_namespace, format_string
:class:`LocalProcessSpawner`
----------------------------
.. autoconfigurable:: LocalProcessSpawner

View File

@@ -34,3 +34,4 @@ Module: :mod:`jupyterhub.user`
.. attribute:: spawner
The user's :class:`~.Spawner` instance.

View File

@@ -7,295 +7,8 @@ command line for details.
## [Unreleased]
## 1.1
### [1.1.0b1] 2019-12-26
1.1 is a release with lots of accumulated fixes and improvements,
especially in performance, metrics, and customization.
There are no database changes in 1.1, so no database upgrade is required
when upgrading from 1.0 to 1.1.
Of particular interest to deployments with automatic health checking and/or large numbers of users is that the slow startup time
introduced in 1.0 by additional spawner validation can now be mitigated by `JupyterHub.init_spawners_timeout`,
allowing the Hub to become responsive before the spawners may have finished validating.
Several new Prometheus metrics are added (and others fixed!)
to measure sources of common performance issues,
such as proxy interactions and startup.
1.1 also begins adoption of the Jupyter telemetry project in JupyterHub,
See [The Jupyter Telemetry docs](https://jupyter-telemetry.readthedocs.io)
for more info. The only events so far are starting and stopping servers,
but more will be added in future releases.
There are many more fixes and improvements listed below.
Thanks to everyone who has contributed to this release!
#### New
- Add prometheus metric to measure hub startup time [#2799](https://github.com/jupyterhub/jupyterhub/pull/2799) ([@rajat404](https://github.com/rajat404))
- Add Spawner.auth_state_hook [#2555](https://github.com/jupyterhub/jupyterhub/pull/2555) ([@rcthomas](https://github.com/rcthomas))
- Link services from jupyterhub pages [#2763](https://github.com/jupyterhub/jupyterhub/pull/2763) ([@rcthomas](https://github.com/rcthomas))
- Add Spawner.auth_state_hook [#2555](https://github.com/jupyterhub/jupyterhub/pull/2555) ([@rcthomas](https://github.com/rcthomas))
- `JupyterHub.user_redirect_hook` is added to allow admins to customize /user-redirect/ behavior [#2790](https://github.com/jupyterhub/jupyterhub/pull/2790) ([@yuvipanda](https://github.com/yuvipanda))
- Add prometheus metric to measure hub startup time [#2799](https://github.com/jupyterhub/jupyterhub/pull/2799) ([@rajat404](https://github.com/rajat404))
- Add prometheus metric to measure proxy route poll times [#2798](https://github.com/jupyterhub/jupyterhub/pull/2798) ([@rajat404](https://github.com/rajat404))
- `PROXY_DELETE_DURATION_SECONDS` prometheus metric is added, to measure proxy route deletion times [#2788](https://github.com/jupyterhub/jupyterhub/pull/2788) ([@rajat404](https://github.com/rajat404))
- `Service.oauth_no_confirm` is added, it is useful for admin-managed services that are considered part of the Hub and shouldn't need to prompt the user for access [#2767](https://github.com/jupyterhub/jupyterhub/pull/2767) ([@minrk](https://github.com/minrk))
- `JupyterHub.default_server_name` is added to make the default server be a named server with provided name [#2735](https://github.com/jupyterhub/jupyterhub/pull/2735) ([@krinsman](https://github.com/krinsman))
- `JupyterHub.init_spawners_timeout` is introduced to combat slow startups on large JupyterHub deployments [#2721](https://github.com/jupyterhub/jupyterhub/pull/2721) ([@minrk](https://github.com/minrk))
- The configuration `uids` for local authenticators is added to consistently assign users UNIX id's between installations [#2687](https://github.com/jupyterhub/jupyterhub/pull/2687) ([@rgerkin](https://github.com/rgerkin))
- `JupyterHub.activity_resolution` is introduced with a default value of 30s improving performance by not updating the database with user activity too often [#2605](https://github.com/jupyterhub/jupyterhub/pull/2605) ([@minrk](https://github.com/minrk))
- [HubAuth](https://jupyterhub.readthedocs.io/en/stable/api/services.auth.html#jupyterhub.services.auth.HubAuth)'s SSL configuration can now be set through environment variables [#2588](https://github.com/jupyterhub/jupyterhub/pull/2588) ([@cmd-ntrf](https://github.com/cmd-ntrf))
- Expose spawner.user_options in REST API. [#2755](https://github.com/jupyterhub/jupyterhub/pull/2755) ([@danielballan](https://github.com/danielballan))
- add block for scripts included in head [#2828](https://github.com/jupyterhub/jupyterhub/pull/2828) ([@bitnik](https://github.com/bitnik))
- Instrument JupyterHub to record events with jupyter_telemetry [Part II] [#2698](https://github.com/jupyterhub/jupyterhub/pull/2698) ([@Zsailer](https://github.com/Zsailer))
- Make announcements visible without custom HTML [#2570](https://github.com/jupyterhub/jupyterhub/pull/2570) ([@consideRatio](https://github.com/consideRatio))
- Display server version on admin page [#2776](https://github.com/jupyterhub/jupyterhub/pull/2776) ([@vilhelmen](https://github.com/vilhelmen))
#### Fixes
- Cleanup if spawner stop fails [#2849](https://github.com/jupyterhub/jupyterhub/pull/2849) ([@gabber12](https://github.com/gabber12))
- Fix an issue occurring with the default spawner and `internal_ssl` enabled [#2785](https://github.com/jupyterhub/jupyterhub/pull/2785) ([@rpwagner](https://github.com/rpwagner))
- Fix named servers to not be spawnable unless activated [#2772](https://github.com/jupyterhub/jupyterhub/pull/2772) ([@bitnik](https://github.com/bitnik))
- JupyterHub now awaits proxy availability before accepting web requests [#2750](https://github.com/jupyterhub/jupyterhub/pull/2750) ([@minrk](https://github.com/minrk))
- Fix a no longer valid assumption that MySQL and MariaDB need to have `innodb_file_format` and `innodb_large_prefix` configured [#2712](https://github.com/jupyterhub/jupyterhub/pull/2712) ([@chicocvenancio](https://github.com/chicocvenancio))
- Login/Logout button now updates to Login on logout [#2705](https://github.com/jupyterhub/jupyterhub/pull/2705) ([@aar0nTw](https://github.com/aar0nTw))
- Fix handling of exceptions within `pre_spawn_start` hooks [#2684](https://github.com/jupyterhub/jupyterhub/pull/2684) ([@GeorgianaElena](https://github.com/GeorgianaElena))
- Fix an issue where a user could end up spawning a default server instead of a named server as intended [#2682](https://github.com/jupyterhub/jupyterhub/pull/2682) ([@rcthomas](https://github.com/rcthomas))
- /hub/admin now redirects to login if unauthenticated [#2670](https://github.com/jupyterhub/jupyterhub/pull/2670) ([@GeorgianaElena](https://github.com/GeorgianaElena))
- Fix spawning of users with names containing characters that needs to be escaped [#2648](https://github.com/jupyterhub/jupyterhub/pull/2648) ([@nicorikken](https://github.com/nicorikken))
- Fix `TOTAL_USERS` prometheus metric [#2637](https://github.com/jupyterhub/jupyterhub/pull/2637) ([@GeorgianaElena](https://github.com/GeorgianaElena))
- Fix `RUNNING_SERVERS` prometheus metric [#2629](https://github.com/jupyterhub/jupyterhub/pull/2629) ([@GeorgianaElena](https://github.com/GeorgianaElena))
- Fix faulty redirects to 404 that could occur with the use of named servers [#2594](https://github.com/jupyterhub/jupyterhub/pull/2594) ([@vilhelmen](https://github.com/vilhelmen))
- JupyterHub API spec is now a valid OpenAPI spec [#2590](https://github.com/jupyterhub/jupyterhub/pull/2590) ([@sbrunk](https://github.com/sbrunk))
- Use of `--help` or `--version` previously could output unrelated errors [#2584](https://github.com/jupyterhub/jupyterhub/pull/2584) ([@minrk](https://github.com/minrk))
- No longer crash on startup in Windows [#2560](https://github.com/jupyterhub/jupyterhub/pull/2560) ([@adelcast](https://github.com/adelcast))
- Escape usernames in the frontend [#2640](https://github.com/jupyterhub/jupyterhub/pull/2640) ([@nicorikken](https://github.com/nicorikken))
#### Maintenance
- chore: Dockerfile updates [#2853](https://github.com/jupyterhub/jupyterhub/pull/2853) ([@jgwerner](https://github.com/jgwerner))
- simplify Dockerfile [#2840](https://github.com/jupyterhub/jupyterhub/pull/2840) ([@minrk](https://github.com/minrk))
- docker: fix onbuild image arg [#2839](https://github.com/jupyterhub/jupyterhub/pull/2839) ([@minrk](https://github.com/minrk))
- remove redundant pip package list in docs environment.yml [#2838](https://github.com/jupyterhub/jupyterhub/pull/2838) ([@minrk](https://github.com/minrk))
- docs: Update docs to run tests [#2812](https://github.com/jupyterhub/jupyterhub/pull/2812) ([@jgwerner](https://github.com/jgwerner))
- remove redundant pip package list in docs environment.yml [#2838](https://github.com/jupyterhub/jupyterhub/pull/2838) ([@minrk](https://github.com/minrk))
- updating to pandas docs theme [#2820](https://github.com/jupyterhub/jupyterhub/pull/2820) ([@choldgraf](https://github.com/choldgraf))
- Adding institutional faq [#2800](https://github.com/jupyterhub/jupyterhub/pull/2800) ([@choldgraf](https://github.com/choldgraf))
- Add inline comment to test [#2826](https://github.com/jupyterhub/jupyterhub/pull/2826) ([@consideRatio](https://github.com/consideRatio))
- Raise error on missing specified config [#2824](https://github.com/jupyterhub/jupyterhub/pull/2824) ([@consideRatio](https://github.com/consideRatio))
- chore: Refactor Dockerfile [#2816](https://github.com/jupyterhub/jupyterhub/pull/2816) ([@jgwerner](https://github.com/jgwerner))
- chore: Update python versions in travis matrix [#2811](https://github.com/jupyterhub/jupyterhub/pull/2811) ([@jgwerner](https://github.com/jgwerner))
- chore: Bump package versions used in pre-commit config [#2810](https://github.com/jupyterhub/jupyterhub/pull/2810) ([@jgwerner](https://github.com/jgwerner))
- adding docs preview to circleci [#2803](https://github.com/jupyterhub/jupyterhub/pull/2803) ([@choldgraf](https://github.com/choldgraf))
- adding institutional faq [#2800](https://github.com/jupyterhub/jupyterhub/pull/2800) ([@choldgraf](https://github.com/choldgraf))
- The proxy's REST API listens on port `8001` [#2795](https://github.com/jupyterhub/jupyterhub/pull/2795) ([@bnuhero](https://github.com/bnuhero))
- cull_idle_servers.py: rebind max_age and inactive_limit locally [#2794](https://github.com/jupyterhub/jupyterhub/pull/2794) ([@rkdarst](https://github.com/rkdarst))
- Fix deprecation warnings [#2789](https://github.com/jupyterhub/jupyterhub/pull/2789) ([@tirkarthi](https://github.com/tirkarthi))
- Log proxy class [#2783](https://github.com/jupyterhub/jupyterhub/pull/2783) ([@GeorgianaElena](https://github.com/GeorgianaElena))
- Add docs for fixtures in CONTRIBUTING.md [#2782](https://github.com/jupyterhub/jupyterhub/pull/2782) ([@kinow](https://github.com/kinow))
- Fix header project name typo [#2775](https://github.com/jupyterhub/jupyterhub/pull/2775) ([@kinow](https://github.com/kinow))
- Remove unused setupegg.py [#2774](https://github.com/jupyterhub/jupyterhub/pull/2774) ([@kinow](https://github.com/kinow))
- Log JupyterHub version on startup [#2752](https://github.com/jupyterhub/jupyterhub/pull/2752) ([@consideRatio](https://github.com/consideRatio))
- Reduce verbosity for "Failing suspected API request to not-running server" (new) [#2751](https://github.com/jupyterhub/jupyterhub/pull/2751) ([@rkdarst](https://github.com/rkdarst))
- Add missing package for json schema doc build [#2744](https://github.com/jupyterhub/jupyterhub/pull/2744) ([@willingc](https://github.com/willingc))
- blacklist urllib3 versions with encoding bug [#2743](https://github.com/jupyterhub/jupyterhub/pull/2743) ([@minrk](https://github.com/minrk))
- Remove tornado deprecated/unnecessary AsyncIOMainLoop().install() call [#2740](https://github.com/jupyterhub/jupyterhub/pull/2740) ([@kinow](https://github.com/kinow))
- Fix deprecated call [#2739](https://github.com/jupyterhub/jupyterhub/pull/2739) ([@kinow](https://github.com/kinow))
- Remove duplicate hub and authenticator traitlets from Spawner [#2736](https://github.com/jupyterhub/jupyterhub/pull/2736) ([@eslavich](https://github.com/eslavich))
- Update issue template [#2725](https://github.com/jupyterhub/jupyterhub/pull/2725) ([@willingc](https://github.com/willingc))
- Use autodoc-traits sphinx extension [#2723](https://github.com/jupyterhub/jupyterhub/pull/2723) ([@willingc](https://github.com/willingc))
- Add New Server: change redirecting to relative to home page in js [#2714](https://github.com/jupyterhub/jupyterhub/pull/2714) ([@bitnik](https://github.com/bitnik))
- Create a warning when creating a service implicitly from service_tokens [#2704](https://github.com/jupyterhub/jupyterhub/pull/2704) ([@katsar0v](https://github.com/katsar0v))
- Fix mistypos [#2702](https://github.com/jupyterhub/jupyterhub/pull/2702) ([@rlukin](https://github.com/rlukin))
- Add Jupyter community link [#2696](https://github.com/jupyterhub/jupyterhub/pull/2696) ([@mattjshannon](https://github.com/mattjshannon))
- Fix failing travis tests [#2695](https://github.com/jupyterhub/jupyterhub/pull/2695) ([@GeorgianaElena](https://github.com/GeorgianaElena))
- Documentation update: hint for using services instead of service tokens. [#2679](https://github.com/jupyterhub/jupyterhub/pull/2679) ([@katsar0v](https://github.com/katsar0v))
- Replace header logo: jupyter -> jupyterhub [#2672](https://github.com/jupyterhub/jupyterhub/pull/2672) ([@consideRatio](https://github.com/consideRatio))
- Update spawn-form example [#2662](https://github.com/jupyterhub/jupyterhub/pull/2662) ([@kinow](https://github.com/kinow))
- Update flask hub authentication services example in doc [#2658](https://github.com/jupyterhub/jupyterhub/pull/2658) ([@cmd-ntrf](https://github.com/cmd-ntrf))
- close `<div class="container">` tag in home.html [#2649](https://github.com/jupyterhub/jupyterhub/pull/2649) ([@bitnik](https://github.com/bitnik))
- Some theme updates; no double NEXT/PREV buttons. [#2647](https://github.com/jupyterhub/jupyterhub/pull/2647) ([@Carreau](https://github.com/Carreau))
- fix typos on technical reference documentation [#2646](https://github.com/jupyterhub/jupyterhub/pull/2646) ([@ilee38](https://github.com/ilee38))
- Update links for Hadoop-related subprojects [#2645](https://github.com/jupyterhub/jupyterhub/pull/2645) ([@jcrist](https://github.com/jcrist))
- corrected docker network create instructions in dockerfiles README [#2632](https://github.com/jupyterhub/jupyterhub/pull/2632) ([@bartolone](https://github.com/bartolone))
- Fixed docs and testing code to use refactored SimpleLocalProcessSpawner [#2631](https://github.com/jupyterhub/jupyterhub/pull/2631) ([@danlester](https://github.com/danlester))
- Update the config used for testing [#2628](https://github.com/jupyterhub/jupyterhub/pull/2628) ([@jtpio](https://github.com/jtpio))
- Update doc: do not suggest depricated config key [#2626](https://github.com/jupyterhub/jupyterhub/pull/2626) ([@lumbric](https://github.com/lumbric))
- Add missing words [#2625](https://github.com/jupyterhub/jupyterhub/pull/2625) ([@remram44](https://github.com/remram44))
- cull-idle: Include a hint on how to add custom culling logic [#2613](https://github.com/jupyterhub/jupyterhub/pull/2613) ([@rkdarst](https://github.com/rkdarst))
- Replace existing redirect code by Tornado's addslash decorator [#2609](https://github.com/jupyterhub/jupyterhub/pull/2609) ([@kinow](https://github.com/kinow))
- Hide Stop My Server red button after server stopped. [#2577](https://github.com/jupyterhub/jupyterhub/pull/2577) ([@aar0nTw](https://github.com/aar0nTw))
- Update link of `changelog` [#2565](https://github.com/jupyterhub/jupyterhub/pull/2565) ([@iblis17](https://github.com/iblis17))
- typo [#2564](https://github.com/jupyterhub/jupyterhub/pull/2564) ([@julienchastang](https://github.com/julienchastang))
- Update to simplify the language related to spawner options [#2558](https://github.com/jupyterhub/jupyterhub/pull/2558) ([@NikeNano](https://github.com/NikeNano))
- Adding the use case of the Elucidata: How Jupyter Notebook is used in… [#2548](https://github.com/jupyterhub/jupyterhub/pull/2548) ([@IamViditAgarwal](https://github.com/IamViditAgarwal))
- Dict rewritten as literal [#2546](https://github.com/jupyterhub/jupyterhub/pull/2546) ([@remyleone](https://github.com/remyleone))
## 1.0
### [1.0.0] 2019-05-03
JupyterHub 1.0 is a major milestone for JupyterHub.
Huge thanks to the many people who have contributed to this release,
whether it was through discussion, testing, documentation, or development.
#### Major new features
- Support TLS encryption and authentication of all internal communication.
Spawners must implement `.move_certs` method to make certificates available
to the notebook server if it is not local to the Hub.
- There is now full UI support for managing named servers.
With named servers, each jupyterhub user may have access to more than one named server. For example, a professor may access a server named `research` and another named `teaching`.
![named servers on the home page](./images/named-servers-home.png)
- Authenticators can now expire and refresh authentication data by implementing
`Authenticator.refresh_user(user)`.
This allows things like OAuth data and access tokens to be refreshed.
When used together with `Authenticator.refresh_pre_spawn = True`,
auth refresh can be forced prior to Spawn,
allowing the Authenticator to *require* that authentication data is fresh
immediately before the user's server is launched.
```eval_rst
.. seealso::
- :meth:`.Authenticator.refresh_user`
- :meth:`.Spawner.create_certs`
- :meth:`.Spawner.move_certs`
```
#### New features
- allow custom spawners, authenticators, and proxies to register themselves via 'entry points', enabling more convenient configuration such as:
```python
c.JupyterHub.authenticator_class = 'github'
c.JupyterHub.spawner_class = 'docker'
c.JupyterHub.proxy_class = 'traefik_etcd'
```
- Spawners are passed the tornado Handler object that requested their spawn (as `self.handler`),
so they can do things like make decisions based on query arguments in the request.
- SimpleSpawner and DummyAuthenticator, which are useful for testing, have been merged into JupyterHub itself:
```python
# For testing purposes only. Should not be used in production.
c.JupyterHub.authenticator_class = 'dummy'
c.JupyterHub.spawner_class = 'simple'
```
These classes are **not** appropriate for production use. Only testing.
- Add health check endpoint at `/hub/health`
- Several prometheus metrics have been added (thanks to [Outreachy](https://www.outreachy.org/) applicants!)
- A new API for registering user activity.
To prepare for the addition of [alternate proxy implementations](https://github.com/jupyterhub/traefik-proxy),
responsibility for tracking activity is taken away from the proxy
and moved to the notebook server (which already has activity tracking features).
Activity is now tracked by pushing it to the Hub from user servers instead of polling the
proxy API.
- Dynamic `options_form` callables may now return an empty string
which will result in no options form being rendered.
- `Spawner.user_options` is persisted to the database to be re-used,
so that a server spawned once via the form can be re-spawned via the API
with the same options.
- Added `c.PAMAuthenticator.pam_normalize_username` option for round-tripping
usernames through PAM to retrieve the normalized form.
- Added `c.JupyterHub.named_server_limit_per_user` configuration to limit
the number of named servers each user can have.
The default is 0, for no limit.
- API requests to HubAuthenticated services (e.g. single-user servers)
may pass a token in the `Authorization` header,
matching authentication with the Hub API itself.
- Added `Authenticator.is_admin(handler, authentication)` method
and `Authenticator.admin_groups` configuration for automatically
determining that a member of a group should be considered an admin.
- New `c.Authenticator.post_auth_hook` configuration
that can be any callable of the form `async def hook(authenticator, handler, authentication=None):`.
This hook may transform the return value of `Authenticator.authenticate()`
and return a new authentication dictionary,
e.g. specifying admin privileges, group membership,
or custom white/blacklisting logic.
This hook is called *after* existing normalization and whitelist checking.
- `Spawner.options_from_form` may now be async
- Added `JupyterHub.shutdown_on_logout` option to trigger shutdown of a user's
servers when they log out.
- When `Spawner.start` raises an Exception,
a message can be passed on to the user if the exception has a `.jupyterhub_message` attribute.
#### Changes
- Authentication methods such as `check_whitelist` should now take an additional
`authentication` argument
that will be a dictionary (default: None) of authentication data,
as returned by `Authenticator.authenticate()`:
```python
def check_whitelist(self, username, authentication=None):
...
```
`authentication` should have a default value of None
for backward-compatibility with jupyterhub < 1.0.
- Prometheus metrics page is now authenticated.
Any authenticated user may see the prometheus metrics.
To disable prometheus authentication,
set `JupyterHub.authenticate_prometheus = False`.
- Visits to `/user/:name` no longer trigger an implicit launch of the user's server.
Instead, a page is shown indicating that the server is not running
with a link to request the spawn.
- API requests to `/user/:name` for a not-running server will have status 503 instead of 404.
- OAuth includes a confirmation page when attempting to visit another user's server,
so that users can choose to cancel authentication with the single-user server.
Confirmation is still skipped when accessing your own server.
#### Fixed
- Various fixes to improve Windows compatibility
(default Authenticator and Spawner still do not support Windows, but other Spawners may)
- Fixed compatibility with Oracle db
- Fewer redirects following a visit to the default `/` url
- Error when progress is requested before progress is ready
- Error when API requests are made to a not-running server without authentication
- Avoid logging database password on connect if password is specified in `JupyterHub.db_url`.
#### Development changes
There have been several changes to the development process that shouldn't
generally affect users of JupyterHub, but may affect contributors.
In general, see `CONTRIBUTING.md` for contribution info or ask if you have questions.
- JupyterHub has adopted `black` as a code autoformatter and `pre-commit`
as a tool for automatically running code formatting on commit.
This is meant to make it *easier* to contribute to JupyterHub,
so let us know if it's having the opposite effect.
- JupyterHub has switched its test suite to using `pytest-asyncio` from `pytest-tornado`.
- OAuth is now implemented internally using `oauthlib` instead of `python-oauth2`. This should have no effect on behavior.
## 0.9
### [0.9.6] 2019-04-01
JupyterHub 0.9.6 is a security release.
- Fixes an Open Redirect vulnerability (CVE-2019-10255).
JupyterHub 0.9.5 included a partial fix for this issue.
### [0.9.4] 2018-09-24
JupyterHub 0.9.4 is a small bugfix release.
- Fixes an issue that required all running user servers to be restarted
when performing an upgrade from 0.8 to 0.9.
- Fixes content-type for API endpoints back to `application/json`.
It was `text/html` in 0.9.0-0.9.3.
### [0.9.3] 2018-09-12
JupyterHub 0.9.3 contains small bugfixes and improvements
@@ -411,7 +124,7 @@ and tornado < 5.0.
coroutines, and CPU/memory/FD consumption.
- Add async `Spawner.get_options_form` alternative to `.options_form`, so it can be a coroutine.
- Add `JupyterHub.redirect_to_server` config to govern whether
users should be sent to their server on login or the JupyterHub home page.
users should be sent to their server on login or the JuptyerHub home page.
- html page templates can be more easily customized and extended.
- Allow registering external OAuth clients for using the Hub as an OAuth provider.
- Add basic prometheus metrics at `/hub/metrics` endpoint.
@@ -704,10 +417,7 @@ Fix removal of `/login` page in 0.4.0, breaking some OAuth providers.
First preview release
[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/1.0.0...HEAD
[1.0.0]: https://github.com/jupyterhub/jupyterhub/compare/0.9.6...1.0.0
[0.9.6]: https://github.com/jupyterhub/jupyterhub/compare/0.9.4...0.9.6
[0.9.4]: https://github.com/jupyterhub/jupyterhub/compare/0.9.3...0.9.4
[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/0.9.3...HEAD
[0.9.3]: https://github.com/jupyterhub/jupyterhub/compare/0.9.2...0.9.3
[0.9.2]: https://github.com/jupyterhub/jupyterhub/compare/0.9.1...0.9.2
[0.9.1]: https://github.com/jupyterhub/jupyterhub/compare/0.9.0...0.9.1

View File

@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
#
import sys
import os
import shlex
import sys
# For conversion from markdown to html
import recommonmark.parser
# Set paths
sys.path.insert(0, os.path.abspath('.'))
@@ -18,8 +21,6 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'autodoc_traits',
'sphinx_copybutton',
'sphinx-jsonschema',
]
templates_path = ['_templates']
@@ -38,6 +39,7 @@ from os.path import dirname
docs = dirname(dirname(__file__))
root = dirname(docs)
sys.path.insert(0, root)
sys.path.insert(0, os.path.join(docs, 'sphinxext'))
import jupyterhub
@@ -56,16 +58,6 @@ default_role = 'literal'
# -- Source -------------------------------------------------------------
import recommonmark
from recommonmark.transform import AutoStructify
def setup(app):
app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True)
app.add_stylesheet('custom.css')
app.add_transform(AutoStructify)
source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser'}
source_suffix = ['.rst', '.md']
@@ -74,7 +66,7 @@ source_suffix = ['.rst', '.md']
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages.
html_theme = 'pandas_sphinx_theme'
html_theme = 'alabaster'
html_logo = '_static/images/logo/logo.png'
html_favicon = '_static/images/logo/favicon.ico'
@@ -82,6 +74,31 @@ html_favicon = '_static/images/logo/favicon.ico'
# Paths that contain custom static files (such as style sheets)
html_static_path = ['_static']
html_theme_options = {
'show_related': True,
'description': 'Documentation for JupyterHub',
'github_user': 'jupyterhub',
'github_repo': 'jupyterhub',
'github_banner': False,
'github_button': True,
'github_type': 'star',
'show_powered_by': False,
'extra_nav_links': {
'GitHub Repo': 'http://github.com/jupyterhub/jupyterhub',
'Issue Tracker': 'http://github.com/jupyterhub/jupyterhub/issues',
},
}
html_sidebars = {
'**': [
'about.html',
'searchbox.html',
'navigation.html',
'relations.html',
'sourcelink.html',
]
}
htmlhelp_basename = 'JupyterHubdoc'
# -- Options for LaTeX output ---------------------------------------------
@@ -164,7 +181,9 @@ intersphinx_mapping = {'https://docs.python.org/3/': None}
# -- Read The Docs --------------------------------------------------------
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if on_rtd:
if not on_rtd:
html_theme = 'alabaster'
else:
# readthedocs.org uses their theme by default, so no need to specify it
# build rest-api, since RTD doesn't run make
from subprocess import check_call as sh

View File

@@ -1,30 +0,0 @@
.. _contributing/community:
================================
Community communication channels
================================
We use `Discourse <https://discourse.jupyter.org>` for online discussion.
Everyone in the Jupyter community is welcome to bring ideas and questions there.
In addition, we use `Gitter <https://gitter.im>`_ for online, real-time text chat,
a place for more ephemeral discussions.
The primary Gitter channel for JupyterHub is `jupyterhub/jupyterhub <https://gitter.im/jupyterhub/jupyterhub>`_.
Gitter isn't archived or searchable, so we recommend going to discourse first
to make sure that discussions are most useful and accessible to the community.
Remember that our community is distributed across the world in various
timezones, so be patient if you do not get an answer immediately!
GitHub issues are used for most long-form project discussions, bug reports
and feature requests. Issues related to a specific authenticator or
spawner should be directed to the appropriate repository for the
authenticator or spawner. If you are using a specific JupyterHub
distribution (such as `Zero to JupyterHub on Kubernetes <http://github.com/jupyterhub/zero-to-jupyterhub-k8s>`_
or `The Littlest JupyterHub <http://github.com/jupyterhub/the-littlest-jupyterhub/>`_),
you should open issues directly in their repository. If you can not
find a repository to open your issue in, do not worry! Create it in the `main
JupyterHub repository <https://github.com/jupyterhub/jupyterhub/>`_ and our
community will help you figure it out.
A `mailing list <https://groups.google.com/forum/#!forum/jupyter>`_ for all
of Project Jupyter exists, along with one for `teaching with Jupyter
<https://groups.google.com/forum/#!forum/jupyter-education>`_.

View File

@@ -1,78 +0,0 @@
.. _contributing/docs:
==========================
Contributing Documentation
==========================
Documentation is often more important than code. This page helps
you get set up on how to contribute documentation to JupyterHub.
Building documentation locally
==============================
We use `sphinx <http://sphinx-doc.org>`_ to build our documentation. It takes
our documentation source files (written in `markdown
<https://daringfireball.net/projects/markdown/>`_ or `reStructuredText
<http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html>`_ &
stored under the ``docs/source`` directory) and converts it into various
formats for people to read. To make sure the documentation you write or
change renders correctly, it is good practice to test it locally.
#. Make sure you have successfuly completed :ref:`contributing/setup`.
#. Install the packages required to build the docs.
.. code-block:: bash
python3 -m pip install -r docs/requirements.txt
#. Build the html version of the docs. This is the most commonly used
output format, so verifying it renders as you should is usually good
enough.
.. code-block:: bash
cd docs
make html
This step will display any syntax or formatting errors in the documentation,
along with the filename / line number in which they occurred. Fix them,
and re-run the ``make html`` command to re-render the documentation.
#. View the rendered documentation by opening ``build/html/index.html`` in
a web browser.
.. tip::
On macOS, you can open a file from the terminal with ``open <path-to-file>``.
On Linux, you can do the same with ``xdg-open <path-to-file>``.
.. _contributing/docs/conventions:
Documentation conventions
=========================
This section lists various conventions we use in our documentation. This is a
living document that grows over time, so feel free to add to it / change it!
Our entire documentation does not yet fully conform to these conventions yet,
so help in making it so would be appreciated!
``pip`` invocation
------------------
There are many ways to invoke a ``pip`` command, we recommend the following
approach:
.. code-block:: bash
python3 -m pip
This invokes pip explicitly using the python3 binary that you are
currently using. This is the **recommended way** to invoke pip
in our documentation, since it is least likely to cause problems
with python3 and pip being from different environments.
For more information on how to invoke ``pip`` commands, see
`the pip documentation <https://pip.pypa.io/en/stable/>`_.

View File

@@ -1,21 +0,0 @@
============
Contributing
============
We want you to contribute to JupyterHub in ways that are most exciting
& useful to you. We value documentation, testing, bug reporting & code equally,
and are glad to have your contributions in whatever form you wish :)
Our `Code of Conduct <https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md>`_
(`reporting guidelines <https://github.com/jupyter/governance/blob/master/conduct/reporting_online.md>`_)
helps keep our community welcoming to as many people as possible.
.. toctree::
:maxdepth: 2
community
setup
docs
tests
roadmap
security

View File

@@ -1,98 +0,0 @@
# The JupyterHub roadmap
This roadmap collects "next steps" for JupyterHub. It is about creating a
shared understanding of the project's vision and direction amongst
the community of users, contributors, and maintainers.
The goal is to communicate priorities and upcoming release plans.
It is not a aimed at limiting contributions to what is listed here.
## Using the roadmap
### Sharing Feedback on the Roadmap
All of the community is encouraged to provide feedback as well as share new
ideas with the community. Please do so by submitting an issue. If you want to
have an informal conversation first use one of the other communication channels.
After submitting the issue, others from the community will probably
respond with questions or comments they have to clarify the issue. The
maintainers will help identify what a good next step is for the issue.
### What do we mean by "next step"?
When submitting an issue, think about what "next step" category best describes
your issue:
* **now**, concrete/actionable step that is ready for someone to start work on.
These might be items that have a link to an issue or more abstract like
"decrease typos and dead links in the documentation"
* **soon**, less concrete/actionable step that is going to happen soon,
discussions around the topic are coming close to an end at which point it can
move into the "now" category
* **later**, abstract ideas or tasks, need a lot of discussion or
experimentation to shape the idea so that it can be executed. Can also
contain concrete/actionable steps that have been postponed on purpose
(these are steps that could be in "now" but the decision was taken to work on
them later)
### Reviewing and Updating the Roadmap
The roadmap will get updated as time passes (next review by 1st December) based
on discussions and ideas captured as issues.
This means this list should not be exhaustive, it should only represent
the "top of the stack" of ideas. It should
not function as a wish list, collection of feature requests or todo list.
For those please create a
[new issue](https://github.com/jupyterhub/jupyterhub/issues/new).
The roadmap should give the reader an idea of what is happening next, what needs
input and discussion before it can happen and what has been postponed.
## The roadmap proper
### Project vision
JupyterHub is a dependable tool used by humans that reduces the complexity of
creating the environment in which a piece of software can be executed.
### Now
These "Now" items are considered active areas of focus for the project:
* HubShare - a sharing service for use with JupyterHub.
* Users should be able to:
- Push a project to other users.
- Get a checkout of a project from other users.
- Push updates to a published project.
- Pull updates from a published project.
- Manage conflicts/merges by simply picking a version (our/theirs)
- Get a checkout of a project from the internet. These steps are completely different from saving notebooks/files.
- Have directories that are managed by git completely separately from our stuff.
- Look at pushed content that they have access to without an explicit pull.
- Define and manage teams of users.
- Adding/removing a user to/from a team gives/removes them access to all projects that team has access to.
- Build other services, such as static HTML publishing and dashboarding on top of these things.
### Soon
These "Soon" items are under discussion. Once an item reaches the point of an
actionable plan, the item will be moved to the "Now" section. Typically,
these will be moved at a future review of the roadmap.
* resource monitoring and management:
- (prometheus?) API for resource monitoring
- tracking activity on single-user servers instead of the proxy
- notes and activity tracking per API token
- UI for managing named servers
### Later
The "Later" items are things that are at the back of the project's mind. At this
time there is no active plan for an item. The project would like to find the
resources and time to discuss these ideas.
- real-time collaboration
- Enter into real-time collaboration mode for a project that starts a shared execution context.
- Once the single-user notebook package supports realtime collaboration,
implement sharing mechanism integrated into the Hub.

View File

@@ -1,10 +0,0 @@
Reporting security issues in Jupyter or JupyterHub
==================================================
If you find a security vulnerability in Jupyter or JupyterHub,
whether it is a failure of the security model described in :doc:`../reference/websecurity`
or a failure in implementation,
please report it to security@ipython.org.
If you prefer to encrypt your security reports,
you can use :download:`this PGP public key </ipython_security.asc>`.

View File

@@ -1,175 +0,0 @@
.. _contributing/setup:
================================
Setting up a development install
================================
System requirements
===================
JupyterHub can only run on MacOS or Linux operating systems. If you are
using Windows, we recommend using `VirtualBox <https://virtualbox.org>`_
or a similar system to run `Ubuntu Linux <https://ubuntu.com>`_ for
development.
Install Python
--------------
JupyterHub is written in the `Python <https://python.org>`_ programming language, and
requires you have at least version 3.5 installed locally. If you havent
installed Python before, the recommended way to install it is to use
`miniconda <https://conda.io/miniconda.html>`_. Remember to get the Python 3 version,
and **not** the Python 2 version!
Install nodejs
--------------
``configurable-http-proxy``, the default proxy implementation for
JupyterHub, is written in Javascript to run on `NodeJS
<https://nodejs.org/en/>`_. If you have not installed nodejs before, we
recommend installing it in the ``miniconda`` environment you set up for
Python. You can do so with ``conda install nodejs``.
Install git
-----------
JupyterHub uses `git <https://git-scm.com>`_ & `GitHub <https://github.com>`_
for development & collaboration. You need to `install git
<https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_ to work on
JupyterHub. We also recommend getting a free account on GitHub.com.
Setting up a development install
================================
When developing JupyterHub, you need to make changes to the code & see
their effects quickly. You need to do a developer install to make that
happen.
1. Clone the `JupyterHub git repository <https://github.com/jupyterhub/jupyterhub>`_
to your computer.
.. code:: bash
git clone https://github.com/jupyterhub/jupyterhub
cd jupyterhub
2. Make sure the ``python`` you installed and the ``npm`` you installed
are available to you on the command line.
.. code:: bash
python -V
This should return a version number greater than or equal to 3.5.
.. code:: bash
npm -v
This should return a version number greater than or equal to 5.0.
3. Install ``configurable-http-proxy``. This is required to run
JupyterHub.
.. code:: bash
npm install -g configurable-http-proxy
If you get an error that says ``Error: EACCES: permission denied``,
you might need to prefix the command with ``sudo``. If you do not
have access to sudo, you may instead run the following commands:
.. code:: bash
npm install configurable-http-proxy
export PATH=$PATH:$(pwd)/node_modules/.bin
The second line needs to be run every time you open a new terminal.
4. Install the python packages required for JupyterHub development.
.. code:: bash
python3 -m pip install -r dev-requirements.txt
python3 -m pip install -r requirements.txt
5. Install the development version of JupyterHub. This lets you edit
JupyterHub code in a text editor & restart the JupyterHub process to
see your code changes immediately.
.. code:: bash
python3 -m pip install --editable .
6. You are now ready to start JupyterHub!
.. code:: bash
jupyterhub
7. You can access JupyterHub from your browser at
``http://localhost:8000`` now.
Happy developing!
Using DummyAuthenticator & SimpleLocalProcessSpawner
====================================================
To simplify testing of JupyterHub, its helpful to use
:class:`~jupyterhub.auth.DummyAuthenticator` instead of the default JupyterHub
authenticator and SimpleLocalProcessSpawner instead of the default spawner.
There is a sample configuration file that does this in
``testing/jupyterhub_config.py``. To launch jupyterhub with this
configuration:
.. code:: bash
jupyterhub -f testing/jupyterhub_config.py
The default JupyterHub `authenticator
<https://jupyterhub.readthedocs.io/en/stable/reference/authenticators.html#the-default-pam-authenticator>`_
& `spawner
<https://jupyterhub.readthedocs.io/en/stable/api/spawner.html#localprocessspawner>`_
require your system to have user accounts for each user you want to log in to
JupyterHub as.
DummyAuthenticator allows you to log in with any username & password,
while SimpleLocalProcessSpawner allows you to start servers without having to
create a unix user for each JupyterHub user. Together, these make it
much easier to test JupyterHub.
Tip: If you are working on parts of JupyterHub that are common to all
authenticators & spawners, we recommend using both DummyAuthenticator &
SimpleLocalProcessSpawner. If you are working on just authenticator related
parts, use only SimpleLocalProcessSpawner. Similarly, if you are working on
just spawner related parts, use only DummyAuthenticator.
Troubleshooting
===============
This section lists common ways setting up your development environment may
fail, and how to fix them. Please add to the list if you encounter yet
another way it can fail!
``lessc`` not found
-------------------
If the ``python3 -m pip install --editable .`` command fails and complains about
``lessc`` being unavailable, you may need to explicitly install some
additional JavaScript dependencies:
.. code:: bash
npm install
This will fetch client-side JavaScript dependencies necessary to compile
CSS.
You may also need to manually update JavaScript and CSS after some
development updates, with:
.. code:: bash
python3 setup.py js # fetch updated client-side js
python3 setup.py css # recompile CSS from LESS sources

View File

@@ -1,68 +0,0 @@
.. _contributing/tests:
==================
Testing JupyterHub
==================
Unit test help validate that JupyterHub works the way we think it does,
and continues to do so when changes occur. They also help communicate
precisely what we expect our code to do.
JupyterHub uses `pytest <https://pytest.org>`_ for all our tests. You
can find them under ``jupyterhub/tests`` directory in the git repository.
Running the tests
==================
#. Make sure you have completed :ref:`contributing/setup`. You should be able
to start ``jupyterhub`` from the commandline & access it from your
web browser. This ensures that the dev environment is properly set
up for tests to run.
#. You can run all tests in JupyterHub
.. code-block:: bash
pytest -v jupyterhub/tests
This should display progress as it runs all the tests, printing
information about any test failures as they occur.
If you wish to confirm test coverage the run tests with the `--cov` flag:
.. code-block:: bash
pytest -v --cov=jupyterhub jupyterhub/tests
#. You can also run tests in just a specific file:
.. code-block:: bash
pytest -v jupyterhub/tests/<test-file-name>
#. To run a specific test only, you can do:
.. code-block:: bash
pytest -v jupyterhub/tests/<test-file-name>::<test-name>
This runs the test with function name ``<test-name>`` defined in
``<test-file-name>``. This is very useful when you are iteratively
developing a single test.
For example, to run the test ``test_shutdown`` in the file ``test_api.py``,
you would run:
.. code-block:: bash
pytest -v jupyterhub/tests/test_api.py::test_shutdown
Troubleshooting Test Failures
=============================
All the tests are failing
-------------------------
Make sure you have completed all the steps in :ref:`contributing/setup` sucessfully, and
can launch ``jupyterhub`` from the terminal.

View File

@@ -1,50 +0,0 @@
Eventlogging and Telemetry
==========================
JupyterHub can be configured to record structured events from a running server using Jupyter's `Telemetry System`_. The types of events that JupyterHub emits are defined by `JSON schemas`_ listed below_
emitted as JSON data, defined and validated by the JSON schemas listed below.
.. _logging: https://docs.python.org/3/library/logging.html
.. _`Telemetry System`: https://github.com/jupyter/telemetry
.. _`JSON schemas`: https://json-schema.org/
How to emit events
------------------
Event logging is handled by its ``Eventlog`` object. This leverages Python's standing logging_ library to emit, filter, and collect event data.
To begin recording events, you'll need to set two configurations:
1. ``handlers``: tells the EventLog *where* to route your events. This trait is a list of Python logging handlers that route events to
2. ``allows_schemas``: tells the EventLog *which* events should be recorded. No events are emitted by default; all recorded events must be listed here.
Here's a basic example:
.. code-block::
import logging
c.EventLog.handlers = [
logging.FileHandler('event.log'),
]
c.EventLog.allowed_schemas = [
'hub.jupyter.org/server-action'
]
The output is a file, ``"event.log"``, with events recorded as JSON data.
.. _below:
Event schemas
-------------
.. toctree::
:maxdepth: 2
server-actions.rst

View File

@@ -1 +0,0 @@
.. jsonschema:: ../../../jupyterhub/event-schemas/server-actions/v1.yaml

View File

@@ -66,7 +66,7 @@ easy to do with RStudio too.
### University of Colorado Boulder
- (CU Research Computing) CURC
- (CU Research Computing) CURC
- [JupyterHub User Guide](https://www.rc.colorado.edu/support/user-guide/jupyterhub.html)
- Slurm job dispatched on Crestone compute cluster
- log troubleshooting
@@ -77,25 +77,16 @@ easy to do with RStudio too.
- Earth Lab at CU
- [Tutorial on Parallel R on JupyterHub](https://earthdatascience.org/tutorials/parallel-r-on-jupyterhub/)
### George Washington University
- [Jupyter Hub](http://go.gwu.edu/jupyter) with university single-sign-on. Deployed early 2017.
### HTCondor
- [HTCondor Python Bindings Tutorial from HTCondor Week 2017 includes information on their JupyterHub tutorials](https://research.cs.wisc.edu/htcondor/HTCondorWeek2017/presentations/TueBockelman_Python.pdf)
### University of Illinois
- https://datascience.business.illinois.edu (currently down; checked 04/26/19)
### IllustrisTNG Simulation Project
- [JupyterHub/Lab-based analysis platform, part of the TNG public data release](http://www.tng-project.org/data/)
- https://datascience.business.illinois.edu
### MIT and Lincoln Labs
- https://supercloud.mit.edu/
### Michigan State University
@@ -109,16 +100,7 @@ easy to do with RStudio too.
- https://dsa.missouri.edu/faq/
### Paderborn University
- [Data Science (DICE) group](https://dice.cs.uni-paderborn.de/)
- [nbgraderutils](https://github.com/dice-group/nbgraderutils): Use JupyterHub + nbgrader + iJava kernel for online Java exercises. Used in lecture Statistical Natural Language Processing.
### Penn State University
- [Press release](https://news.psu.edu/story/523093/2018/05/24/new-open-source-web-apps-available-students-and-faculty): "New open-source web apps available for students and faculty" (but Hub is currently down; checked 04/26/19)
### University of Rochester CIRC
### University of Rochester CIRC
- [JupyterHub Userguide](https://info.circ.rochester.edu/Web_Applications/JupyterHub.html) - Slurm, beehive
@@ -134,7 +116,7 @@ easy to do with RStudio too.
- Educational Technology Services - Paul Jamason
- [jupyterhub.ucsd.edu](https://jupyterhub.ucsd.edu)
### TACC University of Texas
### Texas A&M
@@ -142,10 +124,7 @@ easy to do with RStudio too.
- Kristen Thyng - Oceanography
- [Teaching with JupyterHub and nbgrader](http://kristenthyng.com/blog/2016/09/07/jupyterhub+nbgrader/)
### Elucidata
- What's new in Jupyter Notebooks @[Elucidata](https://elucidata.io/):
- Using Jupyter Notebooks with Jupyterhub on GCP, managed by GKE
- https://medium.com/elucidata/why-you-should-be-using-a-jupyter-notebook-8385a4ccd93d
## Service Providers
@@ -162,6 +141,7 @@ easy to do with RStudio too.
[Everware](https://github.com/everware) Reproducible and reusable science powered by jupyterhub and docker. Like nbviewer, but executable. CERN, Geneva [website](http://everware.xyz/)
### Microsoft Azure
- https://docs.microsoft.com/en-us/azure/machine-learning/machine-learning-data-science-linux-dsvm-intro
@@ -171,11 +151,9 @@ easy to do with RStudio too.
- https://getcarina.com/blog/learning-how-to-whale/
- http://carolynvanslyck.com/talk/carina/jupyterhub/#/
### Hadoop
- [Deploying JupyterHub on Hadoop](https://jupyterhub-on-hadoop.readthedocs.io)
### jcloud.io
- Open to public JupyterHub server
- https://jcloud.io
## Miscellaneous
- https://medium.com/@ybarraud/setting-up-jupyterhub-with-sudospawner-and-anaconda-844628c0dbee#.rm3yt87e1

View File

@@ -31,15 +31,6 @@ c.Authenticator.admin_users = {'mal', 'zoe'}
Users in the admin list are automatically added to the user `whitelist`,
if they are not already present.
Each authenticator may have different ways of determining whether a user is an
administrator. By default JupyterHub use the PAMAuthenticator which provide the
`admin_groups` option and can determine administrator status base on a user
groups. For example we can let any users in the `wheel` group be admin:
```python
c.PAMAuthenticator.admin_groups = {'wheel'}
```
## Give admin access to other users' notebook servers (`admin_access`)
Since the default `JupyterHub.admin_access` setting is False, the admins
@@ -104,16 +95,5 @@ popular services:
A generic implementation, which you can use for OAuth authentication
with any provider, is also available.
## Use DummyAuthenticator for testing
The :class:`~jupyterhub.auth.DummyAuthenticator` is a simple authenticator that
allows for any username/password unless if a global password has been set. If
set, it will allow for any username as long as the correct password is provided.
To set a global password, add this to the config file:
```python
c.DummyAuthenticator.password = "some_password"
```
[PAM]: https://en.wikipedia.org/wiki/Pluggable_authentication_module
[OAuthenticator]: https://github.com/jupyterhub/oauthenticator

View File

@@ -1,7 +1,7 @@
# Configuration Basics
The section contains basic information about configuring settings for a JupyterHub
deployment. The [Technical Reference](../reference/index)
deployment. The [Technical Reference](../reference/index.html)
documentation provides additional details.
This section will help you learn how to:
@@ -44,7 +44,7 @@ jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
```
The IPython documentation provides additional information on the
[config system](http://ipython.readthedocs.io/en/stable/development/config)
[config system](http://ipython.readthedocs.io/en/stable/development/config.html)
that Jupyter uses.
## Configure using command line options
@@ -61,7 +61,7 @@ would enter:
```bash
jupyterhub --ip 10.0.1.2 --port 443 --ssl-key my_ssl.key --ssl-cert my_ssl.cert
```
```
All configurable options may technically be set on the command-line,
though some are inconvenient to type. To set a particular configuration
@@ -77,24 +77,11 @@ jupyterhub --Spawner.notebook_dir='~/assignments'
## Configure for various deployment environments
The default authentication and process spawning mechanisms can be replaced, and
specific [authenticators](./authenticators-users-basics) and
[spawners](./spawners-basics) can be set in the configuration file.
specific [authenticators](./authenticators-users-basics.html) and
[spawners](./spawners-basics.html) can be set in the configuration file.
This enables JupyterHub to be used with a variety of authentication methods or
process control and deployment environments. [Some examples](../reference/config-examples),
process control and deployment environments. [Some examples](../reference/config-examples.html),
meant as illustration, are:
- Using GitHub OAuth instead of PAM with [OAuthenticator](https://github.com/jupyterhub/oauthenticator)
- Spawning single-user servers with Docker, using the [DockerSpawner](https://github.com/jupyterhub/dockerspawner)
## Run the proxy separately
This is *not* strictly necessary, but useful in many cases. If you
use a custom proxy (e.g. Traefik), this also not needed.
Connections to user servers go through the proxy, and *not* the hub
itself. If the proxy stays running when the hub restarts (for
maintenance, re-configuration, etc.), then use connections are not
interrupted. For simplicity, by default the hub starts the proxy
automatically, so if the hub restarts, the proxy restarts, and user
connections are interrupted. It is easy to run the proxy separately,
for information see [the separate proxy page](../reference/separate-proxy).

View File

@@ -1,10 +1,5 @@
Get Started
===========
This section covers how to configure and customize JupyterHub for your
needs. It contains information about authentication, networking, security, and
other topics that are relevant to individuals or organizations deploying their
own JupyterHub.
Getting Started
===============
.. toctree::
:maxdepth: 2
@@ -15,4 +10,3 @@ own JupyterHub.
authenticators-users-basics
spawners-basics
services-basics
institutional-faq

View File

@@ -1,266 +0,0 @@
# Institutional FAQ
This page contains common questions from users of JupyterHub,
broken down by their roles within organizations.
## For all
### Is it appropriate for adoption within a larger institutional context?
Yes! JupyterHub has been used at-scale for large pools of users, as well
as complex and high-performance computing. For example, UC Berkeley uses
JupyterHub for its Data Science Education Program courses (serving over
3,000 students). The Pangeo project uses JupyterHub to provide access
to scalable cloud computing with Dask. JupyterHub is stable customizable
to the use-cases of large organizations.
### I keep hearing about Jupyter Notebook, JupyterLab, and now JupyterHub. Whats the difference?
Here is a quick breakdown of these three tools:
* **The Jupyter Notebook** is a document specification (the `.ipynb`) file that interweaves
narrative text with code cells and their outputs. It is also a graphical interface
that allows users to edit these documents. There are also several other graphical interfaces
that allow users to edit the `.ipynb` format (nteract, Jupyer Lab, Google Colab, Kaggle, etc).
* **JupyterLab** is a flexible and extendible user interface for interactive computing. It
has several extensions that are tailored for using Jupyter Notebooks, as well as extensions
for other parts of the data science stack.
* **JupyterHub** is an application that manages interactive computing sessions for **multiple users**.
It also connects them with infrastructure those users wish to access. It can provide
remote access to Jupyter Notebooks and Jupyter Lab for many people.
## For management
### Briefly, what problem does JupyterHub solve for us?
JupyterHub provides a shared platform for data science and collaboration.
It allows users to utilize familiar data science workflows (such as the scientific python stack,
the R tidyverse, and Jupyter Notebooks) on institutional infrastructure. It also allows administrators
some control over access to resources, security, environments, and authentication.
### Is JupyterHub mature? Why should we trust it?
Yes - the core JupyterHub application recently
reached 1.0 status, and is considered stable and performant for most institutions.
JupyterHub has also been deployed (along with other tools) to work on
scalable infrastructure, large datasets, and high-performance computing.
### Who else uses JupyterHub?
JupyterHub is used at a variety of institutions in academia,
industry, and government research labs. It is most-commonly used by two kinds of groups:
* Small teams (e.g., data science teams, research labs, or collaborative projects) to provide a
shared resource for interactive computing, collaboration, and analytics.
* Large teams (e.g., a department, a large class, or a large group of remote users) to provide
access to organizational hardware, data, and analytics environments at scale.
Here are a sample of organizations that use JupyterHub:
* **Universities and colleges**: UC Berkeley, UC San Diego, Cal Poly SLO, Harvard University, University of Chicago,
University of Oslo, University of Sheffield, Université Paris Sud, University of Versailles
* **Research laboratories**: NASA, NCAR, NOAA, the Large Synoptic Survey Telescope, Brookhaven National Lab,
Minnesota Supercomputing Institute, ALCF, CERN, Lawrence Livermore National Laboratory
* **Online communities**: Pangeo, Quantopian, mybinder.org, MathHub, Open Humans
* **Computing infrastructure providers**: NERSC, San Diego Supercomputing Center, Compute Canada
* **Companies**: Capital One, SANDVIK code, Globus
See the [Gallery of JupyterHub deployments](../gallery-jhub-deployments.md) for
a more complete list of JupyterHub deployments at institutions.
### How does JupyterHub compare with hosted products, like Google Colaboratory, RStudio.cloud, or Anaconda Enterprise?
JupyterHub puts you in control of your data, infrastructure, and coding environment.
In addition, it is vendor neutral, which reduces lock-in to a particular vendor or service.
JupyterHub provides access to interactive computing environments in the cloud (similar to each of these services).
Compared with the tools above, it is more flexible, more customizable, free, and
gives administrators more control over their setup and hardware.
Because JupyterHub is an open-source, community-driven tool, it can be extended and
modified to fit an institution's needs. It plays nicely with the open source data science
stack, and can serve a variety of computing enviroments, user interfaces, and
computational hardware. It can also be deployed anywhere - on enterprise cloud infrastructure, on
High-Performance-Computing machines, on local hardware, or even on a single laptop, which
is not possible with most other tools for shared interactive computing.
## For IT
### How would I set up JupyterHub on institutional hardware?
That depends on what kind of hardware you've got. JupyterHub is flexible enough to be deployed
on a variety of hardware, including in-room hardware, on-prem clusters, cloud infrastructure,
etc.
The most common way to set up a JupyterHub is to use a JupyterHub distribution, these are pre-configured
and opinionated ways to set up a JupyterHub on particular kinds of infrastructure. The two distributions
that we currently suggest are:
* [Zero to JupyterHub for Kubernetes](https://z2jh.jupyter.org) is a scalable JupyterHub deployment and
guide that runs on Kubernetes. Better for larger or dynamic user groups (50-10,000) or more complex
compute/data needs.
* [The Littlest JupyterHub](https://tljh.jupyter.org) is a lightweight JupyterHub that runs on a single
single machine (in the cloud or under your desk). Better for smaller usergroups (4-80) or more
lightweight computational resources.
### Does JupyterHub run well in the cloud?
Yes - most deployments of JupyterHub are run via cloud infrastructure and on a variety of cloud providers.
Depending on the distribution of JupyterHub that you'd like to use, you can also connect your JupyterHub
deployment with a number of other cloud-native services so that users have access to other resources from
their interactive computing sessions.
For example, if you use the [Zero to JupyterHub for Kubernetes](https://z2jh.jupyter.org) distribution,
you'll be able to utilize container-based workflows of other technologies such as the [dask-kubernetes](https://kubernetes.dask.org/en/latest/)
project for distributed computing.
The Z2JH Helm Chart also has some functionality built in for auto-scaling your cluster up and down
as more resources are needed - allowing you to utilize the benefits of a flexible cloud-based deployment.
### Is JupyterHub secure?
The short answer: yes. JupyterHub as a standalone application has been battle-tested at an institutional
level for several years, and makes a number of "default" security decisions that are reasonable for most
users.
* For security considerations in the base JupyterHub application,
[see the JupyterHub security page](https://jupyterhub.readthedocs.io/en/stable/reference/websecurity.html)
* For security considerations when deploying JupyterHub on Kubernetes, see the
[JupyterHub on Kubernetes security page](https://zero-to-jupyterhub.readthedocs.io/en/latest/security.html).
The longer answer: it depends on your deployment. Because JupyterHub is very flexible, it can be used
in a variety of deployment setups. This often entails connecting your JupyterHub to **other** infrastructure
(such as a [Dask Gateway service](https://gateway.dask.org/)). There are many security decisions to be made
in these cases, and the security of your JupyterHub deployment will often depend on these decisions.
If you are worried about security, don't hesitate to reach out to the JupyterHub community in the
[Jupyter Community Forum](https://discourse.jupyter.org/c/jupyterhub). This community of practice has many
individuals with experience running secure JupyterHub deployments.
### Does JupyterHub provide computing or data infrastructure?
No - JupyterHub manages user sessions and can *control* computing infrastructure, but it does not provide these
things itself. You are expected to run JupyterHub on your own infrastructure (local or in the cloud). Moreover,
JupyterHub has no internal concept of "data", but is designed to be able to communicate with data repositories
(again, either locally or remotely) for use within interactive computing sessions.
### How do I manage users?
JupyterHub offers a few options for managing your users. Upon setting up a JupyterHub, you can choose what
kind of **authentication** you'd like to use. For example, you can have users sign up with an institutional
email address, or choose a username / password when they first log-in, or offload authentication onto
another service such as an organization's OAuth.
The users of a JupyterHub are stored locally, and can be modified manually by an administrator of the JupyterHub.
Moreover, the *active* users on a JupyterHub can be found on the administrator's page. This page
gives you the abiltiy to stop or restart kernels, inspect user filesystems, and even take over user
sessions to assist them with debugging.
### How do I manage software environments?
A key benefit of JupyterHub is the ability for an administrator to define the environment(s) that users
have access to. There are many ways to do this, depending on what kind of infrastructure you're using for
your JupyterHub.
For example, **The Littlest JupyterHub** runs on a single VM. In this case, the administrator defines
an environment by installing packages to a shared folder that exists on the path of all users. The
**JupyterHub for Kubernetes** deployment uses Docker images to define environments. You can create your
own list of Docker images that users can select from, and can also control things like the amount of
RAM available to users, or the types of machines that their sessions will use in the cloud.
### How does JupyterHub manage computational resources?
For interactive computing sessions, JupyterHub controls computational resources via a **spawner**.
Spawners define how a new user session is created, and are customized for particular kinds of
infrastructure. For example, the KubeSpawner knows how to control a Kubernetes deployment
to create new pods when users log in.
For more sophisticated computational resources (like distributed computing), JupyterHub can
connect with other infrastructure tools (like Dask or Spark). This allows users to control
scalable or high-performance resources from within their JupyterHub sessions. The logic of
how those resources are controlled is taken care of by the non-JupyterHub application.
### Can JupyterHub be used with my high-performance computing resources?
Yes - JupyterHub can provide access to many kinds of computing infrastructure.
Especially when combined with other open-source schedulers such as Dask, you can manage fairly
complex computing infrastructure from the interactive sessions of a JupyterHub. For example
[see the Dask HPC page](https://docs.dask.org/en/latest/setup/hpc.html).
### How much resources do user sessions take?
This is highly configurable by the administrator. If you wish for your users to have simple
data analytics environments for prototyping and light data exploring, you can restrict their
memory and CPU based on the resources that you have available. If you'd like your JupyterHub
to serve as a gateway to high-performance compute or data resources, you may increase the
resources available on user machines, or connect them with computing infrastructure elsewhere.
### Can I customize the look and feel of a JupyterHub?
JupyterHub provides some customization of the graphics displayed to users. The most common
modification is to add custom branding to the JupyterHub login page, loading pages, and
various elements that persist across all pages (such as headers).
## For Technical Leads
### Will JupyterHub “just work” with our team's interactive computing setup?
Depending on the complexity of your setup, you'll have different experiences with "out of the box"
distributions of JupyterHub. If all of the resources you need will fit on a single VM, then
[The Littlest JupyterHub](https://tljh.jupyter.org) should get you up-and-running within
a half day or so. For more complex setups, such as scalable Kubernetes clusters or access
to high-performance computing and data, it will require more time and expertise with
the technologies your JupyterHub will use (e.g., dev-ops knowledge with cloud computing).
In general, the base JupyterHub deployment is not the bottleneck for setup, it is connecting
your JupyterHub with the various services and tools that you wish to provide to your users.
### How well does JupyterHub scale? What are JupyterHub's limitations?
JupyterHub works well at both a small scale (e.g., a single VM or machine) as well as a
high scale (e.g., a scalable Kubernetes cluster). It can be used for teams as small a 2, and
for user bases as large as 10,000. The scalability of JupyterHub largely depends on the
infrastructure on which it is deployed. JupyterHub has been designed to be lightweight and
flexible, so you can tailor your JupyterHub deployment to your needs.
### Is JupyterHub resilient? What happens when a machine goes down?
For JupyterHubs that are deployed in a containerized environment (e.g., Kubernetes), it is
possible to configure the JupyterHub to be fairly resistant to failures in the system.
For example, if JupyterHub fails, then user sessions will not be affected (though new
users will not be able to log in). When a JupyterHub process is restarted, it should
seamlessly connect with the user database and the system will return to normal.
Again, the details of your JupyterHub deployment (e.g., whether it's deployed on a scalable cluster)
will affect the resiliency of the deployment.
### What interfaces does JupyterHub support?
Out of the box, JupyterHub supports a variety of popular data science interfaces for user sessions,
such as JupyterLab, Jupyter Notebooks, and RStudio. Any interface that can be served
via a web address can be served with a JupyterHub (with the right setup).
### Does JupyterHub make it easier for our team to collaborate?
JupyterHub provides a standardized environment and access to shared resources for your teams.
This greatly reduces the cost associated with sharing analyses and content with other team
members, and makes it easier to collaborate and build off of one another's ideas. Combined with
access to high-performance computing and data, JupyterHub provides a common resource to
amplify your team's ability to prototype their analyses, scale them to larger data, and then
share their results with one another.
JupyterHub also provides a computational framework to share computational narratives between
different levels of an organization. For example, data scientists can share Jupyter Notebooks
rendered as [voila dashboards](https://voila.readthedocs.io/en/stable/) with those who are not
familiar with programming, or create publicly-available interactive analyses to allow others to
interact with your work.
### Can I use JupyterHub with R/RStudio or other languages and environments?
Yes, Jupyter is a polyglot project, and there are over 40 community-provided kernels for a variety
of languages (the most common being Python, Julia, and R). You can also use a JupyterHub to provide
access to other interfaces, such as RStudio, that provide their own access to a language kernel.

View File

@@ -41,7 +41,7 @@ port.
## Set the Proxy's REST API communication URL (optional)
By default, this REST API listens on port 8001 of `localhost` only.
By default, this REST API listens on port 8081 of `localhost` only.
The Hub service talks to the proxy via a REST API on a secondary port. The
API URL can be configured separately and override the default settings.

View File

@@ -124,7 +124,7 @@ hex-encoded string. You can set it this way:
.. code-block:: bash
export JPY_COOKIE_SECRET=$(openssl rand -hex 32)
export JPY_COOKIE_SECRET=`openssl rand -hex 32`
For security reasons, this environment variable should only be visible to the
Hub. If you set it dynamically as above, all users will be logged out each time
@@ -173,7 +173,7 @@ using the ``CONFIGPROXY_AUTH_TOKEN`` environment variable:
.. code-block:: bash
export CONFIGPROXY_AUTH_TOKEN=$(openssl rand -hex 32)
export CONFIGPROXY_AUTH_TOKEN='openssl rand -hex 32'
This environment variable needs to be visible to the Hub and Proxy.

View File

@@ -3,9 +3,9 @@
When working with JupyterHub, a **Service** is defined as a process
that interacts with the Hub's REST API. A Service may perform a specific
or action or task. For example, shutting down individuals' single user
notebook servers that have been idle for some time is a good example of
a task that could be automated by a Service. Let's look at how the
[cull_idle_servers][] script can be used as a Service.
notebook servers that have been is a good example of a task that could
be automated by a Service. Let's look at how the [cull_idle_servers][]
script can be used as a Service.
## Real-world example to cull idle servers
@@ -14,7 +14,7 @@ document will:
- explain some basic information about API tokens
- clarify that API tokens can be used to authenticate to
single-user servers as of [version 0.8.0](../changelog)
single-user servers as of [version 0.8.0](../changelog.html)
- show how the [cull_idle_servers][] script can be:
- used in a Hub-managed service
- run as a standalone script
@@ -29,14 +29,14 @@ Hub via the REST API.
To run such an external service, an API token must be created and
provided to the service.
As of [version 0.6.0](../changelog), the preferred way of doing
As of [version 0.6.0](../changelog.html), the preferred way of doing
this is to first generate an API token:
```bash
openssl rand -hex 32
```
In [version 0.8.0](../changelog), a TOKEN request page for
In [version 0.8.0](../changelog.html), a TOKEN request page for
generating an API token is available from the JupyterHub user interface:
![Request API TOKEN page](../images/token-request.png)
@@ -88,7 +88,7 @@ c.JupyterHub.services = [
{
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, 'cull_idle_servers.py', '--timeout=3600'],
'command': 'python3 cull_idle_servers.py --timeout=3600'.split(),
}
]
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -1,15 +0,0 @@
=====
About
=====
JupyterHub is an open source project and community. It is a part of the
`Jupyter Project <https://jupyter.org>`_. JupyterHub is an open and inclusive
community, and invites contributions from anyone. This section covers information
about our community, as well as ways that you can connect and get involved.
.. toctree::
:maxdepth: 1
contributor-list
changelog
gallery-jhub-deployments

View File

@@ -1,13 +0,0 @@
=====================
Administrator's Guide
=====================
This guide covers best-practices, tips, common questions and operations, as
well as other information relevant to running your own JupyterHub over time.
.. toctree::
:maxdepth: 2
troubleshooting
admin/upgrading
changelog

View File

@@ -1,38 +1,21 @@
==========
JupyterHub
==========
`JupyterHub`_ is the best way to serve `Jupyter notebook`_ for multiple users.
It can be used in a classes of students, a corporate data science group or scientific
research group. It is a multi-user **Hub** that spawns, manages, and proxies multiple
`JupyterHub`_, a multi-user **Hub**, spawns, manages, and proxies multiple
instances of the single-user `Jupyter notebook`_ server.
JupyterHub can be used to serve notebooks to a class of students, a corporate
data science group, or a scientific research group.
To make life easier, JupyterHub have distributions. Be sure to
take a look at them before continuing with the configuration of the broad
original system of `JupyterHub`_. Today, you can find two main cases:
1. If you need a simple case for a small amount of users (0-100) and single server
take a look at
`The Littlest JupyterHub <https://github.com/jupyterhub/the-littlest-jupyterhub>`__ distribution.
2. If you need to allow for even more users, a dynamic amount of servers can be used on a cloud,
take a look at the `Zero to JupyterHub with Kubernetes <https://github.com/jupyterhub/zero-to-jupyterhub-k8s>`__ .
Four subsystems make up JupyterHub:
* a **Hub** (tornado process) that is the heart of JupyterHub
* a **configurable http proxy** (node-http-proxy) that receives the requests from the client's browser
* multiple **single-user Jupyter notebook servers** (Python/IPython/tornado) that are monitored by Spawners
* an **authentication class** that manages how users can access the system
Besides these central pieces, you can add optional configurations through a `config.py` file and manage users kernels on an admin panel. A simplification of the whole system can be seen in the figure below:
.. image:: images/jhub-fluxogram.jpeg
.. image:: images/jhub-parts.png
:alt: JupyterHub subsystems
:width: 80%
:align: center
:width: 40%
:align: right
Three subsystems make up JupyterHub:
* a multi-user **Hub** (tornado process)
* a **configurable http proxy** (node-http-proxy)
* multiple **single-user Jupyter notebook servers** (Python/IPython/tornado)
JupyterHub performs the following functions:
@@ -45,106 +28,98 @@ JupyterHub performs the following functions:
For convenient administration of the Hub, its users, and services,
JupyterHub also provides a `REST API`_.
The JupyterHub team and Project Jupyter value our community, and JupyterHub
follows the Jupyter `Community Guides <https://jupyter.readthedocs.io/en/latest/community/content-community.html>`_.
Contents
========
--------
.. _index/distributions:
**Installation Guide**
Distributions
-------------
* :doc:`installation-guide`
* :doc:`quickstart`
* :doc:`quickstart-docker`
* :doc:`installation-basics`
A JupyterHub **distribution** is tailored towards a particular set of
use cases. These are generally easier to set up than setting up
JupyterHub from scratch, assuming they fit your use case.
**Getting Started**
The two popular ones are:
* :doc:`getting-started/index`
* :doc:`getting-started/config-basics`
* :doc:`getting-started/networking-basics`
* :doc:`getting-started/security-basics`
* :doc:`getting-started/authenticators-users-basics`
* :doc:`getting-started/spawners-basics`
* :doc:`getting-started/services-basics`
* `Zero to JupyterHub on Kubernetes <http://z2jh.jupyter.org>`_, for
running JupyterHub on top of `Kubernetes <https://k8s.io>`_. This
can scale to large number of machines & users.
* `The Littlest JupyterHub <http://tljh.jupyter.org>`_, for an easy
to set up & run JupyterHub supporting 1-100 users on a single machine.
**Technical Reference**
Installation Guide
------------------
* :doc:`reference/index`
* :doc:`reference/technical-overview`
* :doc:`reference/websecurity`
* :doc:`reference/authenticators`
* :doc:`reference/spawners`
* :doc:`reference/services`
* :doc:`reference/rest`
* :doc:`reference/upgrading`
* :doc:`reference/templates`
* :doc:`reference/config-user-env`
* :doc:`reference/config-examples`
* :doc:`reference/config-ghoauth`
* :doc:`reference/config-proxy`
* :doc:`reference/config-sudo`
.. toctree::
:maxdepth: 2
**API Reference**
installation-guide
* :doc:`api/index`
Getting Started
---------------
**Tutorials**
.. toctree::
:maxdepth: 2
* :doc:`tutorials/index`
* :doc:`tutorials/upgrade-dot-eight`
* `Zero to JupyterHub with Kubernetes <https://zero-to-jupyterhub.readthedocs.io/en/latest/>`_
getting-started/index
**Troubleshooting**
Technical Reference
-------------------
* :doc:`troubleshooting`
.. toctree::
:maxdepth: 2
**About JupyterHub**
reference/index
* :doc:`contributor-list`
* :doc:`gallery-jhub-deployments`
Administrators guide
--------------------
**Changelog**
.. toctree::
:maxdepth: 2
index-admin
API Reference
-------------
.. toctree::
:maxdepth: 2
api/index
Contributing
------------
We want you to contribute to JupyterHub in ways that are most exciting
& useful to you. We value documentation, testing, bug reporting & code equally,
and are glad to have your contributions in whatever form you wish :)
Our `Code of Conduct <https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md>`_
(`reporting guidelines <https://github.com/jupyter/governance/blob/master/conduct/reporting_online.md>`_)
helps keep our community welcoming to as many people as possible.
.. toctree::
:maxdepth: 2
contributing/index
About JupyterHub
----------------
.. toctree::
:maxdepth: 2
index-about
* :doc:`changelog`
Indices and tables
==================
------------------
* :ref:`genindex`
* :ref:`modindex`
Questions? Suggestions?
=======================
-----------------------
- `Jupyter mailing list <https://groups.google.com/forum/#!forum/jupyter>`_
- `Jupyter website <https://jupyter.org>`_
.. _contents:
Full Table of Contents
----------------------
.. toctree::
:maxdepth: 2
installation-guide
getting-started/index
reference/index
api/index
tutorials/index
troubleshooting
contributor-list
gallery-jhub-deployments
changelog
.. _JupyterHub: https://github.com/jupyterhub/jupyterhub
.. _Jupyter notebook: https://jupyter-notebook.readthedocs.io/en/latest/
.. _REST API: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default

View File

@@ -6,7 +6,7 @@ JupyterHub is supported on Linux/Unix based systems. To use JupyterHub, you need
a Unix server (typically Linux) running somewhere that is accessible to your
team on the network. The JupyterHub server can be on an internal network at your
organization, or it can run on the public internet (in which case, take care
with the Hub's [security](./getting-started/security-basics)).
with the Hub's [security](./security-basics.html)).
JupyterHub officially **does not** support Windows. You may be able to use
JupyterHub on Windows if you use a Spawner and Authenticator that work on
@@ -28,7 +28,7 @@ Prior to beginning installation, it's helpful to consider some of the following:
- Spawner of singleuser notebook servers (Docker, Batch, etc.)
- Services (nbgrader, etc.)
- JupyterHub database (default SQLite; traditional RDBMS such as PostgreSQL,)
MySQL, or other databases supported by [SQLAlchemy](http://www.sqlalchemy.org))
MySQL, or other databases supported by [SQLAlchemy](http://www.sqlalchemy.org))
## Folders and File Locations

View File

@@ -1,9 +1,5 @@
Installation
============
These sections cover how to get up-and-running with JupyterHub. They cover
some basics of the tools needed to deploy JupyterHub as well as how to get it
running on your own infrastructure.
Installation Guide
==================
.. toctree::
:maxdepth: 3

View File

@@ -1,52 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
mQINBFMx2LoBEAC9xU8JiKI1VlCJ4PT9zqhU5nChQZ06/bj1BBftiMJG07fdGVO0
ibOn4TrCoRYaeRlet0UpHzxT4zDa5h3/usJaJNTSRwtWePw2o7Lik8J+F3LionRf
8Jz81WpJ+81Klg4UWKErXjBHsu/50aoQm6ZNYG4S2nwOmMVEC4nc44IAA0bb+6kW
saFKKzEDsASGyuvyutdyUHiCfvvh5GOC2h9mXYvl4FaMW7K+d2UgCYERcXDNy7C1
Bw+uepQ9ELKdG4ZpvonO6BNr1BWLln3wk93AQfD5qhfsYRJIyj0hJlaRLtBU3i6c
xs+gQNF4mPmybpPSGuOyUr4FYC7NfoG7IUMLj+DYa6d8LcMJO+9px4IbdhQvzGtC
qz5av1TX7/+gnS4L8C9i1g8xgI+MtvogngPmPY4repOlK6y3l/WtxUPkGkyYkn3s
RzYyE/GJgTwuxFXzMQs91s+/iELFQq/QwmEJf+g/QYfSAuM+lVGajEDNBYVAQkxf
gau4s8Gm0GzTZmINilk+7TxpXtKbFc/Yr4A/fMIHmaQ7KmJB84zKwONsQdVv7Jjj
0dpwu8EIQdHxX3k7/Q+KKubEivgoSkVwuoQTG15X9xrOsDZNwfOVQh+JKazPvJtd
SNfep96r9t/8gnXv9JI95CGCQ8lNhXBUSBM3BDPTbudc4b6lFUyMXN0mKQARAQAB
tCxJUHl0aG9uIFNlY3VyaXR5IFRlYW0gPHNlY3VyaXR5QGlweXRob24ub3JnPokC
OAQTAQIAIgUCUzHYugIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQEwJc
LcmZYkjuXg//R/t6nMNQmf9W1h52IVfUbRAVmvZ5d063hQHKV2dssxtnA2dRm/x5
JZu8Wz7ZrEZpyqwRJO14sxN1/lC3v+zs9XzYXr2lBTZuKCPIBypYVGIynCuWJBQJ
rWnfG4+u1RHahnjqlTWTY1C/le6v7SjAvCb6GbdA6k4ZL2EJjQlRaHDmzw3rV/+l
LLx6/tYzIsotuflm/bFumyOMmpQQpJjnCkWIVjnRICZvuAn97jLgtTI0+0Rzf4Zb
k2BwmHwDRqWCTTcRI9QvTl8AzjW+dNImN22TpGOBPfYj8BCZ9twrpKUbf+jNqJ1K
THQzFtpdJ6SzqiFVm74xW4TKqCLkbCQ/HtVjTGMGGz/y7KTtaLpGutQ6XE8SSy6P
EffSb5u+kKlQOWaH7Mc3B0yAojz6T3j5RSI8ts6pFi6pZhDg9hBfPK2dT0v/7Mkv
E1Z7q2IdjZnhhtGWjDAMtDDn2NbY2wuGoa5jAWAR0WvIbEZ3kOxuLE5/ZOG1FyYm
noJRliBz7038nT92EoD5g1pdzuxgXtGCpYyyjRZwaLmmi4CvA+oThKmnqWNY5lyY
ricdNHDiyEXK0YafJL1oZgM86MSb0jKJMp5U11nUkUGzkroFfpGDmzBwAzEPgeiF
40+qgsKB9lqwb3G7PxvfSi3XwxfXgpm1cTyEaPSzsVzve3d1xeqb7Yq5Ag0EUzHY
ugEQALQ5FtLdNoxTxMsgvrRr1ejLiUeRNUfXtN1TYttOfvAhfBVnszjtkpIW8DCB
JF/bA7ETiH8OYYn/Fm6MPI5H64IHEncpzxjf57jgpXd9CA9U2OMk/P1nve5zYchP
QmP2fJxeAWr0aRH0Mse5JS5nCkh8Xv4nAjsBYeLTJEVOb1gPQFXOiFcVp3gaKAzX
GWOZ/mtG/uaNsabH/3TkcQQEgJefd11DWgMB7575GU+eME7c6hn3FPITA5TC5HUX
azvjv/PsWGTTVAJluJ3fUDvhpbGwYOh1uV0rB68lPpqVIro18IIJhNDnccM/xqko
4fpJdokdg4L1wih+B04OEXnwgjWG8OIphR/oL/+M37VV2U7Om/GE6LGefaYccC9c
tIaacRQJmZpG/8RsimFIY2wJ07z8xYBITmhMmOt0bLBv0mU0ym5KH9Dnru1m9QDO
AHwcKrDgL85f9MCn+YYw0d1lYxjOXjf+moaeW3izXCJ5brM+MqVtixY6aos3YO29
J7SzQ4aEDv3h/oKdDfZny21jcVPQxGDui8sqaZCi8usCcyqWsKvFHcr6vkwaufcm
3Knr2HKVotOUF5CDZybopIz1sJvY/5Dx9yfRmtivJtglrxoDKsLi1rQTlEQcFhCS
ACjf7txLtv03vWHxmp4YKQFkkOlbyhIcvfPVLTvqGerdT2FHABEBAAGJAh8EGAEC
AAkFAlMx2LoCGwwACgkQEwJcLcmZYkgK0BAAny0YUugpZldiHzYNf8I6p2OpiDWv
ZHaguTTPg2LJSKaTd+5UHZwRFIWjcSiFu+qTGLNtZAdcr0D5f991CPvyDSLYgOwb
Jm2p3GM2KxfECWzFbB/n/PjbZ5iky3+5sPlOdBR4TkfG4fcu5GwUgCkVe5u3USAk
C6W5lpeaspDz39HAPRSIOFEX70+xV+6FZ17B7nixFGN+giTpGYOEdGFxtUNmHmf+
waJoPECyImDwJvmlMTeP9jfahlB6Pzaxt6TBZYHetI/JR9FU69EmA+XfCSGt5S+0
Eoc330gpsSzo2VlxwRCVNrcuKmG7PsFFANok05ssFq1/Djv5rJ++3lYb88b8HSP2
3pQJPrM7cQNU8iPku9yLXkY5qsoZOH+3yAia554Dgc8WBhp6fWh58R0dIONQxbbo
apNdwvlI8hKFB7TiUL6PNShE1yL+XD201iNkGAJXbLMIC1ImGLirUfU267A3Cop5
hoGs179HGBcyj/sKA3uUIFdNtP+NndaP3v4iYhCitdVCvBJMm6K3tW88qkyRGzOk
4PW422oyWKwbAPeMk5PubvEFuFAIoBAFn1zecrcOg85RzRnEeXaiemmmH8GOe1Xu
Kh+7h8XXyG6RPFy8tCcLOTk+miTqX+4VWy+kVqoS2cQ5IV8WsJ3S7aeIy0H89Z8n
5vmLc+Ibz+eT+rM=
=XVDe
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -25,7 +25,7 @@ Starting JupyterHub with docker
The JupyterHub docker image can be started with the following command::
docker run -d -p 8000:8000 --name jupyterhub jupyterhub/jupyterhub jupyterhub
docker run -d --name jupyterhub jupyterhub/jupyterhub jupyterhub
This command will create a container named ``jupyterhub`` that you can
**stop and resume** with ``docker stop/start``.

View File

@@ -5,8 +5,8 @@ Hub and single user notebook servers.
## The default PAM Authenticator
JupyterHub ships with the default [PAM][]-based Authenticator, for
logging in with local user accounts via a username and password.
JupyterHub ships only with the default [PAM][]-based Authenticator,
for logging in with local user accounts via a username and password.
## The OAuthenticator
@@ -34,17 +34,12 @@ popular services:
A generic implementation, which you can use for OAuth authentication
with any provider, is also available.
## The Dummy Authenticator
When testing, it may be helpful to use the
:class:`~jupyterhub.auth.DummyAuthenticator`. This allows for any username and
password unless if a global password has been set. Once set, any username will
still be accepted but the correct password will need to be provided.
## Additional Authenticators
A partial list of other authenticators is available on the
[JupyterHub wiki](https://github.com/jupyterhub/jupyterhub/wiki/Authenticators).
- ldapauthenticator for LDAP
- tmpauthenticator for temporary accounts
- For Shibboleth, [jhub_shibboleth_auth](https://github.com/gesiscss/jhub_shibboleth_auth)
and [jhub_remote_user_authenticator](https://github.com/cwaldbieser/jhub_remote_user_authenticator)
## Technical Overview of Authentication
@@ -75,6 +70,7 @@ Writing an Authenticator that looks up passwords in a dictionary
requires only overriding this one method:
```python
from tornado import gen
from IPython.utils.traitlets import Dict
from jupyterhub.auth import Authenticator
@@ -84,7 +80,8 @@ class DictionaryAuthenticator(Authenticator):
help="""dict of username:password for authentication"""
)
async def authenticate(self, handler, data):
@gen.coroutine
def authenticate(self, handler, data):
if self.passwords.get(data['username']) == data['password']:
return data['username']
```
@@ -106,16 +103,6 @@ c.Authenticator.username_map = {
}
```
When using `PAMAuthenticator`, you can set
`c.PAMAuthenticator.pam_normalize_username = True`, which will
normalize usernames using PAM (basically round-tripping them: username
to uid to username), which is useful in case you use some external
service that allows multiple usernames mapping to the same user (such
as ActiveDirectory, yes, this really happens). When
`pam_normalize_username` is on, usernames are *not* normalized to
lowercase.
#### Validate usernames
In most cases, there is a very limited set of acceptable usernames.
@@ -151,41 +138,6 @@ See a list of custom Authenticators [on the wiki](https://github.com/jupyterhub/
If you are interested in writing a custom authenticator, you can read
[this tutorial](http://jupyterhub-tutorial.readthedocs.io/en/latest/authenticators.html).
### Registering custom Authenticators via entry points
As of JupyterHub 1.0, custom authenticators can register themselves via
the `jupyterhub.authenticators` entry point metadata.
To do this, in your `setup.py` add:
```python
setup(
...
entry_points={
'jupyterhub.authenticators': [
'myservice = mypackage:MyAuthenticator',
],
},
)
```
If you have added this metadata to your package,
users can select your authenticator with the configuration:
```python
c.JupyterHub.authenticator_class = 'myservice'
```
instead of the full
```python
c.JupyterHub.authenticator_class = 'mypackage:MyAuthenticator'
```
previously required.
Additionally, configurable attributes for your authenticator will
appear in jupyterhub help output and auto-generated configuration files
via `jupyterhub --generate-config`.
### Authentication state

View File

@@ -17,12 +17,10 @@ satisfy the following:
Let's start out with needed JupyterHub configuration in `jupyterhub_config.py`:
```python
# Force the proxy to only listen to connections to 127.0.0.1 (on port 8000)
c.JupyterHub.bind_url = 'http://127.0.0.1:8000'
# Force the proxy to only listen to connections to 127.0.0.1
c.JupyterHub.ip = '127.0.0.1'
```
(For Jupyterhub < 0.9 use `c.JupyterHub.ip = '127.0.0.1'`.)
For high-quality SSL configuration, we also generate Diffie-Helman parameters.
This can take a few minutes:
@@ -192,23 +190,3 @@ Listen 443
</Location>
</VirtualHost>
```
In case of the need to run the jupyterhub under /jhub/ or other location please use the below configurations:
- JupyterHub running locally at http://127.0.0.1:8000/jhub/ or other location
httpd.conf amendments:
```bash
RewriteRule /jhub/(.*) ws://127.0.0.1:8000/jhub/$1 [P,L]
RewriteRule /jhub/(.*) http://127.0.0.1:8000/jhub/$1 [P,L]
ProxyPass /jhub/ http://127.0.0.1:8000/jhub/
ProxyPassReverse /jhub/ http://127.0.0.1:8000/jhub/
```
jupyterhub_config.py amendments:
```bash
--The public facing URL of the whole JupyterHub application.
--This is the address on which the proxy will bind. Sets protocol, ip, base_url
c.JupyterHub.bind_url = 'http://127.0.0.1:8000/jhub/'
```

View File

@@ -37,7 +37,7 @@ Next, you will need [sudospawner](https://github.com/jupyter/sudospawner)
to enable monitoring the single-user servers with sudo:
```bash
sudo python3 -m pip install sudospawner
sudo pip install sudospawner
```
Now we have to configure sudo to allow the Hub user (`rhea`) to launch
@@ -204,8 +204,8 @@ The simplest way to deal with this is to make a directory owned by your Hub user
and use that as the CWD when launching the server.
```bash
$ sudo mkdir /etc/jupyterhub
$ sudo chown rhea /etc/jupyterhub
$ sudo mkdir /etc/jupyterhub
$ sudo chown rhea /etc/jupyterhub
```
## Start jupyterhub
@@ -213,20 +213,20 @@ $ sudo chown rhea /etc/jupyterhub
Finally, start the server as our newly configured user, `rhea`:
```bash
$ cd /etc/jupyterhub
$ sudo -u rhea jupyterhub --JupyterHub.spawner_class=sudospawner.SudoSpawner
```
$ cd /etc/jupyterhub
$ sudo -u rhea jupyterhub --JupyterHub.spawner_class=sudospawner.SudoSpawner
```
And try logging in.
## Troubleshooting: SELinux
### Troubleshooting: SELinux
If you still get a generic `Permission denied` `PermissionError`, it's possible SELinux is blocking you.
Here's how you can make a module to allow this.
First, put this in a file named `sudo_exec_selinux.te`:
First, put this in a file sudo_exec_selinux.te:
```bash
module sudo_exec_selinux 1.1;
module sudo_exec 1.1;
require {
type unconfined_t;
@@ -246,9 +246,9 @@ $ semodule_package -o sudo_exec_selinux.pp -m sudo_exec_selinux.mod
$ semodule -i sudo_exec_selinux.pp
```
## Troubleshooting: PAM session errors
### Troubleshooting: PAM session errors
If the PAM authentication doesn't work and you see errors for
`login:session-auth`, or similar, considering updating to a more recent version
of jupyterhub and disabling the opening of PAM sessions with
`c.PAMAuthenticator.open_sessions=False`.
`login:session-auth`, or similar, considering updating to `master`
and/or incorporating this commit https://github.com/jupyter/jupyterhub/commit/40368b8f555f04ffdd662ffe99d32392a088b1d2
and configuration option, `c.PAMAuthenticator.open_sessions = False`.

View File

@@ -120,7 +120,7 @@ sure are available, I can install their specs system-wide (in /usr/local) with:
```
## Multi-user hosts vs. Containers
## Multi-user hosts vs. Containers
There are two broad categories of user environments that depend on what
Spawner you choose:
@@ -145,37 +145,3 @@ In both cases, you want to *avoid putting configuration in user home
directories* because users can change those configuration settings. Also,
home directories typically persist once they are created, so they are
difficult for admins to update later.
## Named servers
By default, in a JupyterHub deployment each user has exactly one server.
JupyterHub can, however, have multiple servers per user.
This is most useful in deployments where users can configure the environment
in which their server will start (e.g. resource requests on an HPC cluster),
so that a given user can have multiple configurations running at the same time,
without having to stop and restart their one server.
To allow named servers:
```python
c.JupyterHub.allow_named_servers = True
```
Named servers were implemented in the REST API in JupyterHub 0.8,
and JupyterHub 1.0 introduces UI for managing named servers via the user home page:
![named servers on the home page](../images/named-servers-home.png)
as well as the admin page:
![named servers on the admin page](../images/named-servers-admin.png)
Named servers can be accessed, created, started, stopped, and deleted
from these pages. Activity tracking is now per-server as well.
The number of named servers per user can be limited by setting
```python
c.JupyterHub.named_server_limit_per_user = 5
```

View File

@@ -1,24 +1,19 @@
Technical Reference
===================
This section covers more of the details of the JupyterHub architecture, as well as
what happens under-the-hood when you deploy and configure your JupyterHub.
.. toctree::
:maxdepth: 2
technical-overview
urls
websecurity
authenticators
spawners
services
proxy
separate-proxy
rest
database
upgrading
templates
../events/index
config-user-env
config-examples
config-ghoauth

View File

@@ -19,7 +19,7 @@ In general, for a proxy to be usable by JupyterHub, it must:
1. support websockets without prior knowledge of the URL where websockets may
occur
2. support trie-based routing (i.e. allow different routes on `/foo` and
2. support trie-based routing (i.e. allow different routes on `/foo` and
`/foo/bar` and route based on specificity)
3. adding or removing a route should not cause existing connections to drop
@@ -45,12 +45,15 @@ If your proxy should be launched when the Hub starts, you must define how
to start and stop your proxy:
```python
from tornado import gen
class MyProxy(Proxy):
...
async def start(self):
@gen.coroutine
def start(self):
"""Start the proxy"""
async def stop(self):
@gen.coroutine
def stop(self):
"""Stop the proxy"""
```
@@ -59,18 +62,6 @@ These methods **may** be coroutines.
`c.Proxy.should_start` is a configurable flag that determines whether the
Hub should call these methods when the Hub itself starts and stops.
## Encryption
When using `internal_ssl` to encrypt traffic behind the proxy, at minimum,
your `Proxy` will need client ssl certificates which the `Hub` must be made
aware of. These can be generated with the command `jupyterhub --generate-certs`
which will write them to the `internal_certs_location` in folders named
`proxy_api` and `proxy_client`. Alternatively, these can be provided to the
hub via the `jupyterhub_config.py` file by providing a `dict` of named paths
to the `external_authorities` option. The hub will include all certificates
provided in that `dict` in the trust bundle utilized by all internal
components.
### Purely external proxies
Probably most custom proxies will be externally managed,
@@ -102,14 +93,15 @@ route to be proxied, such as `/user/name/`. A routespec will:
### Adding a route
When adding a route, JupyterHub may pass a JSON-serializable dict as a `data`
argument that should be attached to the proxy route. When that route is
argument that should be attacked to the proxy route. When that route is
retrieved, the `data` argument should be returned as well. If your proxy
implementation doesn't support storing data attached to routes, then your
Python wrapper may have to handle storing the `data` piece itself, e.g in a
simple file or database.
```python
async def add_route(self, routespec, target, data):
@gen.coroutine
def add_route(self, routespec, target, data):
"""Proxy `routespec` to `target`.
Store `data` associated with the routespec
@@ -120,7 +112,7 @@ async def add_route(self, routespec, target, data):
Adding a route for a user looks like this:
```python
await proxy.add_route('/user/pgeorgiou/', 'http://127.0.0.1:1227',
proxy.add_route('/user/pgeorgiou/', 'http://127.0.0.1:1227',
{'user': 'pgeorgiou'})
```
@@ -130,7 +122,8 @@ await proxy.add_route('/user/pgeorgiou/', 'http://127.0.0.1:1227',
`delete_route` should still succeed, but a warning may be issued.
```python
async def delete_route(self, routespec):
@gen.coroutine
def delete_route(self, routespec):
"""Delete the route"""
```
@@ -142,7 +135,8 @@ routes. The return value for this function should be a dictionary, keyed by
`add_route` (`routespec`, `target`, `data`)
```python
async def get_all_routes(self):
@gen.coroutine
def get_all_routes(self):
"""Return all routes, keyed by routespec"""
```
@@ -185,38 +179,3 @@ tracked, and services such as cull-idle will not work.
Now that `notebook-5.0` tracks activity internally, we can retrieve activity
information from the single-user servers instead, removing the need to track
activity in the proxy. But this is not yet implemented in JupyterHub 0.8.0.
### Registering custom Proxies via entry points
As of JupyterHub 1.0, custom proxy implementations can register themselves via
the `jupyterhub.proxies` entry point metadata.
To do this, in your `setup.py` add:
```python
setup(
...
entry_points={
'jupyterhub.proxies': [
'mything = mypackage:MyProxy',
],
},
)
```
If you have added this metadata to your package,
users can select your proxy with the configuration:
```python
c.JupyterHub.proxy_class = 'mything'
```
instead of the full
```python
c.JupyterHub.proxy_class = 'mypackage:MyProxy'
```
previously required.
Additionally, configurable attributes for your proxy will
appear in jupyterhub help output and auto-generated configuration files
via `jupyterhub --generate-config`.

View File

@@ -1,14 +0,0 @@
:orphan:
===================
JupyterHub REST API
===================
.. this doc exists as a resolvable link target
.. which _static files are not
.. meta::
:http-equiv=refresh: 0;url=../_static/rest-api/index.html
The rest API docs are `here <../_static/rest-api/index.html>`_
if you are not redirected automatically.

View File

@@ -27,7 +27,7 @@ Hub.
To send requests using JupyterHub API, you must pass an API token with
the request.
As of [version 0.6.0](../changelog.md), the preferred way of
As of [version 0.6.0](../changelog.html), the preferred way of
generating an API token is:
```bash
@@ -48,7 +48,7 @@ jupyterhub token <username>
This command generates a random string to use as a token and registers
it for the given user with the Hub's database.
In [version 0.8.0](../changelog.md), a TOKEN request page for
In [version 0.8.0](../changelog.html), a TOKEN request page for
generating an API token is available from the JupyterHub user interface:
![Request API TOKEN page](../images/token-request.png)
@@ -138,8 +138,8 @@ First you must enable named-servers by including the following setting in the `j
`c.JupyterHub.allow_named_servers = True`
If using the [zero-to-jupyterhub-k8s](https://github.com/jupyterhub/zero-to-jupyterhub-k8s) set-up to run JupyterHub,
then instead of editing the `jupyterhub_config.py` file directly, you could pass
If using the [zero-to-jupyterhub-k8s](https://github.com/jupyterhub/zero-to-jupyterhub-k8s) set-up to run JupyterHub,
then instead of editing the `jupyterhub_config.py` file directly, you could pass
the following as part of the `config.yaml` file, as per the [tutorial](https://zero-to-jupyterhub.readthedocs.io/en/latest/):
```bash
@@ -158,6 +158,11 @@ The same servers can be stopped by substituting `DELETE` for `POST` above.
### Some caveats for using named-servers
The named-server capabilities are not fully implemented for JupyterHub as yet.
While it's possible to start/stop a server via the API, the UI on the
JupyterHub control-panel has not been implemented, and so it may not be obvious
to those viewing the panel that a named-server may be running for a given user.
For named-servers via the API to work, the spawner used to spawn these servers
will need to be able to handle the case of multiple servers per user and ensure
uniqueness of names, particularly if servers are spawned via docker containers
@@ -173,5 +178,5 @@ Note: The Swagger specification is being renamed the [OpenAPI Initiative][].
[interactive style on swagger's petstore]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default
[OpenAPI Initiative]: https://www.openapis.org/
[JupyterHub REST API]: ./rest-api
[JupyterHub REST API]: ../_static/rest-api/index.html
[Jupyter Notebook REST API]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml

View File

@@ -1,80 +0,0 @@
# Running proxy separately from the hub
## Background
The thing which users directly connect to is the proxy, by default
`configurable-http-proxy`. The proxy either redirects users to the
hub (for login and managing servers), or to their own single-user
servers. Thus, as long as the proxy stays running, access to existing
servers continues, even if the hub itself restarts or goes down.
When you first configure the hub, you may not even realize this
because the proxy is automatically managed by the hub. This is great
for getting started and even most use, but everytime you restart the
hub, all user connections also get restarted. But it's also simple to
run the proxy as a service separate from the hub, so that you are free
to reconfigure the hub while only interrupting users who are currently
actively starting the hub.
The default JupyterHub proxy is
[configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy),
and that page has some docs. If you are using a different proxy, such
as Traefik, these instructions are probably not relevant to you.
## Configuration options
`c.JupyterHub.cleanup_servers = False` should be set, which tells the
hub to not stop servers when the hub restarts (this is useful even if
you don't run the proxy separately).
`c.ConfigurableHTTPProxy.should_start = False` should be set, which
tells the hub that the proxy should not be started (because you start
it yourself).
`c.ConfigurableHTTPProxy.auth_token = "CONFIGPROXY_AUTH_TOKEN"` should be set to a
token for authenticating communication with the proxy.
`c.ConfigurableHTTPProxy.api_url = 'http://localhost:8001'` should be
set to the URL which the hub uses to connect *to the proxy's API*.
## Proxy configuration
You need to configure a service to start the proxy. An example
command line for this is `configurable-http-proxy --ip=127.0.0.1
--port=8000 --api-ip=127.0.0.1 --api-port=8001
--default-target=http://localhost:8081
--error-target=http://localhost:8081/hub/error`. (Details for how to
do this is out of scope for this tutorial - for example it might be a
systemd service on within another docker cotainer). The proxy has no
configuration files, all configuration is via the command line and
environment variables.
`--api-ip` and `--api-port` (which tells the proxy where to listen) should match the hub's `ConfigurableHTTPProxy.api_url`.
`--ip`, `-port`, and other options configure the *user* connections to the proxy.
`--default-target` and `--error-target` should point to the hub, and used when users navigate to the proxy originally.
You must define the environment variable `CONFIGPROXY_AUTH_TOKEN` to
match the token given to `c.ConfigurableHTTPProxy.auth_token`.
You should check the [configurable-http-proxy
options](https://github.com/jupyterhub/configurable-http-proxy) to see
what other options are needed, for example SSL options. Note that
these are configured in the hub if the hub is starting the proxy - you
need to move the options to here.
## Docker image
You can use [jupyterhub configurable-http-proxy docker
image](https://hub.docker.com/r/jupyterhub/configurable-http-proxy/)
to run the proxy.
## See also
* [jupyterhub configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy)

View File

@@ -93,7 +93,7 @@ c.JupyterHub.services = [
{
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, '/path/to/cull-idle.py', '--timeout']
'command': ['python', '/path/to/cull-idle.py', '--timeout']
}
]
```
@@ -249,7 +249,7 @@ prefix = os.environ.get('JUPYTERHUB_SERVICE_PREFIX', '/')
auth = HubAuth(
api_token=os.environ['JUPYTERHUB_API_TOKEN'],
cache_max_age=60,
cookie_cache_max_age=60,
)
app = Flask(__name__)

View File

@@ -10,7 +10,6 @@ and a custom Spawner needs to be able to take three actions:
## Examples
Custom Spawners for JupyterHub can be found on the [JupyterHub wiki](https://github.com/jupyterhub/jupyterhub/wiki/Spawners).
Some examples include:
@@ -25,8 +24,6 @@ Some examples include:
run without being root, by spawning an intermediate process via `sudo`
- [BatchSpawner](https://github.com/jupyterhub/batchspawner) for spawning remote
servers using batch systems
- [YarnSpawner](https://github.com/jupyterhub/yarnspawner) for spawning notebook
servers in YARN containers on a Hadoop cluster
- [RemoteSpawner](https://github.com/zonca/remotespawner) to spawn notebooks
and a remote server and tunnel the port via SSH
@@ -177,42 +174,6 @@ When `Spawner.start` is called, this dictionary is accessible as `self.user_opti
If you are interested in building a custom spawner, you can read [this tutorial](http://jupyterhub-tutorial.readthedocs.io/en/latest/spawners.html).
### Registering custom Spawners via entry points
As of JupyterHub 1.0, custom Spawners can register themselves via
the `jupyterhub.spawners` entry point metadata.
To do this, in your `setup.py` add:
```python
setup(
...
entry_points={
'jupyterhub.spawners': [
'myservice = mypackage:MySpawner',
],
},
)
```
If you have added this metadata to your package,
users can select your spawner with the configuration:
```python
c.JupyterHub.spawner_class = 'myservice'
```
instead of the full
```python
c.JupyterHub.spawner_class = 'mypackage:MySpawner'
```
previously required.
Additionally, configurable attributes for your spawner will
appear in jupyterhub help output and auto-generated configuration files
via `jupyterhub --generate-config`.
## Spawners, resource limits, and guarantees (Optional)
Some spawners of the single-user notebook servers allow setting limits or
@@ -262,30 +223,3 @@ in the single-user notebook server when a guarantee is being provided.
**The spawner's underlying system or cluster is responsible for enforcing these
limits and providing these guarantees.** If these values are set to `None`, no
limits or guarantees are provided, and no environment values are set.
### Encryption
Communication between the `Proxy`, `Hub`, and `Notebook` can be secured by
turning on `internal_ssl` in `jupyterhub_config.py`. For a custom spawner to
utilize these certs, there are two methods of interest on the base `Spawner`
class: `.create_certs` and `.move_certs`.
The first method, `.create_certs` will sign a key-cert pair using an internally
trusted authority for notebooks. During this process, `.create_certs` can
apply `ip` and `dns` name information to the cert via an `alt_names` `kwarg`.
This is used for certificate authentication (verification). Without proper
verification, the `Notebook` will be unable to communicate with the `Hub` and
vice versa when `internal_ssl` is enabled. For example, given a deployment
using the `DockerSpawner` which will start containers with `ips` from the
`docker` subnet pool, the `DockerSpawner` would need to instead choose a
container `ip` prior to starting and pass that to `.create_certs` (TODO: edit).
In general though, this method will not need to be changed and the default
`ip`/`dns` (localhost) info will suffice.
When `.create_certs` is run, it will `.create_certs` in a default, central
location specified by `c.JupyterHub.internal_certs_location`. For `Spawners`
that need access to these certs elsewhere (i.e. on another host altogether),
the `.move_certs` method can be overridden to move the certs appropriately.
Again, using `DockerSpawner` as an example, this would entail moving certs
to a directory that will get mounted into the container this spawner starts.

View File

@@ -28,7 +28,7 @@ by the `jupyterhub` command line program:
- **Single-User Notebook Server** (Python/Tornado): a dedicated,
single-user, Jupyter Notebook server is started for each user on the system
when the user logs in. The object that starts the single-user notebook
servers is called a **Spawner**.
servers is called a **Spawner**.
![JupyterHub subsystems](../images/jhub-parts.png)
@@ -49,14 +49,14 @@ The proxy is the only process that listens on a public interface. The Hub sits
behind the proxy at `/hub`. Single-user servers sit behind the proxy at
`/user/[username]`.
Different **[authenticators](./authenticators.md)** control access
Different **[authenticators](./authenticators.html)** control access
to JupyterHub. The default one (PAM) uses the user accounts on the server where
JupyterHub is running. If you use this, you will need to create a user account
on the system for each user on your team. Using other authenticators, you can
allow users to sign in with e.g. a GitHub account, or with any single-sign-on
system your organization has.
Next, **[spawners](./spawners.md)** control how JupyterHub starts
Next, **[spawners](./spawners.html)** control how JupyterHub starts
the individual notebook server for each user. The default spawner will
start a notebook server on the same machine running under their system username.
The other main option is to start each server in a separate container, often
@@ -66,10 +66,10 @@ using Docker.
When a user accesses JupyterHub, the following events take place:
- Login data is handed to the [Authenticator](./authenticators.md) instance for
- Login data is handed to the [Authenticator](./authenticators.html) instance for
validation
- The Authenticator returns the username if the login information is valid
- A single-user notebook server instance is [spawned](./spawners.md) for the
- A single-user notebook server instance is [spawned](./spawners.html) for the
logged-in user
- When the single-user notebook server starts, the proxy is notified to forward
requests to `/user/[username]/*` to the single-user notebook server.
@@ -111,7 +111,7 @@ working directory:
This file needs to persist so that a **Hub** server restart will avoid
invalidating cookies. Conversely, deleting this file and restarting the server
effectively invalidates all login cookies. The cookie secret file is discussed
in the [Cookie Secret section of the Security Settings document](../getting-started/security-basics.md).
in the [Cookie Secret section of the Security Settings document](../getting-started/security-basics.html).
The location of these files can be specified via configuration settings. It is
recommended that these files be stored in standard UNIX filesystem locations,
@@ -122,9 +122,9 @@ all security and runtime files.
There are two basic extension points for JupyterHub:
- How users are authenticated by [Authenticators](./authenticators.md)
- How users are authenticated by [Authenticators](./authenticators.html)
- How user's single-user notebook server processes are started by
[Spawners](./spawners.md)
[Spawners](./spawners.html)
Each is governed by a customizable class, and JupyterHub ships with basic
defaults for each.

View File

@@ -25,19 +25,19 @@ supplement the material in the block. The
make extensive use of blocks, which allows you to customize parts of the
interface easily.
In general, a child template can extend a base template, `page.html`, by beginning with:
In general, a child template can extend a base template, `base.html`, by beginning with:
```html
{% extends "page.html" %}
{% extends "base.html" %}
```
This works, unless you are trying to extend the default template for the same
file name. Starting in version 0.9, you may refer to the base file with a
`templates/` prefix. Thus, if you are writing a custom `page.html`, start the
`templates/` prefix. Thus, if you are writing a custom `base.html`, start the
file with this block:
```html
{% extends "templates/page.html" %}
{% extends "templates/base.html" %}
```
By defining `block`s with same name as in the base template, child templates
@@ -70,7 +70,7 @@ To add announcements to be displayed on a page, you have two options:
### Announcement Configuration Variables
If you set the configuration variable `JupyterHub.template_vars =
{'announcement': 'some_text'}`, the given `some_text` will be placed on
{'announcement': 'some_text}`, the given `some_text` will be placed on
the top of all pages. The more specific variables
`announcement_login`, `announcement_spawn`, `announcement_home`, and
`announcement_logout` are more specific and only show on their

View File

@@ -0,0 +1,98 @@
# Upgrading JupyterHub and its database
From time to time, you may wish to upgrade JupyterHub to take advantage
of new releases. Much of this process is automated using scripts,
such as those generated by alembic for database upgrades. Whether you
are using the default SQLite database or an RDBMS, such as PostgreSQL or
MySQL, the process follows similar steps.
**Before upgrading a JupyterHub deployment**, it's critical to backup your data
and configurations before shutting down the JupyterHub process and server.
## Note about upgrading the SQLite database
When used in production systems, SQLite has some disadvantages when it
comes to upgrading JupyterHub. These are:
- `upgrade-db` may not work, and you may need to start with a fresh database
- `downgrade-db` **will not** work if you want to rollback to an earlier
version, so backup the `jupyterhub.sqlite` file before upgrading
## The upgrade process
Five fundamental process steps are needed when upgrading JupyterHub and its
database:
1. Backup JupyterHub database
2. Backup JupyterHub configuration file
3. Shutdown the Hub
4. Upgrade JupyterHub
5. Upgrade the database using run `jupyterhub upgrade-db`
Let's take a closer look at each step in the upgrade process as well as some
additional information about JupyterHub databases.
### Backup JupyterHub database
To prevent unintended loss of data or configuration information, you should
back up the JupyterHub database (the default SQLite database or a RDBMS
database using PostgreSQL, MySQL, or others supported by SQLAlchemy):
- If using the default SQLite database, back up the `jupyterhub.sqlite`
database.
- If using an RDBMS database such as PostgreSQL, MySQL, or other supported by
SQLAlchemy, back up the JupyterHub database.
Losing the Hub database is often not a big deal. Information that resides only
in the Hub database includes:
- active login tokens (user cookies, service tokens)
- users added via GitHub UI, instead of config files
- info about running servers
If the following conditions are true, you should be fine clearing the Hub
database and starting over:
- users specified in config file
- user servers are stopped during upgrade
- don't mind causing users to login again after upgrade
### Backup JupyterHub configuration file
Additionally, backing up your configuration file, `jupyterhub_config.py`, to
a secure location.
### Shutdown JupyterHub
Prior to shutting down JupyterHub, you should notify the Hub users of the
scheduled downtime. This gives users the opportunity to finish any outstanding
work in process.
Next, shutdown the JupyterHub service.
### Upgrade JupyterHub
Follow directions that correspond to your package manager, `pip` or `conda`,
for the new JupyterHub release. These directions will guide you to the
specific command. In general, `pip install -U jupyterhub` or
`conda upgrade jupyterhub`
### Upgrade JupyterHub databases
To run the upgrade process for JupyterHub databases, enter:
```
jupyterhub upgrade-db
```
## Upgrade checklist
1. Backup JupyterHub database:
- `jupyterhub.sqlite` when using the default sqlite database
- Your JupyterHub database when using an RDBMS
2. Backup JupyterHub configuration file: `jupyterhub_config.py`
3. Shutdown the Hub
4. Upgrade JupyterHub
- `pip install -U jupyterhub` when using `pip`
- `conda upgrade jupyterhub` when using `conda`
5. Upgrade the database using run `jupyterhub upgrade-db`

View File

@@ -1,255 +0,0 @@
# JupyterHub URL scheme
This document describes how JupyterHub routes requests.
This does not include the [REST API](./rest.md) urls.
In general, all URLs can be prefixed with `c.JupyterHub.base_url` to
run the whole JupyterHub application on a prefix.
All authenticated handlers redirect to `/hub/login` to login users
prior to being redirected back to the originating page.
The returned request should preserve all query parameters.
## `/`
The top-level request is always a simple redirect to `/hub/`,
to be handled by the default JupyterHub handler.
In general, all requests to `/anything` that do not start with `/hub/`
but are routed to the Hub, will be redirected to `/hub/anything` before being handled by the Hub.
## `/hub/`
This is an authenticated URL.
This handler redirects users to the default URL of the application,
which defaults to the user's default server.
That is, it redirects to `/hub/spawn` if the user's server is not running,
or the server itself (`/user/:name`) if the server is running.
This default url behavior can be customized in two ways:
To redirect users to the JupyterHub home page (`/hub/home`)
instead of spawning their server,
set `redirect_to_server` to False:
```python
c.JupyterHub.redirect_to_server = False
```
This might be useful if you have a Hub where you expect
users to be managing multiple server configurations
and automatic spawning is not desirable.
Second, you can customise the landing page to any page you like,
such as a custom service you have deployed e.g. with course information:
```python
c.JupyterHub.default_url = '/services/my-landing-service'
```
## `/hub/home`
![The Hub home page with named servers enabled](../images/named-servers-home.png)
By default, the Hub home page has just one or two buttons
for starting and stopping the user's server.
If named servers are enabled, there will be some additional
tools for management of named servers.
*Version added: 1.0* named server UI is new in 1.0.
## `/hub/login`
This is the JupyterHub login page.
If you have a form-based username+password login,
such as the default PAMAuthenticator,
this page will render the login form.
![A login form](../images/login-form.png)
If login is handled by an external service,
e.g. with OAuth, this page will have a button,
declaring "Login with ..." which users can click
to login with the chosen service.
![A login redirect button](../images/login-button.png)
If you want to skip the user-interaction to initiate logging in
via the button, you can set
```python
c.Authenticator.auto_login = True
```
This can be useful when the user is "already logged in" via some mechanism,
but a handshake via redirects is necessary to complete the authentication with JupyterHub.
## `/hub/logout`
Visiting `/hub/logout` clears cookies from the current browser.
Note that **logging out does not stop a user's server(s)** by default.
If you would like to shutdown user servers on logout,
you can enable this behavior with:
```python
c.JupyterHub.shutdown_on_logout = True
```
Be careful with this setting because logging out one browser
does not mean the user is no longer actively using their server from another machine.
## `/user/:username[/:servername]`
If a user's server is running, this URL is handled by the user's given server,
not the Hub.
The username is the first part and, if using named servers,
the server name is the second part.
If the user's server is *not* running, this will be redirected to `/hub/user/:username/...`
## `/hub/user/:username[/:servername]`
This URL indicates a request for a user server that is not running
(because `/user/...` would have been handled by the notebook server
if the specified server were running).
Handling this URL is the most complicated condition in JupyterHub,
because there can be many states:
1. server is not active
a. user matches
b. user doesn't match
2. server is ready
3. server is pending, but not ready
If the server is pending spawn,
the browser will be redirected to `/hub/spawn-pending/:username/:servername`
to see a progress page while waiting for the server to be ready.
If the server is not active at all,
a page will be served with a link to `/hub/spawn/:username/:servername`.
Following that link will launch the requested server.
The HTTP status will be 503 in this case because a request has been made for a server that is not running.
If the server is ready, it is assumed that the proxy has not yet registered the route.
Some checks are performed and a delay is added before redirecting back to `/user/:username/:servername/...`.
If something is really wrong, this can result in a redirect loop.
Visiting this page will never result in triggering the spawn of servers
without additional user action (i.e. clicking the link on the page)
![Visiting a URL for a server that's not running](../images/not-running.png)
*Version changed: 1.0*
Prior to 1.0, this URL itself was responsible for spawning servers,
and served the progress page if it was pending,
redirected to running servers, and
This was useful because it made sure that requested servers were restarted after they stopped,
but could also be harmful because unused servers would continuously be restarted if e.g.
an idle JupyterLab frontend were open pointed at it,
which constantly makes polling requests.
### Special handling of API requests
Requests to `/user/:username[/:servername]/api/...` are assumed to be
from applications connected to stopped servers.
These are failed with 503 and an informative JSON error message
indicating how to spawn the server.
This is meant to help applications such as JupyterLab
that are connected to a server that has stopped.
*Version changed: 1.0*
JupyterHub 0.9 failed these API requests with status 404,
but 1.0 uses 503.
## `/user-redirect/...`
This URL is for sharing a URL that will redirect a user
to a path on their own default server.
This is useful when users have the same file at the same URL on their servers,
and you want a single link to give to any user that will open that file on their server.
e.g. a link to `/user-redirect/notebooks/Index.ipynb`
will send user `hortense` to `/user/hortense/notebooks/Index.ipynb`
**DO NOT** share links to your own server with other users.
This will not work in general,
unless you grant those users access to your server.
**Contributions welcome:** The JupyterLab "shareable link" should share this link
when run with JupyterHub, but it does not.
See [jupyterlab-hub](https://github.com/jupyterhub/jupyterlab-hub)
where this should probably be done and
[this issue in JupyterLab](https://github.com/jupyterlab/jupyterlab/issues/5388)
that is intended to make it possible.
## Spawning
### `/hub/spawn[/:username[/:servername]]`
Requesting `/hub/spawn` will spawn the default server for the current user.
If `username` and optionally `servername` are specified,
then the specified server for the specified user will be spawned.
Once spawn has been requested,
the browser is redirected to `/hub/spawn-pending/...`.
If `Spawner.options_form` is used,
this will render a form,
and a POST request will trigger the actual spawn and redirect.
![The spawn form](../images/spawn-form.png)
*Version added: 1.0*
1.0 adds the ability to specify username and servername.
Prior to 1.0, only `/hub/spawn` was recognized for the default server.
*Version changed: 1.0*
Prior to 1.0, this page redirected back to `/hub/user/:username`,
which was responsible for triggering spawn and rendering progress, etc.
### `/hub/spawn-pending[/:username[/:servername]]`
![The spawn pending page](../images/spawn-pending.png)
*Version added: 1.0* this URL is new in JupyterHub 1.0.
This page renders the progress view for the given spawn request.
Once the server is ready,
the browser is redirected to the running server at `/user/:username/:servername/...`.
If this page is requested at any time after the specified server is ready,
the browser will be redirected to the running server.
Requesting this page will never trigger any side effects.
If the server is not running (e.g. because the spawn has failed),
the spawn failure message (if applicable) will be displayed,
and the page will show a link back to `/hub/spawn/...`.
## `/hub/token`
![The token management page](../images/token-page.png)
On this page, users can manage their JupyterHub API tokens.
They can revoke access and request new tokens for writing scripts
against the [JupyterHub REST API](./rest.md).
## `/hub/admin`
![The admin panel](../images/named-servers-admin.png)
Administrators can take various administrative actions from this page:
1. add/remove users
2. grant admin privileges
3. start/stop user servers
4. shutdown JupyterHub itself

View File

@@ -76,7 +76,7 @@ resolves the cross-site issues.
### Disable user config
If subdomains are not available or not desirable, JupyterHub provides a
If subdomains are not available or not desirable, JupyterHub provides a a
configuration option `Spawner.disable_user_config`, which can be set to prevent
the user-owned configuration files from being loaded. After implementing this
option, PATHs and package installation and PATHs are the other things that the
@@ -99,23 +99,6 @@ single-user server, and not the environment(s) in which the user's kernel(s)
may run. Installing additional packages in the kernel environment does not
pose additional risk to the web application's security.
### Encrypt internal connections with SSL/TLS
By default, all communication on the server, between the proxy, hub, and single
-user notebooks is performed unencrypted. Setting the `internal_ssl` flag in
`jupyterhub_config.py` secures the aforementioned routes. Turning this
feature on does require that the enabled `Spawner` can use the certificates
generated by the `Hub` (the default `LocalProcessSpawner` can, for instance).
It is also important to note that this encryption **does not** (yet) cover the
`zmq tcp` sockets between the Notebook client and kernel. While users cannot
submit arbitrary commands to another user's kernel, they can bind to these
sockets and listen. When serving untrusted users, this eavesdropping can be
mitigated by setting `KernelManager.transport` to `ipc`. This applies standard
Unix permissions to the communication sockets thereby restricting
communication to the socket owner. The `internal_ssl` option will eventually
extend to securing the `tcp` sockets as well.
## Security audits
We recommend that you do periodic reviews of your deployment's security. It's
@@ -127,11 +110,3 @@ A handy website for testing your deployment is
[configurable-http-proxy]: https://github.com/jupyterhub/configurable-http-proxy
## Vulnerability reporting
If you believe youve found a security vulnerability in JupyterHub, or any
Jupyter project, please report it to
[security@ipython.org](mailto:security@iypthon.org). If you prefer to encrypt
your security reports, you can use [this PGP public
key](https://jupyter-notebook.readthedocs.io/en/stable/_downloads/ipython_security.asc).

View File

@@ -210,4 +210,4 @@ Wildcards
willingc
wordlist
Workflow
workflow
workflow

View File

@@ -204,7 +204,7 @@ from there instead of the internet.
For instance, you can install JupyterHub with pip and configurable-http-proxy
with npmbox:
python3 -m pip wheel jupyterhub
pip wheel jupyterhub
npmbox configurable-http-proxy
### I want access to the whole filesystem, but still default users to their home directory
@@ -236,7 +236,7 @@ then you can change the default URL to `/lab`.
For instance:
python3 -m pip install jupyterlab
pip install jupyterlab
jupyter serverextension enable --py jupyterlab --sys-prefix
The important thing is that jupyterlab is installed and enabled in the

View File

@@ -0,0 +1,14 @@
Tutorials
=========
This section provides links to documentation that helps a user do a specific
task.
* :doc:`upgrade-dot-eight`
* `Zero to JupyterHub with Kubernetes <https://zero-to-jupyterhub.readthedocs.io/en/latest/>`_
.. toctree::
:maxdepth: 1
:hidden:
upgrade-dot-eight

View File

@@ -0,0 +1,93 @@
.. _upgrade-dot-eight:
Upgrading to JupyterHub version 0.8
===================================
This document will assist you in upgrading an existing JupyterHub deployment
from version 0.7 to version 0.8.
Upgrade checklist
-----------------
0. Review the release notes. Review any deprecated features and pay attention
to any backwards incompatible changes
1. Backup JupyterHub database:
- ``jupyterhub.sqlite`` when using the default sqlite database
- Your JupyterHub database when using an RDBMS
2. Backup the existing JupyterHub configuration file: ``jupyterhub_config.py``
3. Shutdown the Hub
4. Upgrade JupyterHub
- ``pip install -U jupyterhub`` when using ``pip``
- ``conda upgrade jupyterhub`` when using ``conda``
5. Upgrade the database using run ```jupyterhub upgrade-db``
6. Update the JupyterHub configuration file ``jupyterhub_config.py``
Backup JupyterHub database
--------------------------
To prevent unintended loss of data or configuration information, you should
back up the JupyterHub database (the default SQLite database or a RDBMS
database using PostgreSQL, MySQL, or others supported by SQLAlchemy):
- If using the default SQLite database, back up the ``jupyterhub.sqlite``
database.
- If using an RDBMS database such as PostgreSQL, MySQL, or other supported by
SQLAlchemy, back up the JupyterHub database.
.. note::
Losing the Hub database is often not a big deal. Information that resides only
in the Hub database includes:
- active login tokens (user cookies, service tokens)
- users added via GitHub UI, instead of config files
- info about running servers
If the following conditions are true, you should be fine clearing the Hub
database and starting over:
- users specified in config file
- user servers are stopped during upgrade
- don't mind causing users to login again after upgrade
Backup JupyterHub configuration file
------------------------------------
Backup up your configuration file, ``jupyterhub_config.py``, to a secure
location.
Shutdown JupyterHub
-------------------
- Prior to shutting down JupyterHub, you should notify the Hub users of the
scheduled downtime.
- Shutdown the JupyterHub service.
Upgrade JupyterHub
------------------
Follow directions that correspond to your package manager, ``pip`` or ``conda``,
for the new JupyterHub release:
- ``pip install -U jupyterhub`` for ``pip``
- ``conda upgrade jupyterhub`` for ``conda``
Upgrade the proxy, authenticator, or spawner if needed.
Upgrade JupyterHub database
---------------------------
To run the upgrade process for JupyterHub databases, enter::
jupyterhub upgrade-db
Update the JupyterHub configuration file
----------------------------------------
Create a new JupyterHub configuration file or edit a copy of the existing
file ``jupyterhub_config.py``.
Start JupyterHub
----------------
Start JupyterHub with the same command that you used before the upgrade.

View File

@@ -0,0 +1,55 @@
"""autodoc extension for configurable traits"""
from traitlets import TraitType, Undefined
from sphinx.domains.python import PyClassmember
from sphinx.ext.autodoc import ClassDocumenter, AttributeDocumenter
class ConfigurableDocumenter(ClassDocumenter):
"""Specialized Documenter subclass for traits with config=True"""
objtype = 'configurable'
directivetype = 'class'
def get_object_members(self, want_all):
"""Add traits with .tag(config=True) to members list"""
check, members = super().get_object_members(want_all)
get_traits = (
self.object.class_own_traits
if self.options.inherited_members
else self.object.class_traits
)
trait_members = []
for name, trait in sorted(get_traits(config=True).items()):
# put help in __doc__ where autodoc will look for it
trait.__doc__ = trait.help
trait_members.append((name, trait))
return check, trait_members + members
class TraitDocumenter(AttributeDocumenter):
objtype = 'trait'
directivetype = 'attribute'
member_order = 1
priority = 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, TraitType)
def format_name(self):
return 'config c.' + super().format_name()
def add_directive_header(self, sig):
default = self.object.get_default_value()
if default is Undefined:
default_s = ''
else:
default_s = repr(default)
sig = ' = {}({})'.format(self.object.__class__.__name__, default_s)
return super().add_directive_header(sig)
def setup(app):
app.add_autodocumenter(ConfigurableDocumenter)
app.add_autodocumenter(TraitDocumenter)

View File

@@ -59,31 +59,7 @@ def create_dir_hook(spawner):
c.Spawner.pre_spawn_hook = create_dir_hook
```
### Example #2 - Run `mkhomedir_helper`
Many Linux distributions provide a script that is responsible for user homedir bootstrapping: `/sbin/mkhomedir_helper`. To make use of it, you can use
```python
def create_dir_hook(spawner):
username = spawner.user.name
if not os.path.exists(os.path.join('/volumes/jupyterhub', username)):
subprocess.call(["sudo", "/sbin/mkhomedir_helper", spawner.user.name])
# attach the hook function to the spawner
c.Spawner.pre_spawn_hook = create_dir_hook
```
and make sure to add
```
jupyterhub ALL = (root) NOPASSWD: /sbin/mkhomedir_helper
```
in a new file in `/etc/sudoers.d`, or simply in `/etc/sudoers`.
All new home directories will be created from `/etc/skel`, so make sure to place any custom homedir-contents in there.
### Example #3 - Run a shell script
### Example #2 - Run a shell script
You can specify a plain ole' shell script (or any other executable) to be run
by the bootstrap process.
@@ -118,7 +94,7 @@ Here's an example on what you could do in your shell script. See also
# - The first parameter for the Bootstrap Script is the USER.
USER=$1
if [ "$USER" == "" ]; then
if ["$USER" == ""]; then
exit 1
fi
# ----------------------------------------------------------------------------

View File

@@ -6,7 +6,7 @@
# - The first parameter for the Bootstrap Script is the USER.
USER=$1
if [ "$USER" == "" ]; then
if ["$USER" == ""]; then
exit 1
fi
# ----------------------------------------------------------------------------

View File

@@ -5,28 +5,24 @@ create a directory for the user before the spawner starts
# pylint: disable=import-error
import os
import shutil
from jupyter_client.localinterfaces import public_ips
def create_dir_hook(spawner):
""" Create directory """
username = spawner.user.name # get the username
username = spawner.user.name # get the username
volume_path = os.path.join('/volumes/jupyterhub', username)
if not os.path.exists(volume_path):
os.mkdir(volume_path, 0o755)
# now do whatever you think your user needs
# ...
def clean_dir_hook(spawner):
""" Delete directory """
username = spawner.user.name # get the username
username = spawner.user.name # get the username
temp_path = os.path.join('/volumes/jupyterhub', username, 'temp')
if os.path.exists(temp_path) and os.path.isdir(temp_path):
shutil.rmtree(temp_path)
# attach the hook functions to the spawner
# pylint: disable=undefined-variable
c.Spawner.pre_spawn_hook = create_dir_hook
@@ -41,4 +37,4 @@ c.DockerSpawner.container_ip = "0.0.0.0"
# You can now mount the volume to the docker container as we've
# made sure the directory exists
# pylint: disable=bad-whitespace
c.DockerSpawner.volumes = {'/volumes/jupyterhub/{username}/': '/home/jovyan/work'}
c.DockerSpawner.volumes = { '/volumes/jupyterhub/{username}/': '/home/jovyan/work' }

View File

@@ -15,7 +15,7 @@ c.JupyterHub.services = [
{
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, 'cull_idle_servers.py', '--timeout=3600'],
'command': 'python3 cull_idle_servers.py --timeout=3600'.split(),
}
]
```
@@ -36,6 +36,6 @@ Generate an API token and store it in the `JUPYTERHUB_API_TOKEN` environment
variable. Run `cull_idle_servers.py` manually.
```bash
export JUPYTERHUB_API_TOKEN=$(jupyterhub token)
export JUPYTERHUB_API_TOKEN=`jupyterhub token`
python3 cull_idle_servers.py [--timeout=900] [--url=http://127.0.0.1:8081/hub/api]
```

View File

@@ -16,13 +16,13 @@ You can run this as a service managed by JupyterHub with this in your config::
{
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, 'cull_idle_servers.py', '--timeout=3600'],
'command': 'python3 cull_idle_servers.py --timeout=3600'.split(),
}
]
Or run it manually by generating an API token and storing it in `JUPYTERHUB_API_TOKEN`:
export JUPYTERHUB_API_TOKEN=$(jupyterhub token)
export JUPYTERHUB_API_TOKEN=`jupyterhub token`
python3 cull_idle_servers.py [--timeout=900] [--url=http://127.0.0.1:8081/hub/api]
This script uses the same ``--timeout`` and ``--max-age`` values for
@@ -31,11 +31,11 @@ users and servers, you should add this script to the services list
twice, just with different ``name``s, different values, and one with
the ``--cull-users`` option.
"""
from datetime import datetime, timezone
from functools import partial
import json
import os
from datetime import datetime
from datetime import timezone
from functools import partial
try:
from urllib.parse import quote
@@ -85,21 +85,23 @@ def format_td(td):
@coroutine
def cull_idle(
url, api_token, inactive_limit, cull_users=False, max_age=0, concurrency=10
):
def cull_idle(url, api_token, inactive_limit, cull_users=False, max_age=0, concurrency=10):
"""Shutdown idle single-user servers
If cull_users, inactive *users* will be deleted as well.
"""
auth_header = {'Authorization': 'token %s' % api_token}
req = HTTPRequest(url=url + '/users', headers=auth_header)
auth_header = {
'Authorization': 'token %s' % api_token,
}
req = HTTPRequest(
url=url + '/users',
headers=auth_header,
)
now = datetime.now(timezone.utc)
client = AsyncHTTPClient()
if concurrency:
semaphore = Semaphore(concurrency)
@coroutine
def fetch(req):
"""client.fetch wrapped in a semaphore to limit concurrency"""
@@ -108,7 +110,6 @@ def cull_idle(
return (yield client.fetch(req))
finally:
yield semaphore.release()
else:
fetch = client.fetch
@@ -117,11 +118,9 @@ def cull_idle(
futures = []
@coroutine
def handle_server(user, server_name, server, max_age, inactive_limit):
def handle_server(user, server_name, server):
"""Handle (maybe) culling a single server
"server" is the entire server model from the API.
Returns True if server is now stopped (user removable),
False otherwise.
"""
@@ -130,8 +129,8 @@ def cull_idle(
log_name = '%s/%s' % (user['name'], server_name)
if server.get('pending'):
app_log.warning(
"Not culling server %s with pending %s", log_name, server['pending']
)
"Not culling server %s with pending %s",
log_name, server['pending'])
return False
# jupyterhub < 0.9 defined 'server.url' once the server was ready
@@ -143,8 +142,8 @@ def cull_idle(
if not server.get('ready', bool(server['url'])):
app_log.warning(
"Not culling not-ready not-pending server %s: %s", log_name, server
)
"Not culling not-ready not-pending server %s: %s",
log_name, server)
return False
if server.get('started'):
@@ -164,27 +163,12 @@ def cull_idle(
# for running servers
inactive = age
# CUSTOM CULLING TEST CODE HERE
# Add in additional server tests here. Return False to mean "don't
# cull", True means "cull immediately", or, for example, update some
# other variables like inactive_limit.
#
# Here, server['state'] is the result of the get_state method
# on the spawner. This does *not* contain the below by
# default, you may have to modify your spawner to make this
# work. The `user` variable is the user model from the API.
#
# if server['state']['profile_name'] == 'unlimited'
# return False
# inactive_limit = server['state']['culltime']
should_cull = (
inactive is not None and inactive.total_seconds() >= inactive_limit
)
should_cull = (inactive is not None and
inactive.total_seconds() >= inactive_limit)
if should_cull:
app_log.info(
"Culling server %s (inactive for %s)", log_name, format_td(inactive)
)
"Culling server %s (inactive for %s)",
log_name, format_td(inactive))
if max_age and not should_cull:
# only check started if max_age is specified
@@ -193,34 +177,32 @@ def cull_idle(
if age is not None and age.total_seconds() >= max_age:
app_log.info(
"Culling server %s (age: %s, inactive for %s)",
log_name,
format_td(age),
format_td(inactive),
)
log_name, format_td(age), format_td(inactive))
should_cull = True
if not should_cull:
app_log.debug(
"Not culling server %s (age: %s, inactive for %s)",
log_name,
format_td(age),
format_td(inactive),
)
log_name, format_td(age), format_td(inactive))
return False
if server_name:
# culling a named server
delete_url = url + "/users/%s/servers/%s" % (
quote(user['name']),
quote(server['name']),
quote(user['name']), quote(server['name'])
)
else:
delete_url = url + '/users/%s/server' % quote(user['name'])
req = HTTPRequest(url=delete_url, method='DELETE', headers=auth_header)
req = HTTPRequest(
url=delete_url, method='DELETE', headers=auth_header,
)
resp = yield fetch(req)
if resp.code == 202:
app_log.warning("Server %s is slow to stop", log_name)
app_log.warning(
"Server %s is slow to stop",
log_name,
)
# return False to prevent culling user with pending shutdowns
return False
return True
@@ -252,7 +234,7 @@ def cull_idle(
'url': user['server'],
}
server_futures = [
handle_server(user, server_name, server, max_age, inactive_limit)
handle_server(user, server_name, server)
for server_name, server in servers.items()
]
results = yield multi(server_futures)
@@ -263,9 +245,7 @@ def cull_idle(
if still_alive:
app_log.debug(
"Not culling user %s with %i servers still alive",
user['name'],
still_alive,
)
user['name'], still_alive)
return False
should_cull = False
@@ -285,11 +265,12 @@ def cull_idle(
# which introduces the 'created' field which is never None
inactive = age
should_cull = (
inactive is not None and inactive.total_seconds() >= inactive_limit
)
should_cull = (inactive is not None and
inactive.total_seconds() >= inactive_limit)
if should_cull:
app_log.info("Culling user %s (inactive for %s)", user['name'], inactive)
app_log.info(
"Culling user %s (inactive for %s)",
user['name'], inactive)
if max_age and not should_cull:
# only check created if max_age is specified
@@ -298,23 +279,19 @@ def cull_idle(
if age is not None and age.total_seconds() >= max_age:
app_log.info(
"Culling user %s (age: %s, inactive for %s)",
user['name'],
format_td(age),
format_td(inactive),
)
user['name'], format_td(age), format_td(inactive))
should_cull = True
if not should_cull:
app_log.debug(
"Not culling user %s (created: %s, last active: %s)",
user['name'],
format_td(age),
format_td(inactive),
)
user['name'], format_td(age), format_td(inactive))
return False
req = HTTPRequest(
url=url + '/users/%s' % user['name'], method='DELETE', headers=auth_header
url=url + '/users/%s' % user['name'],
method='DELETE',
headers=auth_header,
)
yield fetch(req)
return True
@@ -339,31 +316,21 @@ if __name__ == '__main__':
help="The JupyterHub API URL",
)
define('timeout', default=600, help="The idle timeout (in seconds)")
define(
'cull_every',
default=0,
help="The interval (in seconds) for checking for idle servers to cull",
)
define(
'max_age',
default=0,
help="The maximum age (in seconds) of servers that should be culled even if they are active",
)
define(
'cull_users',
default=False,
help="""Cull users in addition to servers.
define('cull_every', default=0,
help="The interval (in seconds) for checking for idle servers to cull")
define('max_age', default=0,
help="The maximum age (in seconds) of servers that should be culled even if they are active")
define('cull_users', default=False,
help="""Cull users in addition to servers.
This is for use in temporary-user cases such as tmpnb.""",
)
define(
'concurrency',
default=10,
help="""Limit the number of concurrent requests made to the Hub.
)
define('concurrency', default=10,
help="""Limit the number of concurrent requests made to the Hub.
Deleting a lot of users at the same time can slow down the Hub,
so limit the number of API requests we have outstanding at any given time.
""",
)
"""
)
parse_command_line()
if not options.cull_every:
@@ -376,8 +343,7 @@ if __name__ == '__main__':
app_log.warning(
"Could not load pycurl: %s\n"
"pycurl is recommended if you have a large number of users.",
e,
)
e)
loop = IOLoop.current()
cull = partial(

View File

@@ -1,11 +1,8 @@
import sys
# run cull-idle as a service
c.JupyterHub.services = [
{
'name': 'cull-idle',
'admin': True,
'command': [sys.executable, 'cull_idle_servers.py', '--timeout=3600'],
'command': 'python3 cull_idle_servers.py --timeout=3600'.split(),
}
]

View File

@@ -18,7 +18,7 @@ implementations in other web servers or languages.
1. generate an API token:
export JUPYTERHUB_API_TOKEN=$(openssl rand -hex 32)
export JUPYTERHUB_API_TOKEN=`openssl rand -hex 32`
2. launch a version of the the whoami service.
For `whoami-oauth`:

View File

@@ -4,9 +4,7 @@ import os
# this could come from anywhere
api_token = os.getenv("JUPYTERHUB_API_TOKEN")
if not api_token:
raise ValueError(
"Make sure to `export JUPYTERHUB_API_TOKEN=$(openssl rand -hex 32)`"
)
raise ValueError("Make sure to `export JUPYTERHUB_API_TOKEN=$(openssl rand -hex 32)`")
# tell JupyterHub to register the service as an external oauth client
@@ -16,5 +14,5 @@ c.JupyterHub.services = [
'oauth_client_id': "whoami-oauth-client-test",
'api_token': api_token,
'oauth_redirect_uri': 'http://127.0.0.1:5555/oauth_callback',
}
},
]

View File

@@ -3,19 +3,18 @@
Implements OAuth handshake manually
so all URLs and requests necessary for OAuth with JupyterHub should be in one place
"""
import json
import os
import sys
from urllib.parse import urlencode
from urllib.parse import urlparse
from urllib.parse import urlencode, urlparse
from tornado import log
from tornado import web
from tornado.auth import OAuth2Mixin
from tornado.httpclient import AsyncHTTPClient
from tornado.httpclient import HTTPRequest
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
from tornado.httputil import url_concat
from tornado.ioloop import IOLoop
from tornado import log
from tornado import web
class JupyterHubLoginHandler(web.RequestHandler):
@@ -33,11 +32,11 @@ class JupyterHubLoginHandler(web.RequestHandler):
code=code,
redirect_uri=self.settings['redirect_uri'],
)
req = HTTPRequest(
self.settings['token_url'],
method='POST',
body=urlencode(params).encode('utf8'),
headers={'Content-Type': 'application/x-www-form-urlencoded'},
req = HTTPRequest(self.settings['token_url'], method='POST',
body=urlencode(params).encode('utf8'),
headers={
'Content-Type': 'application/x-www-form-urlencoded',
},
)
response = await AsyncHTTPClient().fetch(req)
data = json.loads(response.body.decode('utf8', 'replace'))
@@ -56,16 +55,14 @@ class JupyterHubLoginHandler(web.RequestHandler):
# we are the login handler,
# begin oauth process which will come back later with an
# authorization_code
self.redirect(
url_concat(
self.settings['authorize_url'],
dict(
redirect_uri=self.settings['redirect_uri'],
client_id=self.settings['client_id'],
response_type='code',
),
self.redirect(url_concat(
self.settings['authorize_url'],
dict(
redirect_uri=self.settings['redirect_uri'],
client_id=self.settings['client_id'],
response_type='code',
)
)
))
class WhoAmIHandler(web.RequestHandler):
@@ -88,7 +85,10 @@ class WhoAmIHandler(web.RequestHandler):
"""Retrieve the user for a given token, via /hub/api/user"""
req = HTTPRequest(
self.settings['user_url'], headers={'Authorization': f'token {token}'}
self.settings['user_url'],
headers={
'Authorization': f'token {token}'
},
)
response = await AsyncHTTPClient().fetch(req)
return json.loads(response.body.decode('utf8', 'replace'))
@@ -110,23 +110,23 @@ def main():
token_url = hub_api + '/oauth2/token'
user_url = hub_api + '/user'
app = web.Application(
[('/oauth_callback', JupyterHubLoginHandler), ('/', WhoAmIHandler)],
app = web.Application([
('/oauth_callback', JupyterHubLoginHandler),
('/', WhoAmIHandler),
],
login_url='/oauth_callback',
cookie_secret=os.urandom(32),
api_token=os.environ['JUPYTERHUB_API_TOKEN'],
client_id=os.environ['JUPYTERHUB_CLIENT_ID'],
redirect_uri=os.environ['JUPYTERHUB_SERVICE_URL'].rstrip('/')
+ '/oauth_callback',
redirect_uri=os.environ['JUPYTERHUB_SERVICE_URL'].rstrip('/') + '/oauth_callback',
authorize_url=authorize_url,
token_url=token_url,
user_url=user_url,
)
url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL'])
log.app_log.info(
"Running basic whoami service on %s", os.environ['JUPYTERHUB_SERVICE_URL']
)
log.app_log.info("Running basic whoami service on %s",
os.environ['JUPYTERHUB_SERVICE_URL'])
app.listen(url.port, url.hostname)
IOLoop.current().start()

View File

@@ -8,10 +8,10 @@ c.Authenticator.whitelist = {'ganymede', 'io', 'rhea'}
# These environment variables are automatically supplied by the linked postgres
# container.
import os
import os;
pg_pass = os.getenv('POSTGRES_ENV_JPY_PSQL_PASSWORD')
pg_host = os.getenv('POSTGRES_PORT_5432_TCP_ADDR')
c.JupyterHub.db_url = 'postgresql://jupyterhub:{}@{}:5432/jupyterhub'.format(
pg_pass, pg_host
pg_pass,
pg_host,
)

View File

@@ -11,7 +11,7 @@ configuration file something like:
{
'name': 'announcement',
'url': 'http://127.0.0.1:8888',
'command': [sys.executable, "-m", "announcement"],
'command': ["python", "-m", "announcement"],
}
]

View File

@@ -1,14 +1,11 @@
import argparse
import datetime
import json
import os
from tornado import escape
from tornado import gen
from tornado import ioloop
from tornado import web
from jupyterhub.services.auth import HubAuthenticated
from tornado import escape, gen, ioloop, web
class AnnouncementRequestHandler(HubAuthenticated, web.RequestHandler):
@@ -24,7 +21,6 @@ class AnnouncementRequestHandler(HubAuthenticated, web.RequestHandler):
@web.authenticated
def post(self):
"""Update announcement"""
user = self.get_current_user()
doc = escape.json_decode(self.request.body)
self.storage["announcement"] = doc["announcement"]
self.storage["timestamp"] = datetime.datetime.now().isoformat()
@@ -56,19 +52,19 @@ def main():
def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument(
"--api-prefix",
"-a",
default=os.environ.get("JUPYTERHUB_SERVICE_PREFIX", "/"),
help="application API prefix",
)
parser.add_argument(
"--port", "-p", default=8888, help="port for API to listen on", type=int
)
parser.add_argument("--api-prefix", "-a",
default=os.environ.get("JUPYTERHUB_SERVICE_PREFIX", "/"),
help="application API prefix")
parser.add_argument("--port", "-p",
default=8888,
help="port for API to listen on",
type=int)
return parser.parse_args()
def create_application(api_prefix="/", handler=AnnouncementRequestHandler, **kwargs):
def create_application(api_prefix="/",
handler=AnnouncementRequestHandler,
**kwargs):
storage = dict(announcement="", timestamp="", user="")
return web.Application([(api_prefix, handler, dict(storage=storage))])

Some files were not shown because too many files have changed in this diff Show More