mirror of
https://github.com/jupyterhub/the-littlest-jupyterhub.git
synced 2025-12-18 21:54:05 +08:00
Sync with main
now that base OS version is updated
This commit is contained in:
50
.github/workflows/integration-test.yaml
vendored
50
.github/workflows/integration-test.yaml
vendored
@@ -58,36 +58,28 @@ jobs:
|
||||
echo $matrix_post_filter | jq -C '.'
|
||||
env:
|
||||
matrix_include_pre_filter: |
|
||||
- name: "Int. tests: Ubuntu 18.04, Py 3.6"
|
||||
ubuntu_version: "18.04"
|
||||
python_version: "3.6"
|
||||
- name: "Int. tests: Debian 11, Py 3.9"
|
||||
distro_image: "debian:11"
|
||||
runs_on: "ubuntu-22.04"
|
||||
extra_flags: ""
|
||||
- name: "Int. tests: Ubuntu 20.04, Py 3.9"
|
||||
ubuntu_version: "20.04"
|
||||
python_version: "3.9"
|
||||
- name: "Int. tests: Ubuntu 20.04, Py 3.8"
|
||||
distro_image: "ubuntu:20.04"
|
||||
extra_flags: ""
|
||||
- name: "Int. tests: Ubuntu 22.04, Py 3.10"
|
||||
ubuntu_version: "22.04"
|
||||
python_version: "3.10"
|
||||
- name: "Int. tests: Ubuntu 22.04 Py 3.10"
|
||||
distro_image: "ubuntu:22.04"
|
||||
extra_flags: ""
|
||||
- name: "Int. tests: Ubuntu 22.04, Py 3.10, --upgrade"
|
||||
ubuntu_version: "22.04"
|
||||
python_version: "3.10"
|
||||
distro_image: "ubuntu:22.04"
|
||||
extra_flags: --upgrade
|
||||
dont_run_on_ref: refs/heads/master
|
||||
|
||||
integration-tests:
|
||||
needs: decide-on-test-jobs-to-run
|
||||
|
||||
# runs-on can only be configured to the LTS releases of ubuntu (20.04,
|
||||
# 22.04, ...), so if we want to test against the latest non-LTS release, we
|
||||
# must compromise when configuring runs-on and configure runs-on to be the
|
||||
# latest LTS release instead.
|
||||
#
|
||||
# This can have consequences because actions like actions/setup-python will
|
||||
# mount cached installations associated with the chosen runs-on environment.
|
||||
#
|
||||
runs-on: ${{ format('ubuntu-{0}', matrix.runs_on || matrix.ubuntu_version) }}
|
||||
# integration tests run in a container,
|
||||
# not in the worker, so this version is not relevant to the tests
|
||||
# and can be the same for all tested versions
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
name: ${{ matrix.name }}
|
||||
strategy:
|
||||
@@ -98,7 +90,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "${{ matrix.python_version }}"
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install pytest
|
||||
run: python3 -m pip install pytest
|
||||
@@ -106,7 +98,7 @@ jobs:
|
||||
# We abort pytest after two failures as a compromise between wanting to
|
||||
# avoid a flood of logs while still understanding if multiple tests would
|
||||
# fail.
|
||||
- name: Run bootstrap tests (Runs in/Builds ubuntu:${{ matrix.ubuntu_version }} derived image)
|
||||
- name: Run bootstrap tests (Runs in/Builds ${{ matrix.distro_image }} derived image)
|
||||
run: |
|
||||
pytest --verbose --maxfail=2 --color=yes --durations=10 --capture=no \
|
||||
integration-tests/test_bootstrap.py
|
||||
@@ -115,14 +107,14 @@ jobs:
|
||||
# integration-tests/test_bootstrap.py will build and start containers
|
||||
# based on this environment variable. This is similar to how
|
||||
# .github/integration-test.py build-image can take a --build-arg
|
||||
# setting the ubuntu_version.
|
||||
UBUNTU_VERSION: ${{ matrix.ubuntu_version }}
|
||||
# setting the base image.
|
||||
BASE_IMAGE: ${{ matrix.distro_image }}
|
||||
|
||||
# We build a docker image from wherein we will work
|
||||
- name: Build systemd image (Builds ubuntu:${{ matrix.ubuntu_version }} derived image)
|
||||
- name: Build systemd image (Builds ${{ matrix.distro_image }} derived image)
|
||||
run: |
|
||||
.github/integration-test.py build-image \
|
||||
--build-arg "ubuntu_version=${{ matrix.ubuntu_version }}"
|
||||
--build-arg "BASE_IMAGE=${{ matrix.distro_image }}"
|
||||
|
||||
# FIXME: Make the logic below easier to follow.
|
||||
# - In short, setting BOOTSTRAP_PIP_SPEC here, specifies from what
|
||||
@@ -151,7 +143,7 @@ jobs:
|
||||
echo "BOOTSTRAP_PIP_SPEC=$BOOTSTRAP_PIP_SPEC" >> $GITHUB_ENV
|
||||
echo $BOOTSTRAP_PIP_SPEC
|
||||
|
||||
- name: Run basic tests (Runs in ubuntu:${{ matrix.ubuntu_version }} derived image)
|
||||
- name: Run basic tests (Runs in ${{ matrix.distro_image }} derived image)
|
||||
run: |
|
||||
.github/integration-test.py run-test basic-tests \
|
||||
--bootstrap-pip-spec "$BOOTSTRAP_PIP_SPEC" \
|
||||
@@ -162,7 +154,7 @@ jobs:
|
||||
test_extensions.py
|
||||
timeout-minutes: 15
|
||||
|
||||
- name: Run admin tests (Runs in ubuntu:${{ matrix.ubuntu_version }} derived image)
|
||||
- name: Run admin tests (Runs in ${{ matrix.distro_image }} derived image)
|
||||
run: |
|
||||
.github/integration-test.py run-test admin-tests \
|
||||
--installer-args "--admin admin:admin" \
|
||||
@@ -171,7 +163,7 @@ jobs:
|
||||
test_admin_installer.py
|
||||
timeout-minutes: 15
|
||||
|
||||
- name: Run plugin tests (Runs in ubuntu:${{ matrix.ubuntu_version }} derived image)
|
||||
- name: Run plugin tests (Runs in ${{ matrix.distro_image }} derived image)
|
||||
run: |
|
||||
.github/integration-test.py run-test plugin-tests \
|
||||
--bootstrap-pip-spec "$BOOTSTRAP_PIP_SPEC" \
|
||||
|
||||
3
.github/workflows/unit-test.yaml
vendored
3
.github/workflows/unit-test.yaml
vendored
@@ -42,9 +42,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: "Unit tests: Ubuntu 18.04, Py 3.6"
|
||||
ubuntu_version: "18.04"
|
||||
python_version: "3.6"
|
||||
- name: "Unit tests: Ubuntu 20.04, Py 3.9"
|
||||
ubuntu_version: "20.04"
|
||||
python_version: "3.9"
|
||||
|
||||
@@ -36,7 +36,7 @@ might still make breaking changes that have no clear upgrade pathway.
|
||||
## Installation
|
||||
|
||||
The Littlest JupyterHub (TLJH) can run on any server that is running at least
|
||||
**Ubuntu 18.04**. Earlier versions of Ubuntu are not supported.
|
||||
**Ubuntu 20.04**. Earlier versions of Ubuntu are not supported.
|
||||
We have several tutorials to get you started.
|
||||
|
||||
- Tutorials to create a new server from scratch on a cloud provider & run TLJH
|
||||
|
||||
@@ -9,11 +9,10 @@ This script is run as:
|
||||
|
||||
Constraints:
|
||||
|
||||
- The entire script should be compatible with Python 3.6, which is the on
|
||||
Ubuntu 18.04+.
|
||||
- The script should parse in Python 3.5 as we print error messages for using
|
||||
Ubuntu 16.04+ which comes with Python 3.5 by default. This means no
|
||||
f-strings can be used.
|
||||
- The entire script should be compatible with Python 3.8, which is the default on
|
||||
Ubuntu 20.04.
|
||||
- The script should parse in Python 3.6 as we print error messages for using
|
||||
Ubuntu 18.04 which comes with Python 3.6 by default.
|
||||
- The script must depend only on stdlib modules, as no previous installation
|
||||
of dependencies can be assumed.
|
||||
|
||||
@@ -133,6 +132,11 @@ progress_page_html = """
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _parse_version(vs):
|
||||
"""Parse a simple version into a tuple of ints"""
|
||||
return tuple(int(part) for part in vs.split("."))
|
||||
|
||||
|
||||
# This function is needed both by the process starting this script, and by the
|
||||
# TLJH installer that this script execs in the end. Make sure its replica at
|
||||
# tljh/utils.py stays in sync with this version!
|
||||
@@ -200,19 +204,22 @@ def ensure_host_system_can_install_tljh():
|
||||
.strip()
|
||||
)
|
||||
|
||||
# Require Ubuntu 18.04+
|
||||
# Require Ubuntu 20.04+ or Debian 11+
|
||||
distro = get_os_release_variable("ID")
|
||||
version = float(get_os_release_variable("VERSION_ID"))
|
||||
if distro != "ubuntu":
|
||||
print("The Littlest JupyterHub currently supports Ubuntu Linux only")
|
||||
version = get_os_release_variable("VERSION_ID")
|
||||
if distro not in ["ubuntu", "debian"]:
|
||||
print("The Littlest JupyterHub currently supports Ubuntu or Debian Linux only")
|
||||
sys.exit(1)
|
||||
elif float(version) < 18.04:
|
||||
print("The Littlest JupyterHub requires Ubuntu 18.04 or higher")
|
||||
elif distro == "ubuntu" and _parse_version(version) < (20, 4):
|
||||
print("The Littlest JupyterHub requires Ubuntu 20.04 or higher")
|
||||
sys.exit(1)
|
||||
elif distro == "debian" and _parse_version(version) < (11,):
|
||||
print("The Littlest JupyterHub requires Debian 11 or higher")
|
||||
sys.exit(1)
|
||||
|
||||
# Require Python 3.6+
|
||||
if sys.version_info < (3, 6):
|
||||
print("bootstrap.py must be run with at least Python 3.6")
|
||||
# Require Python 3.8+
|
||||
if sys.version_info < (3, 8):
|
||||
print(f"bootstrap.py must be run with at least Python 3.8, found {sys.version}")
|
||||
sys.exit(1)
|
||||
|
||||
# Require systemd (systemctl is a part of systemd)
|
||||
@@ -228,6 +235,7 @@ def ensure_host_system_can_install_tljh():
|
||||
"For local development, see http://tljh.jupyter.org/en/latest/contributing/dev-setup.html"
|
||||
)
|
||||
sys.exit(1)
|
||||
return distro, version
|
||||
|
||||
|
||||
class ProgressPageRequestHandler(SimpleHTTPRequestHandler):
|
||||
@@ -330,7 +338,7 @@ def main():
|
||||
start a local webserver temporarily and report its installation progress via
|
||||
a web site served locally on port 80.
|
||||
"""
|
||||
ensure_host_system_can_install_tljh()
|
||||
distro, version = ensure_host_system_can_install_tljh()
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("--show-progress-page", action="store_true")
|
||||
@@ -425,7 +433,9 @@ def main():
|
||||
["apt-get", "install", "--yes", "software-properties-common"],
|
||||
env=apt_get_adjusted_env,
|
||||
)
|
||||
run_subprocess(["add-apt-repository", "universe", "--yes"])
|
||||
# Section "universe" exists and is required only in ubuntu.
|
||||
if distro == "ubuntu":
|
||||
run_subprocess(["add-apt-repository", "universe", "--yes"])
|
||||
run_subprocess(["apt-get", "update"])
|
||||
run_subprocess(
|
||||
[
|
||||
@@ -436,6 +446,7 @@ def main():
|
||||
"python3-venv",
|
||||
"python3-pip",
|
||||
"git",
|
||||
"sudo", # sudo is missing in default debian install
|
||||
],
|
||||
env=apt_get_adjusted_env,
|
||||
)
|
||||
|
||||
2
docs/howto/env/user-environment.rst
vendored
2
docs/howto/env/user-environment.rst
vendored
@@ -170,7 +170,7 @@ To upgrade the Python version of the user environment, one can:
|
||||
|
||||
* **Upgrade Python manually.**
|
||||
|
||||
Because upgrading Python for existing installs can break packages alaredy installed
|
||||
Because upgrading Python for existing installs can break packages already installed
|
||||
under the old Python, upgrading your current TLJH installation, will NOT upgrade
|
||||
the Python version of the user environment, but you may do so manually.
|
||||
|
||||
|
||||
@@ -17,7 +17,10 @@ might still make breaking changes that have no clear upgrade pathway.
|
||||
Installation
|
||||
============
|
||||
|
||||
The Littlest JupyterHub (TLJH) can run on any server that is running **Ubuntu 18.04** or **Ubuntu 20.04** on a amd64 or arm64 CPU architecture. Earlier versions of Ubuntu are not supported.
|
||||
The Littlest JupyterHub (TLJH) can run on any server that is running **Debian 11** or **Ubuntu 20.04** or **22.04** on an amd64 or arm64 CPU architecture.
|
||||
We aim to support 'stable' and Long-Term Support (LTS) versions.
|
||||
Newer versions are likely to work with little or no adjustment, but these are not officially supported or tested.
|
||||
Earlier versions of Ubuntu and Debian are not supported, nor are other Linux distributions.
|
||||
We have a bunch of tutorials to get you started.
|
||||
|
||||
- Tutorials to create a new server from scratch on a cloud provider & run TLJH
|
||||
|
||||
@@ -58,15 +58,15 @@ Let's create the server on which we can run JupyterHub.
|
||||
#. On the page **Step 1: Choose an Amazon Machine Image (AMI)** you are going
|
||||
to pick the base image your remote server will have. The view will
|
||||
default to the 'Quick-start' tab selected and just a few down the page, select
|
||||
**Ubuntu Server 18.04 LTS (HVM), SSD Volume Type - ami-XXXXXXXXXXXXXXXXX**,
|
||||
**Ubuntu Server 22.04 LTS (HVM), SSD Volume Type - ami-XXXXXXXXXXXXXXXXX**,
|
||||
leaving `64-bit (x86)` toggled.
|
||||
|
||||
.. image:: ../images/providers/amazon/select_ubuntu_18.png
|
||||
:alt: Click Ubuntu server 18.04
|
||||
:alt: Click Ubuntu server 22.04
|
||||
|
||||
The `ami` alpha-numeric at the end references the specific Amazon machine
|
||||
image, ignore this as Amazon updates them routinely. The
|
||||
**Ubuntu Server 18.04 LTS (HVM)** is the important part.
|
||||
**Ubuntu Server 22.04 LTS (HVM)** is the important part.
|
||||
|
||||
|
||||
#. After selecting the AMI, you'll be at **Step 2: Choose an Instance Type**.
|
||||
|
||||
@@ -52,7 +52,7 @@ A new screen with all the options for Virtual Machines in Azure will displayed.
|
||||
:alt: Create VM from the marketplace
|
||||
|
||||
#. **Choose an Ubuntu server for your VM**:
|
||||
* Click `Ubuntu Server 18.04 LTS.`
|
||||
* Click `Ubuntu Server 22.04 LTS.`
|
||||
* Make sure `Resource Manager` is selected in the next screen and click **Create**
|
||||
|
||||
.. image:: ../images/providers/azure/ubuntu-vm.png
|
||||
@@ -70,7 +70,7 @@ A new screen with all the options for Virtual Machines in Azure will displayed.
|
||||
* **Name**. Use a descriptive name for your virtual machine (note that you cannot use spaces or special characters).
|
||||
* **Region**. Choose a location near where you expect your users to be located.
|
||||
* **Availability options**. Choose "No infrastructure redundancy required".
|
||||
* **Image**. Make sure "Ubuntu Server 18.04 LTS" is selected (from the previous step).
|
||||
* **Image**. Make sure "Ubuntu Server 22.04 LTS" is selected (from the previous step).
|
||||
* **Authentication type**. Change authentication type to "password".
|
||||
* **Username**. Choose a memorable username, this will be your "root" user, and you'll need it later on.
|
||||
* **Password**. Type in a password, this will be used later for admin access so make sure it is something memorable.
|
||||
|
||||
@@ -31,7 +31,7 @@ Pre-requisites
|
||||
==============
|
||||
|
||||
#. Some familiarity with the command line.
|
||||
#. A server running Ubuntu 18.04 where you have root access.
|
||||
#. A server running Ubuntu 20.04+ where you have root access (Ubuntu 22.04 LTS recommended).
|
||||
#. At least **1GB** of RAM on your server.
|
||||
#. Ability to ``ssh`` into the server & run commands from the prompt.
|
||||
#. An **IP address** where the server can be reached from the browsers of your target audience.
|
||||
|
||||
@@ -34,10 +34,10 @@ Let's create the server on which we can run JupyterHub.
|
||||
This takes you to a page titled **Create Droplets** that lets you configure
|
||||
your server.
|
||||
|
||||
#. Under **Choose an image**, select **18.04 x64** under **Ubuntu**.
|
||||
#. Under **Choose an image**, select **22.04 x64** under **Ubuntu**.
|
||||
|
||||
.. image:: ../images/providers/digitalocean/select-image.png
|
||||
:alt: Select 18.04 x64 image under Ubuntu
|
||||
:alt: Select 22.04 x64 image under Ubuntu
|
||||
|
||||
#. Under **Choose a size**, select the size of the server you want. The default
|
||||
(4GB RAM, 2CPUs, 20 USD / month) is not a bad start. You can resize your server
|
||||
|
||||
@@ -94,10 +94,10 @@ Let's create the server on which we can run JupyterHub.
|
||||
|
||||
This should open a **Boot disk** popup.
|
||||
|
||||
#. Select **Ubuntu 18.04 LTS** from the list of operating system images.
|
||||
#. Select **Ubuntu 22.04 LTS** from the list of operating system images.
|
||||
|
||||
.. image:: ../images/providers/google/boot-disk-ubuntu.png
|
||||
:alt: Selecting Ubuntu 18.04 for OS
|
||||
:alt: Selecting Ubuntu 22.04 for OS
|
||||
|
||||
#. You can also change the **type** and **size** of your disk at the bottom
|
||||
of this popup.
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
Installing
|
||||
==========
|
||||
|
||||
The Littlest JupyterHub (TLJH) can run on any server that is running at least
|
||||
**Ubuntu 18.04**. Earlier versions of Ubuntu are not supported.
|
||||
The Littlest JupyterHub (TLJH) can run on any server that is running **Debian 11** or **Ubuntu 20.04** or **22.04** on a amd64 or arm64 CPU architecture.
|
||||
Earlier versions of Ubuntu and Debian are not supported, nor are other Linux distributions.
|
||||
We have a bunch of tutorials to get you started.
|
||||
|
||||
Tutorials to create a new server from scratch on a cloud provider & run TLJH
|
||||
|
||||
@@ -33,11 +33,11 @@ Let's create the server on which we can run JupyterHub.
|
||||
This takes you to a page with a list of base images you can choose for your
|
||||
server.
|
||||
|
||||
#. Under **Image Search**, search for **Ubuntu 18.04**, and select the
|
||||
**Ubuntu 18.04 Devel and Docker** image.
|
||||
#. Under **Image Search**, search for **Ubuntu 22.04**, and select the
|
||||
**Ubuntu 22.04 Devel and Docker** image.
|
||||
|
||||
.. image:: ../images/providers/jetstream/select-image.png
|
||||
:alt: Select Ubuntu 18.04 x64 image from image list
|
||||
:alt: Select Ubuntu 22.04 x64 image from image list
|
||||
|
||||
#. Once selected, you will see more information about this image. Click the
|
||||
**Launch** button on the top right.
|
||||
|
||||
@@ -52,10 +52,10 @@ Let's create the server on which we can run JupyterHub.
|
||||
|
||||
#. **Select a region**.
|
||||
|
||||
#. Select **Ubuntu 18.04** as the image:
|
||||
#. Select **Ubuntu 22.04** as the image:
|
||||
|
||||
.. image:: ../images/providers/ovh/distribution.png
|
||||
:alt: Select Ubuntu 18.04 as the image
|
||||
:alt: Select Ubuntu 22.04 as the image
|
||||
|
||||
#. OVH requires setting an SSH key to be able to connect to the instance.
|
||||
You can create a new SSH by following
|
||||
|
||||
@@ -7,7 +7,7 @@ Server Requirements
|
||||
Operating System
|
||||
================
|
||||
|
||||
We require using Ubuntu 18.04 as the base operating system for your server.
|
||||
We require using Ubuntu >=20.04 as the base operating system for your server.
|
||||
|
||||
Root access
|
||||
===========
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Systemd inside a Docker container, for CI only
|
||||
ARG ubuntu_version=20.04
|
||||
FROM ubuntu:${ubuntu_version}
|
||||
ARG BASE_IMAGE=ubuntu:20.04
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# DEBIAN_FRONTEND is set to avoid being asked for input and hang during build:
|
||||
# https://anonoz.github.io/tech/2020/04/24/docker-build-stuck-tzdata.html
|
||||
@@ -11,6 +11,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \
|
||||
curl \
|
||||
git \
|
||||
sudo \
|
||||
python3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Kill all the things we don't need
|
||||
|
||||
@@ -6,6 +6,8 @@ import os
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
BASE_IMAGE = os.getenv("BASE_IMAGE", "ubuntu:20.04")
|
||||
|
||||
|
||||
def install_pkgs(container_name, show_progress_page):
|
||||
# Install python3 inside the ubuntu container
|
||||
@@ -13,7 +15,7 @@ def install_pkgs(container_name, show_progress_page):
|
||||
pkgs = ["python3"]
|
||||
if show_progress_page:
|
||||
pkgs += ["systemd", "git", "curl"]
|
||||
# Create the sudoers dir, so that the installer succesfully gets to the
|
||||
# Create the sudoers dir, so that the installer successfully gets to the
|
||||
# point of starting jupyterhub and stopping the progress page server.
|
||||
subprocess.check_output(
|
||||
["docker", "exec", container_name, "mkdir", "-p", "etc/sudoers.d"]
|
||||
@@ -128,15 +130,15 @@ def test_ubuntu_too_old():
|
||||
"""
|
||||
Error with a useful message when running in older Ubuntu
|
||||
"""
|
||||
output = run_bootstrap_after_preparing_container("old-distro-test", "ubuntu:16.04")
|
||||
assert output.stdout == "The Littlest JupyterHub requires Ubuntu 18.04 or higher\n"
|
||||
output = run_bootstrap_after_preparing_container("old-distro-test", "ubuntu:18.04")
|
||||
assert output.stdout == "The Littlest JupyterHub requires Ubuntu 20.04 or higher\n"
|
||||
assert output.returncode == 1
|
||||
|
||||
|
||||
def test_inside_no_systemd_docker():
|
||||
output = run_bootstrap_after_preparing_container(
|
||||
"plain-docker-test",
|
||||
f"ubuntu:{os.getenv('UBUNTU_VERSION', '20.04')}",
|
||||
BASE_IMAGE,
|
||||
)
|
||||
assert "Systemd is required to run TLJH" in output.stdout
|
||||
assert output.returncode == 1
|
||||
@@ -172,7 +174,7 @@ def test_progress_page():
|
||||
installer = executor.submit(
|
||||
run_bootstrap_after_preparing_container,
|
||||
"progress-page",
|
||||
f"ubuntu:{os.getenv('UBUNTU_VERSION', '20.04')}",
|
||||
BASE_IMAGE,
|
||||
True,
|
||||
)
|
||||
|
||||
|
||||
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="the-littlest-jupyterhub",
|
||||
version="0.2.0",
|
||||
version="1.0.0.dev0",
|
||||
description="A small JupyterHub distribution",
|
||||
url="https://github.com/jupyterhub/the-littlest-jupyterhub",
|
||||
author="Jupyter Development Team",
|
||||
|
||||
Reference in New Issue
Block a user