From a81063385c609cd6ecd3fdcb686e79e0774c71ff Mon Sep 17 00:00:00 2001 From: George Hunt Date: Mon, 8 Mar 2021 01:57:10 +0000 Subject: [PATCH 01/62] venv runs without jupyterlab-vim --- .gitignore | 1 + roles/jupyter/defaults/main.yml | 2 ++ roles/jupyter/tasks/install.yml | 17 +++++++++++++++++ roles/jupyter/tasks/main.yml | 23 +++++++++++++++++++++++ vars/default_vars.yml | 2 ++ 5 files changed, 45 insertions(+) create mode 100644 roles/jupyter/defaults/main.yml create mode 100644 roles/jupyter/tasks/install.yml create mode 100644 roles/jupyter/tasks/main.yml diff --git a/.gitignore b/.gitignore index fc4b12be2..38f8427ed 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ deprecated *.patches *.log *.retry +*~ diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml new file mode 100644 index 000000000..017b0de30 --- /dev/null +++ b/roles/jupyter/defaults/main.yml @@ -0,0 +1,2 @@ +notebook_dir: /opt/iiab/notebook +jupyter_venv: /opt/iiab/jupyter diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml new file mode 100644 index 000000000..3330ba743 --- /dev/null +++ b/roles/jupyter/tasks/install.yml @@ -0,0 +1,17 @@ +- name: Make the directories to hold notebooks + file: + state: directory + path: '{{ notebook_dir }}' + +- name: Use pip to install into a virtual environment + pip: + name: + - jupyterlab + #- jupyter_vim + virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv_site_packages: no + virtualenv_command: /usr/bin/virtualenv + virtualenv_python: python3 + extra_args: "--no-cache-dir" + when: internet_available + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml new file mode 100644 index 000000000..9f1804b38 --- /dev/null +++ b/roles/jupyter/tasks/main.yml @@ -0,0 +1,23 @@ +- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: jupyter_installed is undefined + + +#- include_tasks: enable-or-disable.yml + + +- name: Add 'jupyter' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: jupyter + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Jupyter + - option: description + value: '"Raspberry Pi Jupyter python programming environment"' + - option: install + value: "{{ jupyter_install }}" + - option: enabled + value: "{{ jupyter_enabled }}" diff --git a/vars/default_vars.yml b/vars/default_vars.yml index 1f7351cc9..c6be2eeea 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -559,6 +559,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False +jupyter_install: False +jupyter_enabled: False # 9-LOCAL-ADDONS From 4c6f26d8df4f809fd518a3b70b4dfc1062fe14b5 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 04:57:33 +0000 Subject: [PATCH 02/62] Found instructions for the Littlest Jupyterhub --- roles/jupyter/tasks/enable-or-disable.yml | 25 +++++++++++++++++++++++ roles/jupyter/tasks/install.yml | 19 ++++++++++++++--- roles/jupyter/tasks/main.yml | 2 +- roles/jupyter/templates/jupyter.service | 11 ++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 roles/jupyter/tasks/enable-or-disable.yml create mode 100644 roles/jupyter/templates/jupyter.service diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml new file mode 100644 index 000000000..ad8bb17ad --- /dev/null +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -0,0 +1,25 @@ +- name: systemd daemon-reload + systemd: + daemon_reload: yes + + +# enable or disable +- name: Enable & Restart jupyterhub + systemd: + name: "{{ item }}" + enabled: yes + state: restarted + with_items: + - jupyter + when: jupyter_enabled + +- name: Disable jupyterhub + systemd: + name: "{{ item }}" + enabled: no + state: stopped + with_items: + - jupyter + when: not jupyter_enabled + + diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 3330ba743..4e2981584 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,13 +1,16 @@ - name: Make the directories to hold notebooks file: state: directory - path: '{{ notebook_dir }}' + path: '{{ item }}' + with_items: + - '{{ notebook_dir }}/etc/jupyter' + - '{{ notebook_dir }}/etc/jupyterhub' + - '{{ notebook_dir }}/etc/systemd' - name: Use pip to install into a virtual environment pip: name: - - jupyterlab - #- jupyter_vim + - pip virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -15,3 +18,13 @@ extra_args: "--no-cache-dir" when: internet_available +- name: Fetch the Littlest JupyterHub code + ansible.builtin.git: + repo: '{{ jupyterhub_url }} + dest: '{{ jupyter_venv }}' + +- name: Install a bootstrap.py that permits installation on other than Ubunt + template: + src: bootstrap.py + dest: '{{ jupyter_venv }}' + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml index 9f1804b38..137a01b84 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyter/tasks/main.yml @@ -3,7 +3,7 @@ when: jupyter_installed is undefined -#- include_tasks: enable-or-disable.yml +- include_tasks: enable-or-disable.yml - name: Add 'jupyter' variable values to {{ iiab_ini_file }} diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service new file mode 100644 index 000000000..81cee0dd2 --- /dev/null +++ b/roles/jupyter/templates/jupyter.service @@ -0,0 +1,11 @@ +[Unit] +Description=JupyterHub +After=syslog.target network.target + +[Service] +User=hubuser +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" +ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py + +[Install] +WantedBy=multi-user.target From 7dec8d9648727c67d4ad1bd4e44fcb08b112d91c Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 19:56:46 +0000 Subject: [PATCH 03/62] changes to venv --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index 017b0de30..c879b76ac 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,2 +1,3 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter +jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 4e2981584..b311464b6 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -11,6 +11,8 @@ pip: name: - pip + - wheel + - ipywidgets virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv From 5c57aff11dcaea9e5ff9a13ea1bd13417c6a8573 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 22:57:39 +0000 Subject: [PATCH 04/62] displayed the ted notebook on raspi-os --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 44 +- roles/jupyter/templates/jupyter.service | 4 +- roles/jupyter/templates/jupyterhub_config.py | 1231 +++++++++++++++++ .../templates/gateway/iiab-gen-iptables | 4 +- 5 files changed, 1269 insertions(+), 15 deletions(-) create mode 100644 roles/jupyter/templates/jupyterhub_config.py diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index c879b76ac..b22730df0 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,3 +1,4 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_port: 8000 diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index b311464b6..0c2526856 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -3,9 +3,29 @@ state: directory path: '{{ item }}' with_items: - - '{{ notebook_dir }}/etc/jupyter' - - '{{ notebook_dir }}/etc/jupyterhub' - - '{{ notebook_dir }}/etc/systemd' + - '{{ jupyter_venv }}/etc/jupyter' + - '{{ jupyter_venv }}/etc/jupyterhub' + - '{{ jupyter_venv }}/etc/systemd' + +- name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" + set_fact: + nodejs_install: True + nodejs_enabled: True + +- name: NODEJS - run 'nodejs' role (attempt to install & enable Node.js) + include_role: + name: nodejs + +- name: FAIL (STOP THE INSTALL) IF 'nodejs_installed is undefined' + fail: + msg: "Jupyter install cannot proceed, as Node.js is not installed." + when: nodejs_installed is undefined + +- name: use npm to install configurable http proxy + npm: + name: configurable-http-proxy + global: yes + state: latest - name: Use pip to install into a virtual environment pip: @@ -13,6 +33,8 @@ - pip - wheel - ipywidgets + - jupyterhub + - jupyterlab virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -20,13 +42,11 @@ extra_args: "--no-cache-dir" when: internet_available -- name: Fetch the Littlest JupyterHub code - ansible.builtin.git: - repo: '{{ jupyterhub_url }} - dest: '{{ jupyter_venv }}' - -- name: Install a bootstrap.py that permits installation on other than Ubunt +- name: Install the config file for jupyterhub template: - src: bootstrap.py - dest: '{{ jupyter_venv }}' - + src: jupyterhub_config.py + dest: '{{ jupyter_venv }}/env/jupyterhub/' +- name: Use systemd to start jupyterhub + template: + src: jupyter.service + dest: /etc/systemd/system/ diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 81cee0dd2..363390a9f 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=hubuser -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" -ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" +ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py new file mode 100644 index 000000000..00c70a126 --- /dev/null +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -0,0 +1,1231 @@ +# Configuration file for jupyterhub. + +#------------------------------------------------------------------------------ +# Application(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## This is an application. + +## The date format used by logging formatters for %(asctime)s +# Default: '%Y-%m-%d %H:%M:%S' +# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# Default: '[%(name)s]%(highlevel)s %(message)s' +# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] +# Default: 30 +# c.Application.log_level = 30 + +## Instead of starting the Application, dump configuration to stdout +# Default: False +# c.Application.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# Default: False +# c.Application.show_config_json = False + +#------------------------------------------------------------------------------ +# JupyterHub(Application) configuration +#------------------------------------------------------------------------------ +## An Application for starting a Multi-User Jupyter Notebook server. + +## Maximum number of concurrent servers that can be active at a time. +# +# Setting this can limit the total resources your users can consume. +# +# An active server is any server that's not fully stopped. It is considered +# active from the time it has been requested until the time that it has +# completely stopped. +# +# If this many user servers are active, users will not be able to launch new +# servers until a server is shutdown. Spawn requests will be rejected with a 429 +# error asking them to try again. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.active_server_limit = 0 + +## Duration (in seconds) to determine the number of active users. +# Default: 1800 +# c.JupyterHub.active_user_window = 1800 + +## Resolution (in seconds) for updating activity +# +# If activity is registered that is less than activity_resolution seconds more +# recent than the current value, the new value will be ignored. +# +# This avoids too many writes to the Hub database. +# Default: 30 +# c.JupyterHub.activity_resolution = 30 + +## Grant admin users permission to access single-user servers. +# +# Users should be properly informed if this is enabled. +# Default: False +# c.JupyterHub.admin_access = False + +## DEPRECATED since version 0.7.2, use Authenticator.admin_users instead. +# Default: set() +# c.JupyterHub.admin_users = set() + +## Allow named single-user servers per user +# Default: False +# c.JupyterHub.allow_named_servers = False + +## Answer yes to any questions (e.g. confirm overwrite) +# Default: False +# c.JupyterHub.answer_yes = False + +## PENDING DEPRECATION: consider using services +# +# Dict of token:username to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services, which authenticate as JupyterHub users. +# +# Consider using services for general services that talk to the JupyterHub API. +# Default: {} +# c.JupyterHub.api_tokens = {} + +## Authentication for prometheus metrics +# Default: True +# c.JupyterHub.authenticate_prometheus = True + +## Class for authenticating users. +# +# This should be a subclass of :class:`jupyterhub.auth.Authenticator` +# +# with an :meth:`authenticate` method that: +# +# - is a coroutine (asyncio or tornado) +# - returns username on success, None on failure +# - takes two arguments: (handler, data), +# where `handler` is the calling web.RequestHandler, +# and `data` is the POST form data from the login page. +# +# .. versionchanged:: 1.0 +# authenticators may be registered via entry points, +# e.g. `c.JupyterHub.authenticator_class = 'pam'` +# +# Currently installed: +# - default: jupyterhub.auth.PAMAuthenticator +# - dummy: jupyterhub.auth.DummyAuthenticator +# - pam: jupyterhub.auth.PAMAuthenticator +# Default: 'jupyterhub.auth.PAMAuthenticator' +# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' + +## The base URL of the entire application. +# +# Add this to the beginning of all JupyterHub URLs. Use base_url to run +# JupyterHub within an existing website. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '/' +# c.JupyterHub.base_url = '/' + +## The public facing URL of the whole JupyterHub application. +# +# This is the address on which the proxy will bind. Sets protocol, ip, base_url +# Default: 'http://:8000' +# c.JupyterHub.bind_url = 'http://:8000' + +## Whether to shutdown the proxy when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the proxy +# running. +# +# Only valid if the proxy was starting by the Hub process. +# +# If both this and cleanup_servers are False, sending SIGINT to the Hub will +# only shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_proxy = True + +## Whether to shutdown single-user servers when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the single- +# user servers running. +# +# If both this and cleanup_proxy are False, sending SIGINT to the Hub will only +# shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_servers = True + +## Maximum number of concurrent users that can be spawning at a time. +# +# Spawning lots of servers at the same time can cause performance problems for +# the Hub or the underlying spawning system. Set this limit to prevent bursts of +# logins from attempting to spawn too many servers at the same time. +# +# This does not limit the number of total running servers. See +# active_server_limit for that. +# +# If more than this many users attempt to spawn at a time, their requests will +# be rejected with a 429 error asking them to try again. Users will have to wait +# for some of the spawning services to finish starting before they can start +# their own. +# +# If set to 0, no limit is enforced. +# Default: 100 +# c.JupyterHub.concurrent_spawn_limit = 100 + +## The config file to load +# Default: 'jupyterhub_config.py' +# c.JupyterHub.config_file = 'jupyterhub_config.py' + +## DEPRECATED: does nothing +# Default: False +# c.JupyterHub.confirm_no_ssl = False + +## Number of days for a login cookie to be valid. Default is two weeks. +# Default: 14 +# c.JupyterHub.cookie_max_age_days = 14 + +## The cookie secret to use to encrypt cookies. +# +# Loaded from the JPY_COOKIE_SECRET env variable by default. +# +# Should be exactly 256 bits (32 bytes). +# Default: b'' +# c.JupyterHub.cookie_secret = b'' + +## File in which to store the cookie secret. +# Default: 'jupyterhub_cookie_secret' +# c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' + +## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) +# Default: '/opt/iiab/jupyter/share/jupyterhub' +# c.JupyterHub.data_files_path = '/opt/iiab/jupyter/share/jupyterhub' + +## Include any kwargs to pass to the database connection. See +# sqlalchemy.create_engine for details. +# Default: {} +# c.JupyterHub.db_kwargs = {} + +## url for the database. e.g. `sqlite:///jupyterhub.sqlite` +# Default: 'sqlite:///jupyterhub.sqlite' +# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' + +## log all database transactions. This has A LOT of output +# Default: False +# c.JupyterHub.debug_db = False + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.debug +# Default: False +# c.JupyterHub.debug_proxy = False + +## If named servers are enabled, default name of server to spawn or open, e.g. by +# user-redirect. +# Default: '' +# c.JupyterHub.default_server_name = '' + +## The default URL for users when they arrive (e.g. when user directs to "/") +# +# By default, redirects users to their own server. +# +# Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler +# object: +# +# :: +# +# def default_url_fn(handler): +# user = handler.current_user +# if user and user.admin: +# return '/hub/admin' +# return '/hub/home' +# +# c.JupyterHub.default_url = default_url_fn +# Default: traitlets.Undefined +# c.JupyterHub.default_url = traitlets.Undefined + +## Dict authority:dict(files). Specify the key, cert, and/or ca file for an +# authority. This is useful for externally managed proxies that wish to use +# internal_ssl. +# +# The files dict has this format (you must specify at least a cert):: +# +# { +# 'key': '/path/to/key.key', +# 'cert': '/path/to/cert.crt', +# 'ca': '/path/to/ca.crt' +# } +# +# The authorities you can override: 'hub-ca', 'notebooks-ca', 'proxy-api-ca', +# 'proxy-client-ca', and 'services-ca'. +# +# Use with internal_ssl +# Default: {} +# c.JupyterHub.external_ssl_authorities = {} + +## Register extra tornado Handlers for jupyterhub. +# +# Should be of the form ``("", Handler)`` +# +# The Hub prefix will be added, so `/my-page` will be served at `/hub/my-page`. +# Default: [] +# c.JupyterHub.extra_handlers = [] + +## DEPRECATED: use output redirection instead, e.g. +# +# jupyterhub &>> /var/log/jupyterhub.log +# Default: '' +# c.JupyterHub.extra_log_file = '' + +## Extra log handlers to set on JupyterHub logger +# Default: [] +# c.JupyterHub.extra_log_handlers = [] + +## Generate certs used for internal ssl +# Default: False +# c.JupyterHub.generate_certs = False + +## Generate default config file +# Default: False +# c.JupyterHub.generate_config = False + +## The URL on which the Hub will listen. This is a private URL for internal +# communication. Typically set in combination with hub_connect_url. If a unix +# socket, hub_connect_url **must** also be set. +# +# For example: +# +# "http://127.0.0.1:8081" +# "unix+http://%2Fsrv%2Fjupyterhub%2Fjupyterhub.sock" +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_bind_url = '' + +## The ip or hostname for proxies and spawners to use for connecting to the Hub. +# +# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different +# from the connect address. +# +# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, otherwise +# use `hub_ip`. +# +# Note: Some spawners or proxy implementations might not support hostnames. +# Check your spawner or proxy documentation to see if they have extra +# requirements. +# +# .. versionadded:: 0.8 +# Default: '' +# c.JupyterHub.hub_connect_ip = '' + +## DEPRECATED +# +# Use hub_connect_url +# +# .. versionadded:: 0.8 +# +# .. deprecated:: 0.9 +# Use hub_connect_url +# Default: 0 +# c.JupyterHub.hub_connect_port = 0 + +## The URL for connecting to the Hub. Spawners, services, and the proxy will use +# this URL to talk to the Hub. +# +# Only needs to be specified if the default hub URL is not connectable (e.g. +# using a unix+http:// bind url). +# +# .. seealso:: +# JupyterHub.hub_connect_ip +# JupyterHub.hub_bind_url +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_connect_url = '' + +## The ip address for the Hub process to *bind* to. +# +# By default, the hub listens on localhost only. This address must be accessible +# from the proxy and user servers. You may need to set this to a public ip or '' +# for all interfaces if the proxy or user servers are in containers or on a +# different host. +# +# See `hub_connect_ip` for cases where the bind and connect address should +# differ, or `hub_bind_url` for setting the full bind URL. +# Default: '127.0.0.1' +# c.JupyterHub.hub_ip = '127.0.0.1' + +## The internal port for the Hub process. +# +# This is the internal port of the hub itself. It should never be accessed +# directly. See JupyterHub.port for the public port to use when accessing +# jupyterhub. It is rare that this port should be set except in cases of port +# conflict. +# +# See also `hub_ip` for the ip and `hub_bind_url` for setting the full bind URL. +# Default: 8081 +# c.JupyterHub.hub_port = 8081 + +## Trigger implicit spawns after this many seconds. +# +# When a user visits a URL for a server that's not running, they are shown a +# page indicating that the requested server is not running with a button to +# spawn the server. +# +# Setting this to a positive value will redirect the user after this many +# seconds, effectively clicking this button automatically for the users, +# automatically beginning the spawn process. +# +# Warning: this can result in errors and surprising behavior when sharing access +# URLs to actual servers, since the wrong server is likely to be started. +# Default: 0 +# c.JupyterHub.implicit_spawn_seconds = 0 + +## Timeout (in seconds) to wait for spawners to initialize +# +# Checking if spawners are healthy can take a long time if many spawners are +# active at hub start time. +# +# If it takes longer than this timeout to check, init_spawner will be left to +# complete in the background and the http server is allowed to start. +# +# A timeout of -1 means wait forever, which can mean a slow startup of the Hub +# but ensures that the Hub is fully consistent by the time it starts responding +# to requests. This matches the behavior of jupyterhub 1.0. +# +# .. versionadded: 1.1.0 +# Default: 10 +# c.JupyterHub.init_spawners_timeout = 10 + +## The location to store certificates automatically created by JupyterHub. +# +# Use with internal_ssl +# Default: 'internal-ssl' +# c.JupyterHub.internal_certs_location = 'internal-ssl' + +## Enable SSL for all internal communication +# +# This enables end-to-end encryption between all JupyterHub components. +# JupyterHub will automatically create the necessary certificate authority and +# sign notebook certificates as they're created. +# Default: False +# c.JupyterHub.internal_ssl = False + +## The public facing ip of the whole JupyterHub application (specifically +# referred to as the proxy). +# +# This is the address on which the proxy will listen. The default is to listen +# on all interfaces. This is the only address through which JupyterHub should be +# accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '' +# c.JupyterHub.ip = '' + +## Supply extra arguments that will be passed to Jinja environment. +# Default: {} +# c.JupyterHub.jinja_environment_options = {} + +## Interval (in seconds) at which to update last-activity timestamps. +# Default: 300 +# c.JupyterHub.last_activity_interval = 300 + +## Dict of 'group': ['usernames'] to load at startup. +# +# This strictly *adds* groups and users to groups. +# +# Loading one set of groups, then starting JupyterHub again with a different set +# will not remove users or groups from previous launches. That must be done +# through the API. +# Default: {} +# c.JupyterHub.load_groups = {} + +## The date format used by logging formatters for %(asctime)s +# See also: Application.log_datefmt +# c.JupyterHub.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# See also: Application.log_format +# c.JupyterHub.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# See also: Application.log_level +# c.JupyterHub.log_level = 30 + +## Specify path to a logo image to override the Jupyter logo in the banner. +# Default: '' +# c.JupyterHub.logo_file = '' + +## Maximum number of concurrent named servers that can be created by a user at a +# time. +# +# Setting this can limit the total resources a user can consume. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.named_server_limit_per_user = 0 + +## File to write PID Useful for daemonizing JupyterHub. +# Default: '' +# c.JupyterHub.pid_file = '' + +## The public facing port of the proxy. +# +# This is the port on which the proxy will listen. This is the only port through +# which JupyterHub should be accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: 8000 +# c.JupyterHub.port = 8000 + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: '' +# c.JupyterHub.proxy_api_ip = '' + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: 0 +# c.JupyterHub.proxy_api_port = 0 + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.auth_token +# Default: '' +# c.JupyterHub.proxy_auth_token = '' + +## Interval (in seconds) at which to check if the proxy is running. +# Default: 30 +# c.JupyterHub.proxy_check_interval = 30 + +## The class to use for configuring the JupyterHub proxy. +# +# Should be a subclass of :class:`jupyterhub.proxy.Proxy`. +# +# .. versionchanged:: 1.0 +# proxies may be registered via entry points, +# e.g. `c.JupyterHub.proxy_class = 'traefik'` +# +# Currently installed: +# - configurable-http-proxy: jupyterhub.proxy.ConfigurableHTTPProxy +# - default: jupyterhub.proxy.ConfigurableHTTPProxy +# Default: 'jupyterhub.proxy.ConfigurableHTTPProxy' +# c.JupyterHub.proxy_class = 'jupyterhub.proxy.ConfigurableHTTPProxy' + +## DEPRECATED since version 0.8. Use ConfigurableHTTPProxy.command +# Default: [] +# c.JupyterHub.proxy_cmd = [] + +## Recreate all certificates used within JupyterHub on restart. +# +# Note: enabling this feature requires restarting all notebook servers. +# +# Use with internal_ssl +# Default: False +# c.JupyterHub.recreate_internal_certs = False + +## Redirect user to server (if running), instead of control panel. +# Default: True +# c.JupyterHub.redirect_to_server = True + +## Purge and reset the database. +# Default: False +# c.JupyterHub.reset_db = False + +## Interval (in seconds) at which to check connectivity of services with web +# endpoints. +# Default: 60 +# c.JupyterHub.service_check_interval = 60 + +## Dict of token:servicename to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services. +# Default: {} +# c.JupyterHub.service_tokens = {} + +## List of service specification dictionaries. +# +# A service +# +# For instance:: +# +# services = [ +# { +# 'name': 'cull_idle', +# 'command': ['/path/to/cull_idle_servers.py'], +# }, +# { +# 'name': 'formgrader', +# 'url': 'http://127.0.0.1:1234', +# 'api_token': 'super-secret', +# 'environment': +# } +# ] +# Default: [] +# c.JupyterHub.services = [] + +## Instead of starting the Application, dump configuration to stdout +# See also: Application.show_config +# c.JupyterHub.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# See also: Application.show_config_json +# c.JupyterHub.show_config_json = False + +## Shuts down all user servers on logout +# Default: False +# c.JupyterHub.shutdown_on_logout = False + +## The class to use for spawning single-user servers. +# +# Should be a subclass of :class:`jupyterhub.spawner.Spawner`. +# +# .. versionchanged:: 1.0 +# spawners may be registered via entry points, +# e.g. `c.JupyterHub.spawner_class = 'localprocess'` +# +# Currently installed: +# - default: jupyterhub.spawner.LocalProcessSpawner +# - localprocess: jupyterhub.spawner.LocalProcessSpawner +# - simple: jupyterhub.spawner.SimpleLocalProcessSpawner +# Default: 'jupyterhub.spawner.LocalProcessSpawner' +# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' + +## Path to SSL certificate file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_key +# Default: '' +# c.JupyterHub.ssl_cert = '' + +## Path to SSL key file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_cert +# Default: '' +# c.JupyterHub.ssl_key = '' + +## Host to send statsd metrics to. An empty string (the default) disables sending +# metrics. +# Default: '' +# c.JupyterHub.statsd_host = '' + +## Port on which to send statsd metrics about the hub +# Default: 8125 +# c.JupyterHub.statsd_port = 8125 + +## Prefix to use for all metrics sent by jupyterhub to statsd +# Default: 'jupyterhub' +# c.JupyterHub.statsd_prefix = 'jupyterhub' + +## Run single-user servers on subdomains of this host. +# +# This should be the full `https://hub.domain.tld[:port]`. +# +# Provides additional cross-site protections for javascript served by single- +# user servers. +# +# Requires `.hub.domain.tld` to resolve to the same host as +# `hub.domain.tld`. +# +# In general, this is most easily achieved with wildcard DNS. +# +# When using SSL (i.e. always) this also requires a wildcard SSL certificate. +# Default: '' +# c.JupyterHub.subdomain_host = '' + +## Paths to search for jinja templates, before using the default templates. +# Default: [] +# c.JupyterHub.template_paths = [] + +## Extra variables to be passed into jinja templates +# Default: {} +# c.JupyterHub.template_vars = {} + +## Extra settings overrides to pass to the tornado application. +# Default: {} +# c.JupyterHub.tornado_settings = {} + +## Trust user-provided tokens (via JupyterHub.service_tokens) to have good +# entropy. +# +# If you are not inserting additional tokens via configuration file, this flag +# has no effect. +# +# In JupyterHub 0.8, internally generated tokens do not pass through additional +# hashing because the hashing is costly and does not increase the entropy of +# already-good UUIDs. +# +# User-provided tokens, on the other hand, are not trusted to have good entropy +# by default, and are passed through many rounds of hashing to stretch the +# entropy of the key (i.e. user-provided tokens are treated as passwords instead +# of random keys). These keys are more costly to check. +# +# If your inserted tokens are generated by a good-quality mechanism, e.g. +# `openssl rand -hex 32`, then you can set this flag to True to reduce the cost +# of checking authentication tokens. +# Default: False +# c.JupyterHub.trust_user_provided_tokens = False + +## Names to include in the subject alternative name. +# +# These names will be used for server name verification. This is useful if +# JupyterHub is being run behind a reverse proxy or services using ssl are on +# different hosts. +# +# Use with internal_ssl +# Default: [] +# c.JupyterHub.trusted_alt_names = [] + +## Downstream proxy IP addresses to trust. +# +# This sets the list of IP addresses that are trusted and skipped when +# processing the `X-Forwarded-For` header. For example, if an external proxy is +# used for TLS termination, its IP address should be added to this list to +# ensure the correct client IP addresses are recorded in the logs instead of the +# proxy server's IP address. +# Default: [] +# c.JupyterHub.trusted_downstream_ips = [] + +## Upgrade the database automatically on start. +# +# Only safe if database is regularly backed up. Only SQLite databases will be +# backed up to a local file automatically. +# Default: False +# c.JupyterHub.upgrade_db = False + +## Callable to affect behavior of /user-redirect/ +# +# Receives 4 parameters: 1. path - URL path that was provided after /user- +# redirect/ 2. request - A Tornado HTTPServerRequest representing the current +# request. 3. user - The currently authenticated user. 4. base_url - The +# base_url of the current hub, for relative redirects +# +# It should return the new URL to redirect to, or None to preserve current +# behavior. +# Default: None +# c.JupyterHub.user_redirect_hook = None + +#------------------------------------------------------------------------------ +# Spawner(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for spawning single-user notebook servers. +# +# Subclass this, and override the following methods: +# +# - load_state - get_state - start - stop - poll +# +# As JupyterHub supports multiple users, an instance of the Spawner subclass is +# created for each user. If there are 20 JupyterHub users, there will be 20 +# instances of the subclass. + +## Extra arguments to be passed to the single-user server. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables here. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: [] +# c.Spawner.args = [] + +## An optional hook function that you can implement to pass `auth_state` to the +# spawner after it has been initialized but before it starts. The `auth_state` +# dictionary may be set by the `.authenticate()` method of the authenticator. +# This hook enables you to pass some or all of that information to your spawner. +# +# Example:: +# +# def userdata_hook(spawner, auth_state): +# spawner.userdata = auth_state["userdata"] +# +# c.Spawner.auth_state_hook = userdata_hook +# Default: None +# c.Spawner.auth_state_hook = None + +## The command used for starting the single-user server. +# +# Provide either a string or a list containing the path to the startup script +# command. Extra arguments, other than this path, should be provided via `args`. +# +# This is usually set if you want to start the single-user server in a different +# python environment (with virtualenv/conda) than JupyterHub itself. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: ['jupyterhub-singleuser'] +# c.Spawner.cmd = ['jupyterhub-singleuser'] + +## Maximum number of consecutive failures to allow before shutting down +# JupyterHub. +# +# This helps JupyterHub recover from a certain class of problem preventing +# launch in contexts where the Hub is automatically restarted (e.g. systemd, +# docker, kubernetes). +# +# A limit of 0 means no limit and consecutive failures will not be tracked. +# Default: 0 +# c.Spawner.consecutive_failure_limit = 0 + +## Minimum number of cpu-cores a single-user notebook server is guaranteed to +# have available. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_guarantee = None + +## Maximum number of cpu-cores a single-user notebook server is allowed to use. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# The single-user notebook server will never be scheduled by the kernel to use +# more cpu-cores than this. There is no guarantee that it can access this many +# cpu-cores. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_limit = None + +## Enable debug-logging of the single-user server +# Default: False +# c.Spawner.debug = False + +## The URL the single-user server should start in. +# +# `{username}` will be expanded to the user's username +# +# Example uses: +# +# - You can set `notebook_dir` to `/` and `default_url` to `/tree/home/{username}` to allow people to +# navigate the whole filesystem from their notebook server, but still start in their home directory. +# - Start with `/notebooks` instead of `/tree` if `default_url` points to a notebook instead of a directory. +# - You can set this to `/lab` to have JupyterLab start by default, rather than Jupyter Notebook. +# Default: '' +# c.Spawner.default_url = '' + +## Disable per-user configuration of single-user servers. +# +# When starting the user's single-user server, any config file found in the +# user's $HOME directory will be ignored. +# +# Note: a user could circumvent this if the user modifies their Python +# environment, such as when they have their own conda environments / virtualenvs +# / containers. +# Default: False +# c.Spawner.disable_user_config = False + +## List of environment variables for the single-user server to inherit from the +# JupyterHub process. +# +# This list is used to ensure that sensitive information in the JupyterHub +# process's environment (such as `CONFIGPROXY_AUTH_TOKEN`) is not passed to the +# single-user server's process. +# Default: ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] +# c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] + +## Extra environment variables to set for the single-user server's process. +# +# Environment variables that end up in the single-user server's process come from 3 sources: +# - This `environment` configurable +# - The JupyterHub process' environment variables that are listed in `env_keep` +# - Variables to establish contact between the single-user notebook and the hub (such as JUPYTERHUB_API_TOKEN) +# +# The `environment` configurable should be set by JupyterHub administrators to +# add installation specific environment variables. It is a dict where the key is +# the name of the environment variable, and the value can be a string or a +# callable. If it is a callable, it will be called with one parameter (the +# spawner instance), and should return a string fairly quickly (no blocking +# operations please!). +# +# Note that the spawner class' interface is not guaranteed to be exactly same +# across upgrades, so if you are using the callable take care to verify it +# continues to work after upgrades! +# +# .. versionchanged:: 1.2 +# environment from this configuration has highest priority, +# allowing override of 'default' env variables, +# such as JUPYTERHUB_API_URL. +# Default: {} +# c.Spawner.environment = {} + +## Timeout (in seconds) before giving up on a spawned HTTP server +# +# Once a server has successfully been spawned, this is the amount of time we +# wait before assuming that the server is unable to accept connections. +# Default: 30 +# c.Spawner.http_timeout = 30 + +## The IP address (or hostname) the single-user server should listen on. +# +# The JupyterHub proxy implementation should be able to send packets to this +# interface. +# Default: '' +# c.Spawner.ip = '' + +## Minimum number of bytes a single-user notebook server is guaranteed to have +# available. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_guarantee = None + +## Maximum number of bytes a single-user notebook server is allowed to use. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# If the single user server tries to allocate more memory than this, it will +# fail. There is no guarantee that the single-user notebook server will be able +# to allocate this much memory - only that it can not allocate more than this. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_limit = None + +## Path to the notebook directory for the single-user server. +# +# The user sees a file listing of this directory when the notebook interface is +# started. The current interface does not easily allow browsing beyond the +# subdirectories in this directory's tree. +# +# `~` will be expanded to the home directory of the user, and {username} will be +# replaced with the name of the user. +# +# Note that this does *not* prevent users from accessing files outside of this +# path! They can do so with many other means. +# Default: '' +# c.Spawner.notebook_dir = '' + +## An HTML form for options a user can specify on launching their server. +# +# The surrounding `
` element and the submit button are already provided. +# +# For example: +# +# .. code:: html +# +# Set your key: +# +#
+# Choose a letter: +# +# +# The data from this form submission will be passed on to your spawner in +# `self.user_options` +# +# Instead of a form snippet string, this could also be a callable that takes as +# one parameter the current spawner instance and returns a string. The callable +# will be called asynchronously if it returns a future, rather than a str. Note +# that the interface of the spawner class is not deemed stable across versions, +# so using this functionality might cause your JupyterHub upgrades to break. +# Default: traitlets.Undefined +# c.Spawner.options_form = traitlets.Undefined + +## Interpret HTTP form data +# +# Form data will always arrive as a dict of lists of strings. Override this +# function to understand single-values, numbers, etc. +# +# This should coerce form data into the structure expected by self.user_options, +# which must be a dict, and should be JSON-serializeable, though it can contain +# bytes in addition to standard JSON data types. +# +# This method should not have any side effects. Any handling of `user_options` +# should be done in `.start()` to ensure consistent behavior across servers +# spawned via the API and form submission page. +# +# Instances will receive this data on self.user_options, after passing through +# this function, prior to `Spawner.start`. +# +# .. versionchanged:: 1.0 +# user_options are persisted in the JupyterHub database to be reused +# on subsequent spawns if no options are given. +# user_options is serialized to JSON as part of this persistence +# (with additional support for bytes in case of uploaded file data), +# and any non-bytes non-jsonable values will be replaced with None +# if the user_options are re-used. +# Default: traitlets.Undefined +# c.Spawner.options_from_form = traitlets.Undefined + +## Interval (in seconds) on which to poll the spawner for single-user server's +# status. +# +# At every poll interval, each spawner's `.poll` method is called, which checks +# if the single-user server is still running. If it isn't running, then +# JupyterHub modifies its own state accordingly and removes appropriate routes +# from the configurable proxy. +# Default: 30 +# c.Spawner.poll_interval = 30 + +## The port for single-user servers to listen on. +# +# Defaults to `0`, which uses a randomly allocated port number each time. +# +# If set to a non-zero value, all Spawners will use the same port, which only +# makes sense if each server is on a different address, e.g. in containers. +# +# New in version 0.7. +# Default: 0 +# c.Spawner.port = 0 + +## An optional hook function that you can implement to do work after the spawner +# stops. +# +# This can be set independent of any concrete spawner implementation. +# Default: None +# c.Spawner.post_stop_hook = None + +## An optional hook function that you can implement to do some bootstrapping work +# before the spawner starts. For example, create a directory for your user or +# load initial content. +# +# This can be set independent of any concrete spawner implementation. +# +# This maybe a coroutine. +# +# Example:: +# +# from subprocess import check_call +# def my_hook(spawner): +# username = spawner.user.name +# check_call(['./examples/bootstrap-script/bootstrap.sh', username]) +# +# c.Spawner.pre_spawn_hook = my_hook +# Default: None +# c.Spawner.pre_spawn_hook = None + +## List of SSL alt names +# +# May be set in config if all spawners should have the same value(s), or set at +# runtime by Spawner that know their names. +# Default: [] +# c.Spawner.ssl_alt_names = [] + +## Whether to include DNS:localhost, IP:127.0.0.1 in alt names +# Default: True +# c.Spawner.ssl_alt_names_include_local = True + +## Timeout (in seconds) before giving up on starting of single-user server. +# +# This is the timeout for start to return, not the timeout for the server to +# respond. Callers of spawner.start will assume that startup has failed if it +# takes longer than this. start should return when the server process is started +# and its location is known. +# Default: 60 +# c.Spawner.start_timeout = 60 + +#------------------------------------------------------------------------------ +# Authenticator(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for implementing an authentication provider for JupyterHub + +## Set of users that will have admin rights on this JupyterHub. +# +# Admin users have extra privileges: +# - Use the admin panel to see list of users logged in +# - Add / remove users in some authenticators +# - Restart / halt the hub +# - Start / stop users' single-user servers +# - Can access each individual users' single-user server (if configured) +# +# Admin access should be treated the same way root access is. +# +# Defaults to an empty set, in which case no user has admin access. +# Default: set() +# c.Authenticator.admin_users = set() + +## Set of usernames that are allowed to log in. +# +# Use this with supported authenticators to restrict which users can log in. +# This is an additional list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionchanged:: 1.2 +# `Authenticator.whitelist` renamed to `allowed_users` +# Default: set() +# c.Authenticator.allowed_users = set() + +## The max age (in seconds) of authentication info before forcing a refresh of +# user auth info. +# +# Refreshing auth info allows, e.g. requesting/re-validating auth tokens. +# +# See :meth:`.refresh_user` for what happens when user auth info is refreshed +# (nothing by default). +# Default: 300 +# c.Authenticator.auth_refresh_age = 300 + +## Automatically begin the login process +# +# rather than starting with a "Login with..." link at `/hub/login` +# +# To work, `.login_url()` must give a URL other than the default `/hub/login`, +# such as an oauth handler or another automatic login handler, registered with +# `.get_handlers()`. +# +# .. versionadded:: 0.8 +# Default: False +# c.Authenticator.auto_login = False + +## Set of usernames that are not allowed to log in. +# +# Use this with supported authenticators to restrict which users can not log in. +# This is an additional block list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionadded: 0.9 +# +# .. versionchanged:: 1.2 +# `Authenticator.blacklist` renamed to `blocked_users` +# Default: set() +# c.Authenticator.blocked_users = set() + +## Delete any users from the database that do not pass validation +# +# When JupyterHub starts, `.add_user` will be called on each user in the +# database to verify that all users are still valid. +# +# If `delete_invalid_users` is True, any users that do not pass validation will +# be deleted from the database. Use this if users might be deleted from an +# external system, such as local user accounts. +# +# If False (default), invalid users remain in the Hub's database and a warning +# will be issued. This is the default to avoid data loss due to config changes. +# Default: False +# c.Authenticator.delete_invalid_users = False + +## Enable persisting auth_state (if available). +# +# auth_state will be encrypted and stored in the Hub's database. This can +# include things like authentication tokens, etc. to be passed to Spawners as +# environment variables. +# +# Encrypting auth_state requires the cryptography package. +# +# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one +# (or more, separated by ;) 32B encryption keys. These can be either base64 or +# hex-encoded. +# +# If encryption is unavailable, auth_state cannot be persisted. +# +# New in JupyterHub 0.8 +# Default: False +# c.Authenticator.enable_auth_state = False + +## An optional hook function that you can implement to do some bootstrapping work +# during authentication. For example, loading user account details from an +# external system. +# +# This function is called after the user has passed all authentication checks +# and is ready to successfully authenticate. This function must return the +# authentication dict reguardless of changes to it. +# +# This maybe a coroutine. +# +# .. versionadded: 1.0 +# +# Example:: +# +# import os, pwd +# def my_hook(authenticator, handler, authentication): +# user_data = pwd.getpwnam(authentication['name']) +# spawn_data = { +# 'pw_data': user_data +# 'gid_list': os.getgrouplist(authentication['name'], user_data.pw_gid) +# } +# +# if authentication['auth_state'] is None: +# authentication['auth_state'] = {} +# authentication['auth_state']['spawn_data'] = spawn_data +# +# return authentication +# +# c.Authenticator.post_auth_hook = my_hook +# Default: None +# c.Authenticator.post_auth_hook = None + +## Force refresh of auth prior to spawn. +# +# This forces :meth:`.refresh_user` to be called prior to launching a server, to +# ensure that auth state is up-to-date. +# +# This can be important when e.g. auth tokens that may have expired are passed +# to the spawner via environment variables from auth_state. +# +# If refresh_user cannot refresh the user auth data, launch will fail until the +# user logs in again. +# Default: False +# c.Authenticator.refresh_pre_spawn = False + +## Dictionary mapping authenticator usernames to JupyterHub users. +# +# Primarily used to normalize OAuth user names to local users. +# Default: {} +# c.Authenticator.username_map = {} + +## Regular expression pattern that all valid usernames must match. +# +# If a username does not match the pattern specified here, authentication will +# not be attempted. +# +# If not set, allow any username. +# Default: '' +# c.Authenticator.username_pattern = '' + +## Deprecated, use `Authenticator.allowed_users` +# Default: set() +# c.Authenticator.whitelist = set() + +#------------------------------------------------------------------------------ +# CryptKeeper(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## Encapsulate encryption configuration +# +# Use via the encryption_config singleton below. + +# Default: [] +# c.CryptKeeper.keys = [] + +## The number of threads to allocate for encryption +# Default: 4 +# c.CryptKeeper.n_threads = 4 + +#------------------------------------------------------------------------------ +# Pagination(Configurable) configuration +#------------------------------------------------------------------------------ +## Default number of entries per page for paginated results. +# Default: 100 +# c.Pagination.default_per_page = 100 + +## Maximum number of entries per page for paginated results. +# Default: 250 +# c.Pagination.max_per_page = 250 diff --git a/roles/network/templates/gateway/iiab-gen-iptables b/roles/network/templates/gateway/iiab-gen-iptables index f7ee6c7c9..942418a88 100755 --- a/roles/network/templates/gateway/iiab-gen-iptables +++ b/roles/network/templates/gateway/iiab-gen-iptables @@ -73,6 +73,7 @@ pbx_data_ports={{ pbx_data_ports }} sugarizer_port={{ sugarizer_port }} transmission_http_port={{ transmission_http_port }} transmission_peer_port={{ transmission_peer_port }} +jupyterhub_port={{ jupyterhub_port }} samba_udp_ports={{ samba_udp_ports }} samba_tcp_mports={{ samba_tcp_mports }} @@ -167,7 +168,8 @@ if [ "$wan" != "none" ]; then $IPTABLES -A INPUT -p tcp --dport $sugarizer_port -m state --state NEW -i $wan -j ACCEPT $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT - $IPTABLES -A INPUT -p tcp --dport $transmission_peer_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $jupyterhub_port -m state --state NEW -i $wan -j ACCEPT fi # 4 = ssh + http-or-https + common IIAB services + Samba From 5e7cf6839941564d0d027d8156c37e6ff2470f77 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:10:49 +0000 Subject: [PATCH 05/62] systemd spawner is working writing to /var/lib/private --- roles/jupyter/tasks/install.yml | 17 +++++++++++++++-- roles/jupyter/templates/jupyter.service | 2 +- roles/jupyter/templates/jupyterhub_config.py | 13 ++++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 0c2526856..353f78cae 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,4 +1,9 @@ -- name: Make the directories to hold notebooks +- name: We need a non-privileged user to write all the notebooks + ansible.builtin.user: + name: web-user + home: /opt/iiab/notebooks + +- name: Make the directories to hold jupyter config file: state: directory path: '{{ item }}' @@ -7,6 +12,12 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' +- name: Make a directory to hold notebooks + file: + state: directory + path: /opt/iiab/notebooks + owner: web-user + - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -35,6 +46,8 @@ - ipywidgets - jupyterhub - jupyterlab + - jupyterhub_firstuseauthenticator + - jupyterhub-systemdspawner virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -45,7 +58,7 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/env/jupyterhub/' + dest: '{{ jupyter_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 363390a9f..f9e5aa798 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -3,7 +3,7 @@ Description=JupyterHub After=syslog.target network.target [Service] -User=hubuser +User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 00c70a126..71d81dbb9 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -114,7 +114,7 @@ # - dummy: jupyterhub.auth.DummyAuthenticator # - pam: jupyterhub.auth.PAMAuthenticator # Default: 'jupyterhub.auth.PAMAuthenticator' -# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' +c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' ## The base URL of the entire application. # @@ -194,7 +194,7 @@ # # Should be exactly 256 bits (32 bytes). # Default: b'' -# c.JupyterHub.cookie_secret = b'' +c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## File in which to store the cookie secret. # Default: 'jupyterhub_cookie_secret' @@ -589,7 +589,7 @@ # - localprocess: jupyterhub.spawner.LocalProcessSpawner # - simple: jupyterhub.spawner.SimpleLocalProcessSpawner # Default: 'jupyterhub.spawner.LocalProcessSpawner' -# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' +c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## Path to SSL certificate file for the public facing interface of the proxy # @@ -1229,3 +1229,10 @@ ## Maximum number of entries per page for paginated results. # Default: 250 # c.Pagination.max_per_page = 250 + +#------------------------------------------------------------------------------ +# Systemdspawner config +#------------------------------------------------------------------------------ +c.SystemdSpawner.dynamic_users = True +c.SystemdSpawner.user_workingdir = '/opt/iiab/notebooks/{USERNAME}' + From ca287e2acfee73b94000b77f857824c3237ca552 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:19:17 +0000 Subject: [PATCH 06/62] change systemd to more specifially use the venv --- roles/jupyter/templates/jupyter.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index f9e5aa798..8ce535369 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -5,7 +5,7 @@ After=syslog.target network.target [Service] User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target From 01b4f2edde259e58de2c067ef25ce77371009836 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:33:47 +0000 Subject: [PATCH 07/62] add iiab-admin to the authentication list --- roles/jupyter/templates/jupyterhub_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 71d81dbb9..999715a8f 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() -# c.Authenticator.admin_users = set() + c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From 6d8ef095824877e1815d4be1a922d877652e7fb8 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 05:15:15 +0000 Subject: [PATCH 08/62] remove creation of notebook, spawner puts in /var/lib/private --- roles/jupyter/tasks/enable-or-disable.yml | 16 ++++++++++++++++ roles/jupyter/tasks/install.yml | 12 +----------- roles/jupyter/templates/jupyterhub_config.py | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml index ad8bb17ad..becab8e9a 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -23,3 +23,19 @@ when: not jupyter_enabled +- name: Put the nginx config file in place + template: + src: jupyter-nginx.conf + dest: "{{ nginx_conf_dir }}/" + when: jupyter_enabled + +- name: Disable jupyterhub + file: + path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + state: absent + when: not jupyter_enabled + +- name: Restart 'nginx' systemd service + systemd: + name: nginx + state: restarted diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 353f78cae..6901db83d 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,8 +1,3 @@ -- name: We need a non-privileged user to write all the notebooks - ansible.builtin.user: - name: web-user - home: /opt/iiab/notebooks - - name: Make the directories to hold jupyter config file: state: directory @@ -12,12 +7,6 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' -- name: Make a directory to hold notebooks - file: - state: directory - path: /opt/iiab/notebooks - owner: web-user - - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -59,6 +48,7 @@ template: src: jupyterhub_config.py dest: '{{ jupyter_venv }}/etc/jupyterhub/' + - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 999715a8f..cd0999ca1 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() - c.Authenticator.admin_users = set('iiab-admin') +c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From e6fe48cb298b3c0ffb4fdbd066a663bae868ee26 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 17:35:48 +0000 Subject: [PATCH 09/62] getting nginx proxy to work /jupyterhub --- roles/jupyter/templates/jupyter-nginx.conf | 20 ++++++++++++++++++++ roles/jupyter/templates/jupyterhub_config.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 roles/jupyter/templates/jupyter-nginx.conf diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyter/templates/jupyter-nginx.conf new file mode 100644 index 000000000..a9d450c10 --- /dev/null +++ b/roles/jupyter/templates/jupyter-nginx.conf @@ -0,0 +1,20 @@ +location /jupyterhub { + proxy_pass http://127.0.0.1:8000; + proxy_set_header X-Real-IP $remote_addr; + #proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; + + + # websocket headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + #proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Scheme $scheme; + + proxy_buffering off; + } + # Managing requests to verify letsencrypt host + location ~ /.well-known { + allow all; + } diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index cd0999ca1..ade964254 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/' +# c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From 8bae949efb4b35b302b366f5ad0da77224508399 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 05:07:56 +0000 Subject: [PATCH 10/62] add in README.md --- roles/jupyter/docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 roles/jupyter/docs/README.md diff --git a/roles/jupyter/docs/README.md b/roles/jupyter/docs/README.md new file mode 100644 index 000000000..2878ebaa6 --- /dev/null +++ b/roles/jupyter/docs/README.md @@ -0,0 +1,6 @@ +### Jupyter Notebooks on Rpi Server +* Jupyter Notebooks are widely used in the scientific community. +* This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. +* Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. +* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. +* Students will not have any priviletes outside of their own folder. From 748260f314fecee0d34559cabce56f5792f7f525 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:24:05 +0000 Subject: [PATCH 11/62] remove the jupyter<->jupyterhub conflict. Make all jupyterhub --- roles/{jupyter => jupyterhub}/defaults/main.yml | 2 +- roles/{jupyter => jupyterhub}/docs/README.md | 0 .../tasks/enable-or-disable.yml | 16 ++++++++-------- roles/{jupyter => jupyterhub}/tasks/install.yml | 12 ++++++------ roles/{jupyter => jupyterhub}/tasks/main.yml | 8 ++++---- .../templates/jupyterhub-nginx.conf} | 0 .../templates/jupyterhub.service} | 4 ++-- .../templates/jupyterhub_config.py | 0 vars/default_vars.yml | 4 ++-- 9 files changed, 23 insertions(+), 23 deletions(-) rename roles/{jupyter => jupyterhub}/defaults/main.yml (77%) rename roles/{jupyter => jupyterhub}/docs/README.md (100%) rename roles/{jupyter => jupyterhub}/tasks/enable-or-disable.yml (69%) rename roles/{jupyter => jupyterhub}/tasks/install.yml (81%) rename roles/{jupyter => jupyterhub}/tasks/main.yml (66%) rename roles/{jupyter/templates/jupyter-nginx.conf => jupyterhub/templates/jupyterhub-nginx.conf} (100%) rename roles/{jupyter/templates/jupyter.service => jupyterhub/templates/jupyterhub.service} (54%) rename roles/{jupyter => jupyterhub}/templates/jupyterhub_config.py (100%) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyterhub/defaults/main.yml similarity index 77% rename from roles/jupyter/defaults/main.yml rename to roles/jupyterhub/defaults/main.yml index b22730df0..d4231ae72 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,4 @@ notebook_dir: /opt/iiab/notebook -jupyter_venv: /opt/iiab/jupyter +jupyterhub_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub jupyterhub_port: 8000 diff --git a/roles/jupyter/docs/README.md b/roles/jupyterhub/docs/README.md similarity index 100% rename from roles/jupyter/docs/README.md rename to roles/jupyterhub/docs/README.md diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyterhub/tasks/enable-or-disable.yml similarity index 69% rename from roles/jupyter/tasks/enable-or-disable.yml rename to roles/jupyterhub/tasks/enable-or-disable.yml index becab8e9a..aacd9a35d 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyterhub/tasks/enable-or-disable.yml @@ -10,8 +10,8 @@ enabled: yes state: restarted with_items: - - jupyter - when: jupyter_enabled + - jupyterhub.service + when: jupyterhub_enabled - name: Disable jupyterhub systemd: @@ -19,21 +19,21 @@ enabled: no state: stopped with_items: - - jupyter - when: not jupyter_enabled + - jupyterhub + when: not jupyterhub_enabled - name: Put the nginx config file in place template: - src: jupyter-nginx.conf + src: jupyterhub-nginx.conf dest: "{{ nginx_conf_dir }}/" - when: jupyter_enabled + when: jupyterhub_enabled - name: Disable jupyterhub file: - path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + path: "{{ nginx_conf_dir }}/jupyterhub-nginx.conf" state: absent - when: not jupyter_enabled + when: not jupyterhub_enabled - name: Restart 'nginx' systemd service systemd: diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyterhub/tasks/install.yml similarity index 81% rename from roles/jupyter/tasks/install.yml rename to roles/jupyterhub/tasks/install.yml index 6901db83d..baae04456 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyterhub/tasks/install.yml @@ -3,9 +3,9 @@ state: directory path: '{{ item }}' with_items: - - '{{ jupyter_venv }}/etc/jupyter' - - '{{ jupyter_venv }}/etc/jupyterhub' - - '{{ jupyter_venv }}/etc/systemd' + - '{{ jupyterhub_venv }}/etc/jupyter' + - '{{ jupyterhub_venv }}/etc/jupyterhub' + - '{{ jupyterhub_venv }}/etc/systemd' - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: @@ -37,7 +37,7 @@ - jupyterlab - jupyterhub_firstuseauthenticator - jupyterhub-systemdspawner - virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv virtualenv_python: python3 @@ -47,9 +47,9 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/etc/jupyterhub/' + dest: '{{ jupyterhub_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: - src: jupyter.service + src: jupyterhub.service dest: /etc/systemd/system/ diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyterhub/tasks/main.yml similarity index 66% rename from roles/jupyter/tasks/main.yml rename to roles/jupyterhub/tasks/main.yml index 137a01b84..9090610a0 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -1,6 +1,6 @@ -- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml +- name: Install Jupyter if jupyterhub_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml include_tasks: install.yml - when: jupyter_installed is undefined + when: jupyterhub_installed is undefined - include_tasks: enable-or-disable.yml @@ -18,6 +18,6 @@ - option: description value: '"Raspberry Pi Jupyter python programming environment"' - option: install - value: "{{ jupyter_install }}" + value: "{{ jupyterhub_install }}" - option: enabled - value: "{{ jupyter_enabled }}" + value: "{{ jupyterhub_enabled }}" diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf similarity index 100% rename from roles/jupyter/templates/jupyter-nginx.conf rename to roles/jupyterhub/templates/jupyterhub-nginx.conf diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyterhub/templates/jupyterhub.service similarity index 54% rename from roles/jupyter/templates/jupyter.service rename to roles/jupyterhub/templates/jupyterhub.service index 8ce535369..3137d0404 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyterhub/templates/jupyterhub.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=root -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyterhub_venv }}/bin" +ExecStart={{ jupyterhub_venv }}/bin/python3 -m jupyterhub -f {{ jupyterhub_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py similarity index 100% rename from roles/jupyter/templates/jupyterhub_config.py rename to roles/jupyterhub/templates/jupyterhub_config.py diff --git a/vars/default_vars.yml b/vars/default_vars.yml index c6be2eeea..6ca9d468a 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -559,8 +559,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False -jupyter_install: False -jupyter_enabled: False +jupyterhub_install: False +jupyterhub_enabled: False # 9-LOCAL-ADDONS From bf8c6934a72d90cd7aee0e095afbc26d47844a0b Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:35:27 +0000 Subject: [PATCH 12/62] remaining jupyter->jupyterhub items --- roles/jupyterhub/defaults/main.yml | 4 +--- roles/jupyterhub/templates/jupyterhub_config.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/roles/jupyterhub/defaults/main.yml b/roles/jupyterhub/defaults/main.yml index d4231ae72..a859f9946 100644 --- a/roles/jupyterhub/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,2 @@ -notebook_dir: /opt/iiab/notebook -jupyterhub_venv: /opt/iiab/jupyter -jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_venv: /opt/iiab/jupyterhub jupyterhub_port: 8000 diff --git a/roles/jupyterhub/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py index ade964254..2eba8b290 100644 --- a/roles/jupyterhub/templates/jupyterhub_config.py +++ b/roles/jupyterhub/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/jupyterhub' +c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From 17a6d030f70a1f8e837925a3692c2d2c68764926 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Mon, 8 Mar 2021 01:57:10 +0000 Subject: [PATCH 13/62] venv runs without jupyterlab-vim --- .gitignore | 1 + roles/jupyter/defaults/main.yml | 2 ++ roles/jupyter/tasks/install.yml | 17 +++++++++++++++++ roles/jupyter/tasks/main.yml | 23 +++++++++++++++++++++++ vars/default_vars.yml | 2 ++ 5 files changed, 45 insertions(+) create mode 100644 roles/jupyter/defaults/main.yml create mode 100644 roles/jupyter/tasks/install.yml create mode 100644 roles/jupyter/tasks/main.yml diff --git a/.gitignore b/.gitignore index fc4b12be2..38f8427ed 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ deprecated *.patches *.log *.retry +*~ diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml new file mode 100644 index 000000000..017b0de30 --- /dev/null +++ b/roles/jupyter/defaults/main.yml @@ -0,0 +1,2 @@ +notebook_dir: /opt/iiab/notebook +jupyter_venv: /opt/iiab/jupyter diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml new file mode 100644 index 000000000..3330ba743 --- /dev/null +++ b/roles/jupyter/tasks/install.yml @@ -0,0 +1,17 @@ +- name: Make the directories to hold notebooks + file: + state: directory + path: '{{ notebook_dir }}' + +- name: Use pip to install into a virtual environment + pip: + name: + - jupyterlab + #- jupyter_vim + virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv_site_packages: no + virtualenv_command: /usr/bin/virtualenv + virtualenv_python: python3 + extra_args: "--no-cache-dir" + when: internet_available + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml new file mode 100644 index 000000000..9f1804b38 --- /dev/null +++ b/roles/jupyter/tasks/main.yml @@ -0,0 +1,23 @@ +- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: jupyter_installed is undefined + + +#- include_tasks: enable-or-disable.yml + + +- name: Add 'jupyter' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: jupyter + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Jupyter + - option: description + value: '"Raspberry Pi Jupyter python programming environment"' + - option: install + value: "{{ jupyter_install }}" + - option: enabled + value: "{{ jupyter_enabled }}" diff --git a/vars/default_vars.yml b/vars/default_vars.yml index 9690ba595..d1fb036e1 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -564,6 +564,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False +jupyter_install: False +jupyter_enabled: False # 9-LOCAL-ADDONS From e91319bb27b3fcb68f188b6662d8f5f438b20743 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 04:57:33 +0000 Subject: [PATCH 14/62] Found instructions for the Littlest Jupyterhub --- roles/jupyter/tasks/enable-or-disable.yml | 25 +++++++++++++++++++++++ roles/jupyter/tasks/install.yml | 19 ++++++++++++++--- roles/jupyter/tasks/main.yml | 2 +- roles/jupyter/templates/jupyter.service | 11 ++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 roles/jupyter/tasks/enable-or-disable.yml create mode 100644 roles/jupyter/templates/jupyter.service diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml new file mode 100644 index 000000000..ad8bb17ad --- /dev/null +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -0,0 +1,25 @@ +- name: systemd daemon-reload + systemd: + daemon_reload: yes + + +# enable or disable +- name: Enable & Restart jupyterhub + systemd: + name: "{{ item }}" + enabled: yes + state: restarted + with_items: + - jupyter + when: jupyter_enabled + +- name: Disable jupyterhub + systemd: + name: "{{ item }}" + enabled: no + state: stopped + with_items: + - jupyter + when: not jupyter_enabled + + diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 3330ba743..4e2981584 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,13 +1,16 @@ - name: Make the directories to hold notebooks file: state: directory - path: '{{ notebook_dir }}' + path: '{{ item }}' + with_items: + - '{{ notebook_dir }}/etc/jupyter' + - '{{ notebook_dir }}/etc/jupyterhub' + - '{{ notebook_dir }}/etc/systemd' - name: Use pip to install into a virtual environment pip: name: - - jupyterlab - #- jupyter_vim + - pip virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -15,3 +18,13 @@ extra_args: "--no-cache-dir" when: internet_available +- name: Fetch the Littlest JupyterHub code + ansible.builtin.git: + repo: '{{ jupyterhub_url }} + dest: '{{ jupyter_venv }}' + +- name: Install a bootstrap.py that permits installation on other than Ubunt + template: + src: bootstrap.py + dest: '{{ jupyter_venv }}' + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml index 9f1804b38..137a01b84 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyter/tasks/main.yml @@ -3,7 +3,7 @@ when: jupyter_installed is undefined -#- include_tasks: enable-or-disable.yml +- include_tasks: enable-or-disable.yml - name: Add 'jupyter' variable values to {{ iiab_ini_file }} diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service new file mode 100644 index 000000000..81cee0dd2 --- /dev/null +++ b/roles/jupyter/templates/jupyter.service @@ -0,0 +1,11 @@ +[Unit] +Description=JupyterHub +After=syslog.target network.target + +[Service] +User=hubuser +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" +ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py + +[Install] +WantedBy=multi-user.target From 95fed43cc93f865cdfbad822f37d4283e018d7a9 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 19:56:46 +0000 Subject: [PATCH 15/62] changes to venv --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index 017b0de30..c879b76ac 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,2 +1,3 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter +jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 4e2981584..b311464b6 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -11,6 +11,8 @@ pip: name: - pip + - wheel + - ipywidgets virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv From 09904517e5af5d77217f0701a29a01d23d844ddd Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 22:57:39 +0000 Subject: [PATCH 16/62] displayed the ted notebook on raspi-os --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 44 +- roles/jupyter/templates/jupyter.service | 4 +- roles/jupyter/templates/jupyterhub_config.py | 1231 +++++++++++++++++ .../templates/gateway/iiab-gen-iptables | 4 +- 5 files changed, 1269 insertions(+), 15 deletions(-) create mode 100644 roles/jupyter/templates/jupyterhub_config.py diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index c879b76ac..b22730df0 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,3 +1,4 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_port: 8000 diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index b311464b6..0c2526856 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -3,9 +3,29 @@ state: directory path: '{{ item }}' with_items: - - '{{ notebook_dir }}/etc/jupyter' - - '{{ notebook_dir }}/etc/jupyterhub' - - '{{ notebook_dir }}/etc/systemd' + - '{{ jupyter_venv }}/etc/jupyter' + - '{{ jupyter_venv }}/etc/jupyterhub' + - '{{ jupyter_venv }}/etc/systemd' + +- name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" + set_fact: + nodejs_install: True + nodejs_enabled: True + +- name: NODEJS - run 'nodejs' role (attempt to install & enable Node.js) + include_role: + name: nodejs + +- name: FAIL (STOP THE INSTALL) IF 'nodejs_installed is undefined' + fail: + msg: "Jupyter install cannot proceed, as Node.js is not installed." + when: nodejs_installed is undefined + +- name: use npm to install configurable http proxy + npm: + name: configurable-http-proxy + global: yes + state: latest - name: Use pip to install into a virtual environment pip: @@ -13,6 +33,8 @@ - pip - wheel - ipywidgets + - jupyterhub + - jupyterlab virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -20,13 +42,11 @@ extra_args: "--no-cache-dir" when: internet_available -- name: Fetch the Littlest JupyterHub code - ansible.builtin.git: - repo: '{{ jupyterhub_url }} - dest: '{{ jupyter_venv }}' - -- name: Install a bootstrap.py that permits installation on other than Ubunt +- name: Install the config file for jupyterhub template: - src: bootstrap.py - dest: '{{ jupyter_venv }}' - + src: jupyterhub_config.py + dest: '{{ jupyter_venv }}/env/jupyterhub/' +- name: Use systemd to start jupyterhub + template: + src: jupyter.service + dest: /etc/systemd/system/ diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 81cee0dd2..363390a9f 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=hubuser -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" -ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" +ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py new file mode 100644 index 000000000..00c70a126 --- /dev/null +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -0,0 +1,1231 @@ +# Configuration file for jupyterhub. + +#------------------------------------------------------------------------------ +# Application(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## This is an application. + +## The date format used by logging formatters for %(asctime)s +# Default: '%Y-%m-%d %H:%M:%S' +# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# Default: '[%(name)s]%(highlevel)s %(message)s' +# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] +# Default: 30 +# c.Application.log_level = 30 + +## Instead of starting the Application, dump configuration to stdout +# Default: False +# c.Application.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# Default: False +# c.Application.show_config_json = False + +#------------------------------------------------------------------------------ +# JupyterHub(Application) configuration +#------------------------------------------------------------------------------ +## An Application for starting a Multi-User Jupyter Notebook server. + +## Maximum number of concurrent servers that can be active at a time. +# +# Setting this can limit the total resources your users can consume. +# +# An active server is any server that's not fully stopped. It is considered +# active from the time it has been requested until the time that it has +# completely stopped. +# +# If this many user servers are active, users will not be able to launch new +# servers until a server is shutdown. Spawn requests will be rejected with a 429 +# error asking them to try again. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.active_server_limit = 0 + +## Duration (in seconds) to determine the number of active users. +# Default: 1800 +# c.JupyterHub.active_user_window = 1800 + +## Resolution (in seconds) for updating activity +# +# If activity is registered that is less than activity_resolution seconds more +# recent than the current value, the new value will be ignored. +# +# This avoids too many writes to the Hub database. +# Default: 30 +# c.JupyterHub.activity_resolution = 30 + +## Grant admin users permission to access single-user servers. +# +# Users should be properly informed if this is enabled. +# Default: False +# c.JupyterHub.admin_access = False + +## DEPRECATED since version 0.7.2, use Authenticator.admin_users instead. +# Default: set() +# c.JupyterHub.admin_users = set() + +## Allow named single-user servers per user +# Default: False +# c.JupyterHub.allow_named_servers = False + +## Answer yes to any questions (e.g. confirm overwrite) +# Default: False +# c.JupyterHub.answer_yes = False + +## PENDING DEPRECATION: consider using services +# +# Dict of token:username to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services, which authenticate as JupyterHub users. +# +# Consider using services for general services that talk to the JupyterHub API. +# Default: {} +# c.JupyterHub.api_tokens = {} + +## Authentication for prometheus metrics +# Default: True +# c.JupyterHub.authenticate_prometheus = True + +## Class for authenticating users. +# +# This should be a subclass of :class:`jupyterhub.auth.Authenticator` +# +# with an :meth:`authenticate` method that: +# +# - is a coroutine (asyncio or tornado) +# - returns username on success, None on failure +# - takes two arguments: (handler, data), +# where `handler` is the calling web.RequestHandler, +# and `data` is the POST form data from the login page. +# +# .. versionchanged:: 1.0 +# authenticators may be registered via entry points, +# e.g. `c.JupyterHub.authenticator_class = 'pam'` +# +# Currently installed: +# - default: jupyterhub.auth.PAMAuthenticator +# - dummy: jupyterhub.auth.DummyAuthenticator +# - pam: jupyterhub.auth.PAMAuthenticator +# Default: 'jupyterhub.auth.PAMAuthenticator' +# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' + +## The base URL of the entire application. +# +# Add this to the beginning of all JupyterHub URLs. Use base_url to run +# JupyterHub within an existing website. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '/' +# c.JupyterHub.base_url = '/' + +## The public facing URL of the whole JupyterHub application. +# +# This is the address on which the proxy will bind. Sets protocol, ip, base_url +# Default: 'http://:8000' +# c.JupyterHub.bind_url = 'http://:8000' + +## Whether to shutdown the proxy when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the proxy +# running. +# +# Only valid if the proxy was starting by the Hub process. +# +# If both this and cleanup_servers are False, sending SIGINT to the Hub will +# only shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_proxy = True + +## Whether to shutdown single-user servers when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the single- +# user servers running. +# +# If both this and cleanup_proxy are False, sending SIGINT to the Hub will only +# shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_servers = True + +## Maximum number of concurrent users that can be spawning at a time. +# +# Spawning lots of servers at the same time can cause performance problems for +# the Hub or the underlying spawning system. Set this limit to prevent bursts of +# logins from attempting to spawn too many servers at the same time. +# +# This does not limit the number of total running servers. See +# active_server_limit for that. +# +# If more than this many users attempt to spawn at a time, their requests will +# be rejected with a 429 error asking them to try again. Users will have to wait +# for some of the spawning services to finish starting before they can start +# their own. +# +# If set to 0, no limit is enforced. +# Default: 100 +# c.JupyterHub.concurrent_spawn_limit = 100 + +## The config file to load +# Default: 'jupyterhub_config.py' +# c.JupyterHub.config_file = 'jupyterhub_config.py' + +## DEPRECATED: does nothing +# Default: False +# c.JupyterHub.confirm_no_ssl = False + +## Number of days for a login cookie to be valid. Default is two weeks. +# Default: 14 +# c.JupyterHub.cookie_max_age_days = 14 + +## The cookie secret to use to encrypt cookies. +# +# Loaded from the JPY_COOKIE_SECRET env variable by default. +# +# Should be exactly 256 bits (32 bytes). +# Default: b'' +# c.JupyterHub.cookie_secret = b'' + +## File in which to store the cookie secret. +# Default: 'jupyterhub_cookie_secret' +# c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' + +## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) +# Default: '/opt/iiab/jupyter/share/jupyterhub' +# c.JupyterHub.data_files_path = '/opt/iiab/jupyter/share/jupyterhub' + +## Include any kwargs to pass to the database connection. See +# sqlalchemy.create_engine for details. +# Default: {} +# c.JupyterHub.db_kwargs = {} + +## url for the database. e.g. `sqlite:///jupyterhub.sqlite` +# Default: 'sqlite:///jupyterhub.sqlite' +# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' + +## log all database transactions. This has A LOT of output +# Default: False +# c.JupyterHub.debug_db = False + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.debug +# Default: False +# c.JupyterHub.debug_proxy = False + +## If named servers are enabled, default name of server to spawn or open, e.g. by +# user-redirect. +# Default: '' +# c.JupyterHub.default_server_name = '' + +## The default URL for users when they arrive (e.g. when user directs to "/") +# +# By default, redirects users to their own server. +# +# Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler +# object: +# +# :: +# +# def default_url_fn(handler): +# user = handler.current_user +# if user and user.admin: +# return '/hub/admin' +# return '/hub/home' +# +# c.JupyterHub.default_url = default_url_fn +# Default: traitlets.Undefined +# c.JupyterHub.default_url = traitlets.Undefined + +## Dict authority:dict(files). Specify the key, cert, and/or ca file for an +# authority. This is useful for externally managed proxies that wish to use +# internal_ssl. +# +# The files dict has this format (you must specify at least a cert):: +# +# { +# 'key': '/path/to/key.key', +# 'cert': '/path/to/cert.crt', +# 'ca': '/path/to/ca.crt' +# } +# +# The authorities you can override: 'hub-ca', 'notebooks-ca', 'proxy-api-ca', +# 'proxy-client-ca', and 'services-ca'. +# +# Use with internal_ssl +# Default: {} +# c.JupyterHub.external_ssl_authorities = {} + +## Register extra tornado Handlers for jupyterhub. +# +# Should be of the form ``("", Handler)`` +# +# The Hub prefix will be added, so `/my-page` will be served at `/hub/my-page`. +# Default: [] +# c.JupyterHub.extra_handlers = [] + +## DEPRECATED: use output redirection instead, e.g. +# +# jupyterhub &>> /var/log/jupyterhub.log +# Default: '' +# c.JupyterHub.extra_log_file = '' + +## Extra log handlers to set on JupyterHub logger +# Default: [] +# c.JupyterHub.extra_log_handlers = [] + +## Generate certs used for internal ssl +# Default: False +# c.JupyterHub.generate_certs = False + +## Generate default config file +# Default: False +# c.JupyterHub.generate_config = False + +## The URL on which the Hub will listen. This is a private URL for internal +# communication. Typically set in combination with hub_connect_url. If a unix +# socket, hub_connect_url **must** also be set. +# +# For example: +# +# "http://127.0.0.1:8081" +# "unix+http://%2Fsrv%2Fjupyterhub%2Fjupyterhub.sock" +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_bind_url = '' + +## The ip or hostname for proxies and spawners to use for connecting to the Hub. +# +# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different +# from the connect address. +# +# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, otherwise +# use `hub_ip`. +# +# Note: Some spawners or proxy implementations might not support hostnames. +# Check your spawner or proxy documentation to see if they have extra +# requirements. +# +# .. versionadded:: 0.8 +# Default: '' +# c.JupyterHub.hub_connect_ip = '' + +## DEPRECATED +# +# Use hub_connect_url +# +# .. versionadded:: 0.8 +# +# .. deprecated:: 0.9 +# Use hub_connect_url +# Default: 0 +# c.JupyterHub.hub_connect_port = 0 + +## The URL for connecting to the Hub. Spawners, services, and the proxy will use +# this URL to talk to the Hub. +# +# Only needs to be specified if the default hub URL is not connectable (e.g. +# using a unix+http:// bind url). +# +# .. seealso:: +# JupyterHub.hub_connect_ip +# JupyterHub.hub_bind_url +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_connect_url = '' + +## The ip address for the Hub process to *bind* to. +# +# By default, the hub listens on localhost only. This address must be accessible +# from the proxy and user servers. You may need to set this to a public ip or '' +# for all interfaces if the proxy or user servers are in containers or on a +# different host. +# +# See `hub_connect_ip` for cases where the bind and connect address should +# differ, or `hub_bind_url` for setting the full bind URL. +# Default: '127.0.0.1' +# c.JupyterHub.hub_ip = '127.0.0.1' + +## The internal port for the Hub process. +# +# This is the internal port of the hub itself. It should never be accessed +# directly. See JupyterHub.port for the public port to use when accessing +# jupyterhub. It is rare that this port should be set except in cases of port +# conflict. +# +# See also `hub_ip` for the ip and `hub_bind_url` for setting the full bind URL. +# Default: 8081 +# c.JupyterHub.hub_port = 8081 + +## Trigger implicit spawns after this many seconds. +# +# When a user visits a URL for a server that's not running, they are shown a +# page indicating that the requested server is not running with a button to +# spawn the server. +# +# Setting this to a positive value will redirect the user after this many +# seconds, effectively clicking this button automatically for the users, +# automatically beginning the spawn process. +# +# Warning: this can result in errors and surprising behavior when sharing access +# URLs to actual servers, since the wrong server is likely to be started. +# Default: 0 +# c.JupyterHub.implicit_spawn_seconds = 0 + +## Timeout (in seconds) to wait for spawners to initialize +# +# Checking if spawners are healthy can take a long time if many spawners are +# active at hub start time. +# +# If it takes longer than this timeout to check, init_spawner will be left to +# complete in the background and the http server is allowed to start. +# +# A timeout of -1 means wait forever, which can mean a slow startup of the Hub +# but ensures that the Hub is fully consistent by the time it starts responding +# to requests. This matches the behavior of jupyterhub 1.0. +# +# .. versionadded: 1.1.0 +# Default: 10 +# c.JupyterHub.init_spawners_timeout = 10 + +## The location to store certificates automatically created by JupyterHub. +# +# Use with internal_ssl +# Default: 'internal-ssl' +# c.JupyterHub.internal_certs_location = 'internal-ssl' + +## Enable SSL for all internal communication +# +# This enables end-to-end encryption between all JupyterHub components. +# JupyterHub will automatically create the necessary certificate authority and +# sign notebook certificates as they're created. +# Default: False +# c.JupyterHub.internal_ssl = False + +## The public facing ip of the whole JupyterHub application (specifically +# referred to as the proxy). +# +# This is the address on which the proxy will listen. The default is to listen +# on all interfaces. This is the only address through which JupyterHub should be +# accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '' +# c.JupyterHub.ip = '' + +## Supply extra arguments that will be passed to Jinja environment. +# Default: {} +# c.JupyterHub.jinja_environment_options = {} + +## Interval (in seconds) at which to update last-activity timestamps. +# Default: 300 +# c.JupyterHub.last_activity_interval = 300 + +## Dict of 'group': ['usernames'] to load at startup. +# +# This strictly *adds* groups and users to groups. +# +# Loading one set of groups, then starting JupyterHub again with a different set +# will not remove users or groups from previous launches. That must be done +# through the API. +# Default: {} +# c.JupyterHub.load_groups = {} + +## The date format used by logging formatters for %(asctime)s +# See also: Application.log_datefmt +# c.JupyterHub.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# See also: Application.log_format +# c.JupyterHub.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# See also: Application.log_level +# c.JupyterHub.log_level = 30 + +## Specify path to a logo image to override the Jupyter logo in the banner. +# Default: '' +# c.JupyterHub.logo_file = '' + +## Maximum number of concurrent named servers that can be created by a user at a +# time. +# +# Setting this can limit the total resources a user can consume. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.named_server_limit_per_user = 0 + +## File to write PID Useful for daemonizing JupyterHub. +# Default: '' +# c.JupyterHub.pid_file = '' + +## The public facing port of the proxy. +# +# This is the port on which the proxy will listen. This is the only port through +# which JupyterHub should be accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: 8000 +# c.JupyterHub.port = 8000 + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: '' +# c.JupyterHub.proxy_api_ip = '' + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: 0 +# c.JupyterHub.proxy_api_port = 0 + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.auth_token +# Default: '' +# c.JupyterHub.proxy_auth_token = '' + +## Interval (in seconds) at which to check if the proxy is running. +# Default: 30 +# c.JupyterHub.proxy_check_interval = 30 + +## The class to use for configuring the JupyterHub proxy. +# +# Should be a subclass of :class:`jupyterhub.proxy.Proxy`. +# +# .. versionchanged:: 1.0 +# proxies may be registered via entry points, +# e.g. `c.JupyterHub.proxy_class = 'traefik'` +# +# Currently installed: +# - configurable-http-proxy: jupyterhub.proxy.ConfigurableHTTPProxy +# - default: jupyterhub.proxy.ConfigurableHTTPProxy +# Default: 'jupyterhub.proxy.ConfigurableHTTPProxy' +# c.JupyterHub.proxy_class = 'jupyterhub.proxy.ConfigurableHTTPProxy' + +## DEPRECATED since version 0.8. Use ConfigurableHTTPProxy.command +# Default: [] +# c.JupyterHub.proxy_cmd = [] + +## Recreate all certificates used within JupyterHub on restart. +# +# Note: enabling this feature requires restarting all notebook servers. +# +# Use with internal_ssl +# Default: False +# c.JupyterHub.recreate_internal_certs = False + +## Redirect user to server (if running), instead of control panel. +# Default: True +# c.JupyterHub.redirect_to_server = True + +## Purge and reset the database. +# Default: False +# c.JupyterHub.reset_db = False + +## Interval (in seconds) at which to check connectivity of services with web +# endpoints. +# Default: 60 +# c.JupyterHub.service_check_interval = 60 + +## Dict of token:servicename to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services. +# Default: {} +# c.JupyterHub.service_tokens = {} + +## List of service specification dictionaries. +# +# A service +# +# For instance:: +# +# services = [ +# { +# 'name': 'cull_idle', +# 'command': ['/path/to/cull_idle_servers.py'], +# }, +# { +# 'name': 'formgrader', +# 'url': 'http://127.0.0.1:1234', +# 'api_token': 'super-secret', +# 'environment': +# } +# ] +# Default: [] +# c.JupyterHub.services = [] + +## Instead of starting the Application, dump configuration to stdout +# See also: Application.show_config +# c.JupyterHub.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# See also: Application.show_config_json +# c.JupyterHub.show_config_json = False + +## Shuts down all user servers on logout +# Default: False +# c.JupyterHub.shutdown_on_logout = False + +## The class to use for spawning single-user servers. +# +# Should be a subclass of :class:`jupyterhub.spawner.Spawner`. +# +# .. versionchanged:: 1.0 +# spawners may be registered via entry points, +# e.g. `c.JupyterHub.spawner_class = 'localprocess'` +# +# Currently installed: +# - default: jupyterhub.spawner.LocalProcessSpawner +# - localprocess: jupyterhub.spawner.LocalProcessSpawner +# - simple: jupyterhub.spawner.SimpleLocalProcessSpawner +# Default: 'jupyterhub.spawner.LocalProcessSpawner' +# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' + +## Path to SSL certificate file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_key +# Default: '' +# c.JupyterHub.ssl_cert = '' + +## Path to SSL key file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_cert +# Default: '' +# c.JupyterHub.ssl_key = '' + +## Host to send statsd metrics to. An empty string (the default) disables sending +# metrics. +# Default: '' +# c.JupyterHub.statsd_host = '' + +## Port on which to send statsd metrics about the hub +# Default: 8125 +# c.JupyterHub.statsd_port = 8125 + +## Prefix to use for all metrics sent by jupyterhub to statsd +# Default: 'jupyterhub' +# c.JupyterHub.statsd_prefix = 'jupyterhub' + +## Run single-user servers on subdomains of this host. +# +# This should be the full `https://hub.domain.tld[:port]`. +# +# Provides additional cross-site protections for javascript served by single- +# user servers. +# +# Requires `.hub.domain.tld` to resolve to the same host as +# `hub.domain.tld`. +# +# In general, this is most easily achieved with wildcard DNS. +# +# When using SSL (i.e. always) this also requires a wildcard SSL certificate. +# Default: '' +# c.JupyterHub.subdomain_host = '' + +## Paths to search for jinja templates, before using the default templates. +# Default: [] +# c.JupyterHub.template_paths = [] + +## Extra variables to be passed into jinja templates +# Default: {} +# c.JupyterHub.template_vars = {} + +## Extra settings overrides to pass to the tornado application. +# Default: {} +# c.JupyterHub.tornado_settings = {} + +## Trust user-provided tokens (via JupyterHub.service_tokens) to have good +# entropy. +# +# If you are not inserting additional tokens via configuration file, this flag +# has no effect. +# +# In JupyterHub 0.8, internally generated tokens do not pass through additional +# hashing because the hashing is costly and does not increase the entropy of +# already-good UUIDs. +# +# User-provided tokens, on the other hand, are not trusted to have good entropy +# by default, and are passed through many rounds of hashing to stretch the +# entropy of the key (i.e. user-provided tokens are treated as passwords instead +# of random keys). These keys are more costly to check. +# +# If your inserted tokens are generated by a good-quality mechanism, e.g. +# `openssl rand -hex 32`, then you can set this flag to True to reduce the cost +# of checking authentication tokens. +# Default: False +# c.JupyterHub.trust_user_provided_tokens = False + +## Names to include in the subject alternative name. +# +# These names will be used for server name verification. This is useful if +# JupyterHub is being run behind a reverse proxy or services using ssl are on +# different hosts. +# +# Use with internal_ssl +# Default: [] +# c.JupyterHub.trusted_alt_names = [] + +## Downstream proxy IP addresses to trust. +# +# This sets the list of IP addresses that are trusted and skipped when +# processing the `X-Forwarded-For` header. For example, if an external proxy is +# used for TLS termination, its IP address should be added to this list to +# ensure the correct client IP addresses are recorded in the logs instead of the +# proxy server's IP address. +# Default: [] +# c.JupyterHub.trusted_downstream_ips = [] + +## Upgrade the database automatically on start. +# +# Only safe if database is regularly backed up. Only SQLite databases will be +# backed up to a local file automatically. +# Default: False +# c.JupyterHub.upgrade_db = False + +## Callable to affect behavior of /user-redirect/ +# +# Receives 4 parameters: 1. path - URL path that was provided after /user- +# redirect/ 2. request - A Tornado HTTPServerRequest representing the current +# request. 3. user - The currently authenticated user. 4. base_url - The +# base_url of the current hub, for relative redirects +# +# It should return the new URL to redirect to, or None to preserve current +# behavior. +# Default: None +# c.JupyterHub.user_redirect_hook = None + +#------------------------------------------------------------------------------ +# Spawner(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for spawning single-user notebook servers. +# +# Subclass this, and override the following methods: +# +# - load_state - get_state - start - stop - poll +# +# As JupyterHub supports multiple users, an instance of the Spawner subclass is +# created for each user. If there are 20 JupyterHub users, there will be 20 +# instances of the subclass. + +## Extra arguments to be passed to the single-user server. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables here. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: [] +# c.Spawner.args = [] + +## An optional hook function that you can implement to pass `auth_state` to the +# spawner after it has been initialized but before it starts. The `auth_state` +# dictionary may be set by the `.authenticate()` method of the authenticator. +# This hook enables you to pass some or all of that information to your spawner. +# +# Example:: +# +# def userdata_hook(spawner, auth_state): +# spawner.userdata = auth_state["userdata"] +# +# c.Spawner.auth_state_hook = userdata_hook +# Default: None +# c.Spawner.auth_state_hook = None + +## The command used for starting the single-user server. +# +# Provide either a string or a list containing the path to the startup script +# command. Extra arguments, other than this path, should be provided via `args`. +# +# This is usually set if you want to start the single-user server in a different +# python environment (with virtualenv/conda) than JupyterHub itself. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: ['jupyterhub-singleuser'] +# c.Spawner.cmd = ['jupyterhub-singleuser'] + +## Maximum number of consecutive failures to allow before shutting down +# JupyterHub. +# +# This helps JupyterHub recover from a certain class of problem preventing +# launch in contexts where the Hub is automatically restarted (e.g. systemd, +# docker, kubernetes). +# +# A limit of 0 means no limit and consecutive failures will not be tracked. +# Default: 0 +# c.Spawner.consecutive_failure_limit = 0 + +## Minimum number of cpu-cores a single-user notebook server is guaranteed to +# have available. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_guarantee = None + +## Maximum number of cpu-cores a single-user notebook server is allowed to use. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# The single-user notebook server will never be scheduled by the kernel to use +# more cpu-cores than this. There is no guarantee that it can access this many +# cpu-cores. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_limit = None + +## Enable debug-logging of the single-user server +# Default: False +# c.Spawner.debug = False + +## The URL the single-user server should start in. +# +# `{username}` will be expanded to the user's username +# +# Example uses: +# +# - You can set `notebook_dir` to `/` and `default_url` to `/tree/home/{username}` to allow people to +# navigate the whole filesystem from their notebook server, but still start in their home directory. +# - Start with `/notebooks` instead of `/tree` if `default_url` points to a notebook instead of a directory. +# - You can set this to `/lab` to have JupyterLab start by default, rather than Jupyter Notebook. +# Default: '' +# c.Spawner.default_url = '' + +## Disable per-user configuration of single-user servers. +# +# When starting the user's single-user server, any config file found in the +# user's $HOME directory will be ignored. +# +# Note: a user could circumvent this if the user modifies their Python +# environment, such as when they have their own conda environments / virtualenvs +# / containers. +# Default: False +# c.Spawner.disable_user_config = False + +## List of environment variables for the single-user server to inherit from the +# JupyterHub process. +# +# This list is used to ensure that sensitive information in the JupyterHub +# process's environment (such as `CONFIGPROXY_AUTH_TOKEN`) is not passed to the +# single-user server's process. +# Default: ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] +# c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] + +## Extra environment variables to set for the single-user server's process. +# +# Environment variables that end up in the single-user server's process come from 3 sources: +# - This `environment` configurable +# - The JupyterHub process' environment variables that are listed in `env_keep` +# - Variables to establish contact between the single-user notebook and the hub (such as JUPYTERHUB_API_TOKEN) +# +# The `environment` configurable should be set by JupyterHub administrators to +# add installation specific environment variables. It is a dict where the key is +# the name of the environment variable, and the value can be a string or a +# callable. If it is a callable, it will be called with one parameter (the +# spawner instance), and should return a string fairly quickly (no blocking +# operations please!). +# +# Note that the spawner class' interface is not guaranteed to be exactly same +# across upgrades, so if you are using the callable take care to verify it +# continues to work after upgrades! +# +# .. versionchanged:: 1.2 +# environment from this configuration has highest priority, +# allowing override of 'default' env variables, +# such as JUPYTERHUB_API_URL. +# Default: {} +# c.Spawner.environment = {} + +## Timeout (in seconds) before giving up on a spawned HTTP server +# +# Once a server has successfully been spawned, this is the amount of time we +# wait before assuming that the server is unable to accept connections. +# Default: 30 +# c.Spawner.http_timeout = 30 + +## The IP address (or hostname) the single-user server should listen on. +# +# The JupyterHub proxy implementation should be able to send packets to this +# interface. +# Default: '' +# c.Spawner.ip = '' + +## Minimum number of bytes a single-user notebook server is guaranteed to have +# available. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_guarantee = None + +## Maximum number of bytes a single-user notebook server is allowed to use. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# If the single user server tries to allocate more memory than this, it will +# fail. There is no guarantee that the single-user notebook server will be able +# to allocate this much memory - only that it can not allocate more than this. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_limit = None + +## Path to the notebook directory for the single-user server. +# +# The user sees a file listing of this directory when the notebook interface is +# started. The current interface does not easily allow browsing beyond the +# subdirectories in this directory's tree. +# +# `~` will be expanded to the home directory of the user, and {username} will be +# replaced with the name of the user. +# +# Note that this does *not* prevent users from accessing files outside of this +# path! They can do so with many other means. +# Default: '' +# c.Spawner.notebook_dir = '' + +## An HTML form for options a user can specify on launching their server. +# +# The surrounding `` element and the submit button are already provided. +# +# For example: +# +# .. code:: html +# +# Set your key: +# +#
+# Choose a letter: +# +# +# The data from this form submission will be passed on to your spawner in +# `self.user_options` +# +# Instead of a form snippet string, this could also be a callable that takes as +# one parameter the current spawner instance and returns a string. The callable +# will be called asynchronously if it returns a future, rather than a str. Note +# that the interface of the spawner class is not deemed stable across versions, +# so using this functionality might cause your JupyterHub upgrades to break. +# Default: traitlets.Undefined +# c.Spawner.options_form = traitlets.Undefined + +## Interpret HTTP form data +# +# Form data will always arrive as a dict of lists of strings. Override this +# function to understand single-values, numbers, etc. +# +# This should coerce form data into the structure expected by self.user_options, +# which must be a dict, and should be JSON-serializeable, though it can contain +# bytes in addition to standard JSON data types. +# +# This method should not have any side effects. Any handling of `user_options` +# should be done in `.start()` to ensure consistent behavior across servers +# spawned via the API and form submission page. +# +# Instances will receive this data on self.user_options, after passing through +# this function, prior to `Spawner.start`. +# +# .. versionchanged:: 1.0 +# user_options are persisted in the JupyterHub database to be reused +# on subsequent spawns if no options are given. +# user_options is serialized to JSON as part of this persistence +# (with additional support for bytes in case of uploaded file data), +# and any non-bytes non-jsonable values will be replaced with None +# if the user_options are re-used. +# Default: traitlets.Undefined +# c.Spawner.options_from_form = traitlets.Undefined + +## Interval (in seconds) on which to poll the spawner for single-user server's +# status. +# +# At every poll interval, each spawner's `.poll` method is called, which checks +# if the single-user server is still running. If it isn't running, then +# JupyterHub modifies its own state accordingly and removes appropriate routes +# from the configurable proxy. +# Default: 30 +# c.Spawner.poll_interval = 30 + +## The port for single-user servers to listen on. +# +# Defaults to `0`, which uses a randomly allocated port number each time. +# +# If set to a non-zero value, all Spawners will use the same port, which only +# makes sense if each server is on a different address, e.g. in containers. +# +# New in version 0.7. +# Default: 0 +# c.Spawner.port = 0 + +## An optional hook function that you can implement to do work after the spawner +# stops. +# +# This can be set independent of any concrete spawner implementation. +# Default: None +# c.Spawner.post_stop_hook = None + +## An optional hook function that you can implement to do some bootstrapping work +# before the spawner starts. For example, create a directory for your user or +# load initial content. +# +# This can be set independent of any concrete spawner implementation. +# +# This maybe a coroutine. +# +# Example:: +# +# from subprocess import check_call +# def my_hook(spawner): +# username = spawner.user.name +# check_call(['./examples/bootstrap-script/bootstrap.sh', username]) +# +# c.Spawner.pre_spawn_hook = my_hook +# Default: None +# c.Spawner.pre_spawn_hook = None + +## List of SSL alt names +# +# May be set in config if all spawners should have the same value(s), or set at +# runtime by Spawner that know their names. +# Default: [] +# c.Spawner.ssl_alt_names = [] + +## Whether to include DNS:localhost, IP:127.0.0.1 in alt names +# Default: True +# c.Spawner.ssl_alt_names_include_local = True + +## Timeout (in seconds) before giving up on starting of single-user server. +# +# This is the timeout for start to return, not the timeout for the server to +# respond. Callers of spawner.start will assume that startup has failed if it +# takes longer than this. start should return when the server process is started +# and its location is known. +# Default: 60 +# c.Spawner.start_timeout = 60 + +#------------------------------------------------------------------------------ +# Authenticator(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for implementing an authentication provider for JupyterHub + +## Set of users that will have admin rights on this JupyterHub. +# +# Admin users have extra privileges: +# - Use the admin panel to see list of users logged in +# - Add / remove users in some authenticators +# - Restart / halt the hub +# - Start / stop users' single-user servers +# - Can access each individual users' single-user server (if configured) +# +# Admin access should be treated the same way root access is. +# +# Defaults to an empty set, in which case no user has admin access. +# Default: set() +# c.Authenticator.admin_users = set() + +## Set of usernames that are allowed to log in. +# +# Use this with supported authenticators to restrict which users can log in. +# This is an additional list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionchanged:: 1.2 +# `Authenticator.whitelist` renamed to `allowed_users` +# Default: set() +# c.Authenticator.allowed_users = set() + +## The max age (in seconds) of authentication info before forcing a refresh of +# user auth info. +# +# Refreshing auth info allows, e.g. requesting/re-validating auth tokens. +# +# See :meth:`.refresh_user` for what happens when user auth info is refreshed +# (nothing by default). +# Default: 300 +# c.Authenticator.auth_refresh_age = 300 + +## Automatically begin the login process +# +# rather than starting with a "Login with..." link at `/hub/login` +# +# To work, `.login_url()` must give a URL other than the default `/hub/login`, +# such as an oauth handler or another automatic login handler, registered with +# `.get_handlers()`. +# +# .. versionadded:: 0.8 +# Default: False +# c.Authenticator.auto_login = False + +## Set of usernames that are not allowed to log in. +# +# Use this with supported authenticators to restrict which users can not log in. +# This is an additional block list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionadded: 0.9 +# +# .. versionchanged:: 1.2 +# `Authenticator.blacklist` renamed to `blocked_users` +# Default: set() +# c.Authenticator.blocked_users = set() + +## Delete any users from the database that do not pass validation +# +# When JupyterHub starts, `.add_user` will be called on each user in the +# database to verify that all users are still valid. +# +# If `delete_invalid_users` is True, any users that do not pass validation will +# be deleted from the database. Use this if users might be deleted from an +# external system, such as local user accounts. +# +# If False (default), invalid users remain in the Hub's database and a warning +# will be issued. This is the default to avoid data loss due to config changes. +# Default: False +# c.Authenticator.delete_invalid_users = False + +## Enable persisting auth_state (if available). +# +# auth_state will be encrypted and stored in the Hub's database. This can +# include things like authentication tokens, etc. to be passed to Spawners as +# environment variables. +# +# Encrypting auth_state requires the cryptography package. +# +# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one +# (or more, separated by ;) 32B encryption keys. These can be either base64 or +# hex-encoded. +# +# If encryption is unavailable, auth_state cannot be persisted. +# +# New in JupyterHub 0.8 +# Default: False +# c.Authenticator.enable_auth_state = False + +## An optional hook function that you can implement to do some bootstrapping work +# during authentication. For example, loading user account details from an +# external system. +# +# This function is called after the user has passed all authentication checks +# and is ready to successfully authenticate. This function must return the +# authentication dict reguardless of changes to it. +# +# This maybe a coroutine. +# +# .. versionadded: 1.0 +# +# Example:: +# +# import os, pwd +# def my_hook(authenticator, handler, authentication): +# user_data = pwd.getpwnam(authentication['name']) +# spawn_data = { +# 'pw_data': user_data +# 'gid_list': os.getgrouplist(authentication['name'], user_data.pw_gid) +# } +# +# if authentication['auth_state'] is None: +# authentication['auth_state'] = {} +# authentication['auth_state']['spawn_data'] = spawn_data +# +# return authentication +# +# c.Authenticator.post_auth_hook = my_hook +# Default: None +# c.Authenticator.post_auth_hook = None + +## Force refresh of auth prior to spawn. +# +# This forces :meth:`.refresh_user` to be called prior to launching a server, to +# ensure that auth state is up-to-date. +# +# This can be important when e.g. auth tokens that may have expired are passed +# to the spawner via environment variables from auth_state. +# +# If refresh_user cannot refresh the user auth data, launch will fail until the +# user logs in again. +# Default: False +# c.Authenticator.refresh_pre_spawn = False + +## Dictionary mapping authenticator usernames to JupyterHub users. +# +# Primarily used to normalize OAuth user names to local users. +# Default: {} +# c.Authenticator.username_map = {} + +## Regular expression pattern that all valid usernames must match. +# +# If a username does not match the pattern specified here, authentication will +# not be attempted. +# +# If not set, allow any username. +# Default: '' +# c.Authenticator.username_pattern = '' + +## Deprecated, use `Authenticator.allowed_users` +# Default: set() +# c.Authenticator.whitelist = set() + +#------------------------------------------------------------------------------ +# CryptKeeper(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## Encapsulate encryption configuration +# +# Use via the encryption_config singleton below. + +# Default: [] +# c.CryptKeeper.keys = [] + +## The number of threads to allocate for encryption +# Default: 4 +# c.CryptKeeper.n_threads = 4 + +#------------------------------------------------------------------------------ +# Pagination(Configurable) configuration +#------------------------------------------------------------------------------ +## Default number of entries per page for paginated results. +# Default: 100 +# c.Pagination.default_per_page = 100 + +## Maximum number of entries per page for paginated results. +# Default: 250 +# c.Pagination.max_per_page = 250 diff --git a/roles/network/templates/gateway/iiab-gen-iptables b/roles/network/templates/gateway/iiab-gen-iptables index f7ee6c7c9..942418a88 100755 --- a/roles/network/templates/gateway/iiab-gen-iptables +++ b/roles/network/templates/gateway/iiab-gen-iptables @@ -73,6 +73,7 @@ pbx_data_ports={{ pbx_data_ports }} sugarizer_port={{ sugarizer_port }} transmission_http_port={{ transmission_http_port }} transmission_peer_port={{ transmission_peer_port }} +jupyterhub_port={{ jupyterhub_port }} samba_udp_ports={{ samba_udp_ports }} samba_tcp_mports={{ samba_tcp_mports }} @@ -167,7 +168,8 @@ if [ "$wan" != "none" ]; then $IPTABLES -A INPUT -p tcp --dport $sugarizer_port -m state --state NEW -i $wan -j ACCEPT $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT - $IPTABLES -A INPUT -p tcp --dport $transmission_peer_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $jupyterhub_port -m state --state NEW -i $wan -j ACCEPT fi # 4 = ssh + http-or-https + common IIAB services + Samba From c2ef5999a7f6fbfa3f6645b709e1981196765e68 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:10:49 +0000 Subject: [PATCH 17/62] systemd spawner is working writing to /var/lib/private --- roles/jupyter/tasks/install.yml | 17 +++++++++++++++-- roles/jupyter/templates/jupyter.service | 2 +- roles/jupyter/templates/jupyterhub_config.py | 13 ++++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 0c2526856..353f78cae 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,4 +1,9 @@ -- name: Make the directories to hold notebooks +- name: We need a non-privileged user to write all the notebooks + ansible.builtin.user: + name: web-user + home: /opt/iiab/notebooks + +- name: Make the directories to hold jupyter config file: state: directory path: '{{ item }}' @@ -7,6 +12,12 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' +- name: Make a directory to hold notebooks + file: + state: directory + path: /opt/iiab/notebooks + owner: web-user + - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -35,6 +46,8 @@ - ipywidgets - jupyterhub - jupyterlab + - jupyterhub_firstuseauthenticator + - jupyterhub-systemdspawner virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -45,7 +58,7 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/env/jupyterhub/' + dest: '{{ jupyter_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 363390a9f..f9e5aa798 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -3,7 +3,7 @@ Description=JupyterHub After=syslog.target network.target [Service] -User=hubuser +User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 00c70a126..71d81dbb9 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -114,7 +114,7 @@ # - dummy: jupyterhub.auth.DummyAuthenticator # - pam: jupyterhub.auth.PAMAuthenticator # Default: 'jupyterhub.auth.PAMAuthenticator' -# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' +c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' ## The base URL of the entire application. # @@ -194,7 +194,7 @@ # # Should be exactly 256 bits (32 bytes). # Default: b'' -# c.JupyterHub.cookie_secret = b'' +c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## File in which to store the cookie secret. # Default: 'jupyterhub_cookie_secret' @@ -589,7 +589,7 @@ # - localprocess: jupyterhub.spawner.LocalProcessSpawner # - simple: jupyterhub.spawner.SimpleLocalProcessSpawner # Default: 'jupyterhub.spawner.LocalProcessSpawner' -# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' +c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## Path to SSL certificate file for the public facing interface of the proxy # @@ -1229,3 +1229,10 @@ ## Maximum number of entries per page for paginated results. # Default: 250 # c.Pagination.max_per_page = 250 + +#------------------------------------------------------------------------------ +# Systemdspawner config +#------------------------------------------------------------------------------ +c.SystemdSpawner.dynamic_users = True +c.SystemdSpawner.user_workingdir = '/opt/iiab/notebooks/{USERNAME}' + From f95cbd5222c67caba5596c23c21e2261eb5dc4be Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:19:17 +0000 Subject: [PATCH 18/62] change systemd to more specifially use the venv --- roles/jupyter/templates/jupyter.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index f9e5aa798..8ce535369 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -5,7 +5,7 @@ After=syslog.target network.target [Service] User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target From def835205beb6e2be4cac7995150732625a27c50 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:33:47 +0000 Subject: [PATCH 19/62] add iiab-admin to the authentication list --- roles/jupyter/templates/jupyterhub_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 71d81dbb9..999715a8f 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() -# c.Authenticator.admin_users = set() + c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From 94f5d14c9aae292fa83ada21ef70940f0a872b08 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 05:15:15 +0000 Subject: [PATCH 20/62] remove creation of notebook, spawner puts in /var/lib/private --- roles/jupyter/tasks/enable-or-disable.yml | 16 ++++++++++++++++ roles/jupyter/tasks/install.yml | 12 +----------- roles/jupyter/templates/jupyterhub_config.py | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml index ad8bb17ad..becab8e9a 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -23,3 +23,19 @@ when: not jupyter_enabled +- name: Put the nginx config file in place + template: + src: jupyter-nginx.conf + dest: "{{ nginx_conf_dir }}/" + when: jupyter_enabled + +- name: Disable jupyterhub + file: + path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + state: absent + when: not jupyter_enabled + +- name: Restart 'nginx' systemd service + systemd: + name: nginx + state: restarted diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 353f78cae..6901db83d 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,8 +1,3 @@ -- name: We need a non-privileged user to write all the notebooks - ansible.builtin.user: - name: web-user - home: /opt/iiab/notebooks - - name: Make the directories to hold jupyter config file: state: directory @@ -12,12 +7,6 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' -- name: Make a directory to hold notebooks - file: - state: directory - path: /opt/iiab/notebooks - owner: web-user - - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -59,6 +48,7 @@ template: src: jupyterhub_config.py dest: '{{ jupyter_venv }}/etc/jupyterhub/' + - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 999715a8f..cd0999ca1 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() - c.Authenticator.admin_users = set('iiab-admin') +c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From f0a0fa0996fdeaddefdaa65f7af976ad75451fbd Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 17:35:48 +0000 Subject: [PATCH 21/62] getting nginx proxy to work /jupyterhub --- roles/jupyter/templates/jupyter-nginx.conf | 20 ++++++++++++++++++++ roles/jupyter/templates/jupyterhub_config.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 roles/jupyter/templates/jupyter-nginx.conf diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyter/templates/jupyter-nginx.conf new file mode 100644 index 000000000..a9d450c10 --- /dev/null +++ b/roles/jupyter/templates/jupyter-nginx.conf @@ -0,0 +1,20 @@ +location /jupyterhub { + proxy_pass http://127.0.0.1:8000; + proxy_set_header X-Real-IP $remote_addr; + #proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; + + + # websocket headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + #proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Scheme $scheme; + + proxy_buffering off; + } + # Managing requests to verify letsencrypt host + location ~ /.well-known { + allow all; + } diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index cd0999ca1..ade964254 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/' +# c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From e9bb8fdb63f8772d6c12afa6363c4d6be279301c Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 05:07:56 +0000 Subject: [PATCH 22/62] add in README.md --- roles/jupyter/docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 roles/jupyter/docs/README.md diff --git a/roles/jupyter/docs/README.md b/roles/jupyter/docs/README.md new file mode 100644 index 000000000..2878ebaa6 --- /dev/null +++ b/roles/jupyter/docs/README.md @@ -0,0 +1,6 @@ +### Jupyter Notebooks on Rpi Server +* Jupyter Notebooks are widely used in the scientific community. +* This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. +* Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. +* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. +* Students will not have any priviletes outside of their own folder. From 2248b9fdad27a3b90457dcba940f6e0d6e6e7e4a Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:24:05 +0000 Subject: [PATCH 23/62] remove the jupyter<->jupyterhub conflict. Make all jupyterhub --- roles/{jupyter => jupyterhub}/defaults/main.yml | 2 +- roles/{jupyter => jupyterhub}/docs/README.md | 0 .../tasks/enable-or-disable.yml | 16 ++++++++-------- roles/{jupyter => jupyterhub}/tasks/install.yml | 12 ++++++------ roles/{jupyter => jupyterhub}/tasks/main.yml | 8 ++++---- .../templates/jupyterhub-nginx.conf} | 0 .../templates/jupyterhub.service} | 4 ++-- .../templates/jupyterhub_config.py | 0 vars/default_vars.yml | 4 ++-- 9 files changed, 23 insertions(+), 23 deletions(-) rename roles/{jupyter => jupyterhub}/defaults/main.yml (77%) rename roles/{jupyter => jupyterhub}/docs/README.md (100%) rename roles/{jupyter => jupyterhub}/tasks/enable-or-disable.yml (69%) rename roles/{jupyter => jupyterhub}/tasks/install.yml (81%) rename roles/{jupyter => jupyterhub}/tasks/main.yml (66%) rename roles/{jupyter/templates/jupyter-nginx.conf => jupyterhub/templates/jupyterhub-nginx.conf} (100%) rename roles/{jupyter/templates/jupyter.service => jupyterhub/templates/jupyterhub.service} (54%) rename roles/{jupyter => jupyterhub}/templates/jupyterhub_config.py (100%) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyterhub/defaults/main.yml similarity index 77% rename from roles/jupyter/defaults/main.yml rename to roles/jupyterhub/defaults/main.yml index b22730df0..d4231ae72 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,4 @@ notebook_dir: /opt/iiab/notebook -jupyter_venv: /opt/iiab/jupyter +jupyterhub_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub jupyterhub_port: 8000 diff --git a/roles/jupyter/docs/README.md b/roles/jupyterhub/docs/README.md similarity index 100% rename from roles/jupyter/docs/README.md rename to roles/jupyterhub/docs/README.md diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyterhub/tasks/enable-or-disable.yml similarity index 69% rename from roles/jupyter/tasks/enable-or-disable.yml rename to roles/jupyterhub/tasks/enable-or-disable.yml index becab8e9a..aacd9a35d 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyterhub/tasks/enable-or-disable.yml @@ -10,8 +10,8 @@ enabled: yes state: restarted with_items: - - jupyter - when: jupyter_enabled + - jupyterhub.service + when: jupyterhub_enabled - name: Disable jupyterhub systemd: @@ -19,21 +19,21 @@ enabled: no state: stopped with_items: - - jupyter - when: not jupyter_enabled + - jupyterhub + when: not jupyterhub_enabled - name: Put the nginx config file in place template: - src: jupyter-nginx.conf + src: jupyterhub-nginx.conf dest: "{{ nginx_conf_dir }}/" - when: jupyter_enabled + when: jupyterhub_enabled - name: Disable jupyterhub file: - path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + path: "{{ nginx_conf_dir }}/jupyterhub-nginx.conf" state: absent - when: not jupyter_enabled + when: not jupyterhub_enabled - name: Restart 'nginx' systemd service systemd: diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyterhub/tasks/install.yml similarity index 81% rename from roles/jupyter/tasks/install.yml rename to roles/jupyterhub/tasks/install.yml index 6901db83d..baae04456 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyterhub/tasks/install.yml @@ -3,9 +3,9 @@ state: directory path: '{{ item }}' with_items: - - '{{ jupyter_venv }}/etc/jupyter' - - '{{ jupyter_venv }}/etc/jupyterhub' - - '{{ jupyter_venv }}/etc/systemd' + - '{{ jupyterhub_venv }}/etc/jupyter' + - '{{ jupyterhub_venv }}/etc/jupyterhub' + - '{{ jupyterhub_venv }}/etc/systemd' - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: @@ -37,7 +37,7 @@ - jupyterlab - jupyterhub_firstuseauthenticator - jupyterhub-systemdspawner - virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv virtualenv_python: python3 @@ -47,9 +47,9 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/etc/jupyterhub/' + dest: '{{ jupyterhub_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: - src: jupyter.service + src: jupyterhub.service dest: /etc/systemd/system/ diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyterhub/tasks/main.yml similarity index 66% rename from roles/jupyter/tasks/main.yml rename to roles/jupyterhub/tasks/main.yml index 137a01b84..9090610a0 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -1,6 +1,6 @@ -- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml +- name: Install Jupyter if jupyterhub_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml include_tasks: install.yml - when: jupyter_installed is undefined + when: jupyterhub_installed is undefined - include_tasks: enable-or-disable.yml @@ -18,6 +18,6 @@ - option: description value: '"Raspberry Pi Jupyter python programming environment"' - option: install - value: "{{ jupyter_install }}" + value: "{{ jupyterhub_install }}" - option: enabled - value: "{{ jupyter_enabled }}" + value: "{{ jupyterhub_enabled }}" diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf similarity index 100% rename from roles/jupyter/templates/jupyter-nginx.conf rename to roles/jupyterhub/templates/jupyterhub-nginx.conf diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyterhub/templates/jupyterhub.service similarity index 54% rename from roles/jupyter/templates/jupyter.service rename to roles/jupyterhub/templates/jupyterhub.service index 8ce535369..3137d0404 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyterhub/templates/jupyterhub.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=root -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyterhub_venv }}/bin" +ExecStart={{ jupyterhub_venv }}/bin/python3 -m jupyterhub -f {{ jupyterhub_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py similarity index 100% rename from roles/jupyter/templates/jupyterhub_config.py rename to roles/jupyterhub/templates/jupyterhub_config.py diff --git a/vars/default_vars.yml b/vars/default_vars.yml index d1fb036e1..c932b98a6 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -564,8 +564,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False -jupyter_install: False -jupyter_enabled: False +jupyterhub_install: False +jupyterhub_enabled: False # 9-LOCAL-ADDONS From c6629cea695ca0c4c4ce7b4e4af49af44a60a25d Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:35:27 +0000 Subject: [PATCH 24/62] remaining jupyter->jupyterhub items --- roles/jupyterhub/defaults/main.yml | 4 +--- roles/jupyterhub/templates/jupyterhub_config.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/roles/jupyterhub/defaults/main.yml b/roles/jupyterhub/defaults/main.yml index d4231ae72..a859f9946 100644 --- a/roles/jupyterhub/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,2 @@ -notebook_dir: /opt/iiab/notebook -jupyterhub_venv: /opt/iiab/jupyter -jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_venv: /opt/iiab/jupyterhub jupyterhub_port: 8000 diff --git a/roles/jupyterhub/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py index ade964254..2eba8b290 100644 --- a/roles/jupyterhub/templates/jupyterhub_config.py +++ b/roles/jupyterhub/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/jupyterhub' +c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From 8864389f25951d5ab6207f7c040e01f976ecaf50 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 1 Apr 2021 13:22:04 +0000 Subject: [PATCH 25/62] update README --- roles/jupyterhub/docs/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/roles/jupyterhub/docs/README.md b/roles/jupyterhub/docs/README.md index 2878ebaa6..9285bfa1b 100644 --- a/roles/jupyterhub/docs/README.md +++ b/roles/jupyterhub/docs/README.md @@ -3,4 +3,5 @@ * This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. * Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. * Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. -* Students will not have any priviletes outside of their own folder. +* Students will not have any privileges outside of their own folder. +* They may upload jupyter notebooks from a local machine, and download the current state of their work via a normal browser download. From 9e43834f00145c9e3e28a25574e5580f4502f767 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Mon, 12 Apr 2021 04:47:31 +0100 Subject: [PATCH 26/62] seems able to save files -- but storage is not in library as requested --- roles/jupyterhub/templates/jupyterhub-nginx.conf | 2 +- roles/jupyterhub/templates/jupyterhub_config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/jupyterhub/templates/jupyterhub-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf index a9d450c10..32c999261 100644 --- a/roles/jupyterhub/templates/jupyterhub-nginx.conf +++ b/roles/jupyterhub/templates/jupyterhub-nginx.conf @@ -1,7 +1,7 @@ location /jupyterhub { proxy_pass http://127.0.0.1:8000; proxy_set_header X-Real-IP $remote_addr; - #proxy_set_header Host $host; + proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; diff --git a/roles/jupyterhub/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py index 2eba8b290..d78f82f80 100644 --- a/roles/jupyterhub/templates/jupyterhub_config.py +++ b/roles/jupyterhub/templates/jupyterhub_config.py @@ -211,7 +211,7 @@ c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## url for the database. e.g. `sqlite:///jupyterhub.sqlite` # Default: 'sqlite:///jupyterhub.sqlite' -# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' +c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## log all database transactions. This has A LOT of output # Default: False From 98634909ec366e143643f31435d92903b58231b2 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Mon, 8 Mar 2021 01:57:10 +0000 Subject: [PATCH 27/62] venv runs without jupyterlab-vim --- .gitignore | 1 + roles/jupyter/defaults/main.yml | 2 ++ roles/jupyter/tasks/install.yml | 17 +++++++++++++++++ roles/jupyter/tasks/main.yml | 23 +++++++++++++++++++++++ vars/default_vars.yml | 2 ++ 5 files changed, 45 insertions(+) create mode 100644 roles/jupyter/defaults/main.yml create mode 100644 roles/jupyter/tasks/install.yml create mode 100644 roles/jupyter/tasks/main.yml diff --git a/.gitignore b/.gitignore index fc4b12be2..38f8427ed 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ deprecated *.patches *.log *.retry +*~ diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml new file mode 100644 index 000000000..017b0de30 --- /dev/null +++ b/roles/jupyter/defaults/main.yml @@ -0,0 +1,2 @@ +notebook_dir: /opt/iiab/notebook +jupyter_venv: /opt/iiab/jupyter diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml new file mode 100644 index 000000000..3330ba743 --- /dev/null +++ b/roles/jupyter/tasks/install.yml @@ -0,0 +1,17 @@ +- name: Make the directories to hold notebooks + file: + state: directory + path: '{{ notebook_dir }}' + +- name: Use pip to install into a virtual environment + pip: + name: + - jupyterlab + #- jupyter_vim + virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv_site_packages: no + virtualenv_command: /usr/bin/virtualenv + virtualenv_python: python3 + extra_args: "--no-cache-dir" + when: internet_available + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml new file mode 100644 index 000000000..9f1804b38 --- /dev/null +++ b/roles/jupyter/tasks/main.yml @@ -0,0 +1,23 @@ +- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: jupyter_installed is undefined + + +#- include_tasks: enable-or-disable.yml + + +- name: Add 'jupyter' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: jupyter + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Jupyter + - option: description + value: '"Raspberry Pi Jupyter python programming environment"' + - option: install + value: "{{ jupyter_install }}" + - option: enabled + value: "{{ jupyter_enabled }}" diff --git a/vars/default_vars.yml b/vars/default_vars.yml index 9690ba595..d1fb036e1 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -564,6 +564,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False +jupyter_install: False +jupyter_enabled: False # 9-LOCAL-ADDONS From ca697f492621b658e86080980572c6b7a5c5096b Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 04:57:33 +0000 Subject: [PATCH 28/62] Found instructions for the Littlest Jupyterhub --- roles/jupyter/tasks/enable-or-disable.yml | 25 +++++++++++++++++++++++ roles/jupyter/tasks/install.yml | 19 ++++++++++++++--- roles/jupyter/tasks/main.yml | 2 +- roles/jupyter/templates/jupyter.service | 11 ++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 roles/jupyter/tasks/enable-or-disable.yml create mode 100644 roles/jupyter/templates/jupyter.service diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml new file mode 100644 index 000000000..ad8bb17ad --- /dev/null +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -0,0 +1,25 @@ +- name: systemd daemon-reload + systemd: + daemon_reload: yes + + +# enable or disable +- name: Enable & Restart jupyterhub + systemd: + name: "{{ item }}" + enabled: yes + state: restarted + with_items: + - jupyter + when: jupyter_enabled + +- name: Disable jupyterhub + systemd: + name: "{{ item }}" + enabled: no + state: stopped + with_items: + - jupyter + when: not jupyter_enabled + + diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 3330ba743..4e2981584 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,13 +1,16 @@ - name: Make the directories to hold notebooks file: state: directory - path: '{{ notebook_dir }}' + path: '{{ item }}' + with_items: + - '{{ notebook_dir }}/etc/jupyter' + - '{{ notebook_dir }}/etc/jupyterhub' + - '{{ notebook_dir }}/etc/systemd' - name: Use pip to install into a virtual environment pip: name: - - jupyterlab - #- jupyter_vim + - pip virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -15,3 +18,13 @@ extra_args: "--no-cache-dir" when: internet_available +- name: Fetch the Littlest JupyterHub code + ansible.builtin.git: + repo: '{{ jupyterhub_url }} + dest: '{{ jupyter_venv }}' + +- name: Install a bootstrap.py that permits installation on other than Ubunt + template: + src: bootstrap.py + dest: '{{ jupyter_venv }}' + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml index 9f1804b38..137a01b84 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyter/tasks/main.yml @@ -3,7 +3,7 @@ when: jupyter_installed is undefined -#- include_tasks: enable-or-disable.yml +- include_tasks: enable-or-disable.yml - name: Add 'jupyter' variable values to {{ iiab_ini_file }} diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service new file mode 100644 index 000000000..81cee0dd2 --- /dev/null +++ b/roles/jupyter/templates/jupyter.service @@ -0,0 +1,11 @@ +[Unit] +Description=JupyterHub +After=syslog.target network.target + +[Service] +User=hubuser +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" +ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py + +[Install] +WantedBy=multi-user.target From 67a19a6eb522942fcf8edddf53787f917a42640e Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 19:56:46 +0000 Subject: [PATCH 29/62] changes to venv --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index 017b0de30..c879b76ac 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,2 +1,3 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter +jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 4e2981584..b311464b6 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -11,6 +11,8 @@ pip: name: - pip + - wheel + - ipywidgets virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv From abeae782596108e2f48bf49c2ceafecc76a4dc14 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 22:57:39 +0000 Subject: [PATCH 30/62] displayed the ted notebook on raspi-os --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 44 +- roles/jupyter/templates/jupyter.service | 4 +- roles/jupyter/templates/jupyterhub_config.py | 1231 +++++++++++++++++ .../templates/gateway/iiab-gen-iptables | 4 +- 5 files changed, 1269 insertions(+), 15 deletions(-) create mode 100644 roles/jupyter/templates/jupyterhub_config.py diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index c879b76ac..b22730df0 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,3 +1,4 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_port: 8000 diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index b311464b6..0c2526856 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -3,9 +3,29 @@ state: directory path: '{{ item }}' with_items: - - '{{ notebook_dir }}/etc/jupyter' - - '{{ notebook_dir }}/etc/jupyterhub' - - '{{ notebook_dir }}/etc/systemd' + - '{{ jupyter_venv }}/etc/jupyter' + - '{{ jupyter_venv }}/etc/jupyterhub' + - '{{ jupyter_venv }}/etc/systemd' + +- name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" + set_fact: + nodejs_install: True + nodejs_enabled: True + +- name: NODEJS - run 'nodejs' role (attempt to install & enable Node.js) + include_role: + name: nodejs + +- name: FAIL (STOP THE INSTALL) IF 'nodejs_installed is undefined' + fail: + msg: "Jupyter install cannot proceed, as Node.js is not installed." + when: nodejs_installed is undefined + +- name: use npm to install configurable http proxy + npm: + name: configurable-http-proxy + global: yes + state: latest - name: Use pip to install into a virtual environment pip: @@ -13,6 +33,8 @@ - pip - wheel - ipywidgets + - jupyterhub + - jupyterlab virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -20,13 +42,11 @@ extra_args: "--no-cache-dir" when: internet_available -- name: Fetch the Littlest JupyterHub code - ansible.builtin.git: - repo: '{{ jupyterhub_url }} - dest: '{{ jupyter_venv }}' - -- name: Install a bootstrap.py that permits installation on other than Ubunt +- name: Install the config file for jupyterhub template: - src: bootstrap.py - dest: '{{ jupyter_venv }}' - + src: jupyterhub_config.py + dest: '{{ jupyter_venv }}/env/jupyterhub/' +- name: Use systemd to start jupyterhub + template: + src: jupyter.service + dest: /etc/systemd/system/ diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 81cee0dd2..363390a9f 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=hubuser -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" -ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" +ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py new file mode 100644 index 000000000..00c70a126 --- /dev/null +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -0,0 +1,1231 @@ +# Configuration file for jupyterhub. + +#------------------------------------------------------------------------------ +# Application(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## This is an application. + +## The date format used by logging formatters for %(asctime)s +# Default: '%Y-%m-%d %H:%M:%S' +# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# Default: '[%(name)s]%(highlevel)s %(message)s' +# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] +# Default: 30 +# c.Application.log_level = 30 + +## Instead of starting the Application, dump configuration to stdout +# Default: False +# c.Application.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# Default: False +# c.Application.show_config_json = False + +#------------------------------------------------------------------------------ +# JupyterHub(Application) configuration +#------------------------------------------------------------------------------ +## An Application for starting a Multi-User Jupyter Notebook server. + +## Maximum number of concurrent servers that can be active at a time. +# +# Setting this can limit the total resources your users can consume. +# +# An active server is any server that's not fully stopped. It is considered +# active from the time it has been requested until the time that it has +# completely stopped. +# +# If this many user servers are active, users will not be able to launch new +# servers until a server is shutdown. Spawn requests will be rejected with a 429 +# error asking them to try again. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.active_server_limit = 0 + +## Duration (in seconds) to determine the number of active users. +# Default: 1800 +# c.JupyterHub.active_user_window = 1800 + +## Resolution (in seconds) for updating activity +# +# If activity is registered that is less than activity_resolution seconds more +# recent than the current value, the new value will be ignored. +# +# This avoids too many writes to the Hub database. +# Default: 30 +# c.JupyterHub.activity_resolution = 30 + +## Grant admin users permission to access single-user servers. +# +# Users should be properly informed if this is enabled. +# Default: False +# c.JupyterHub.admin_access = False + +## DEPRECATED since version 0.7.2, use Authenticator.admin_users instead. +# Default: set() +# c.JupyterHub.admin_users = set() + +## Allow named single-user servers per user +# Default: False +# c.JupyterHub.allow_named_servers = False + +## Answer yes to any questions (e.g. confirm overwrite) +# Default: False +# c.JupyterHub.answer_yes = False + +## PENDING DEPRECATION: consider using services +# +# Dict of token:username to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services, which authenticate as JupyterHub users. +# +# Consider using services for general services that talk to the JupyterHub API. +# Default: {} +# c.JupyterHub.api_tokens = {} + +## Authentication for prometheus metrics +# Default: True +# c.JupyterHub.authenticate_prometheus = True + +## Class for authenticating users. +# +# This should be a subclass of :class:`jupyterhub.auth.Authenticator` +# +# with an :meth:`authenticate` method that: +# +# - is a coroutine (asyncio or tornado) +# - returns username on success, None on failure +# - takes two arguments: (handler, data), +# where `handler` is the calling web.RequestHandler, +# and `data` is the POST form data from the login page. +# +# .. versionchanged:: 1.0 +# authenticators may be registered via entry points, +# e.g. `c.JupyterHub.authenticator_class = 'pam'` +# +# Currently installed: +# - default: jupyterhub.auth.PAMAuthenticator +# - dummy: jupyterhub.auth.DummyAuthenticator +# - pam: jupyterhub.auth.PAMAuthenticator +# Default: 'jupyterhub.auth.PAMAuthenticator' +# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' + +## The base URL of the entire application. +# +# Add this to the beginning of all JupyterHub URLs. Use base_url to run +# JupyterHub within an existing website. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '/' +# c.JupyterHub.base_url = '/' + +## The public facing URL of the whole JupyterHub application. +# +# This is the address on which the proxy will bind. Sets protocol, ip, base_url +# Default: 'http://:8000' +# c.JupyterHub.bind_url = 'http://:8000' + +## Whether to shutdown the proxy when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the proxy +# running. +# +# Only valid if the proxy was starting by the Hub process. +# +# If both this and cleanup_servers are False, sending SIGINT to the Hub will +# only shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_proxy = True + +## Whether to shutdown single-user servers when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the single- +# user servers running. +# +# If both this and cleanup_proxy are False, sending SIGINT to the Hub will only +# shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_servers = True + +## Maximum number of concurrent users that can be spawning at a time. +# +# Spawning lots of servers at the same time can cause performance problems for +# the Hub or the underlying spawning system. Set this limit to prevent bursts of +# logins from attempting to spawn too many servers at the same time. +# +# This does not limit the number of total running servers. See +# active_server_limit for that. +# +# If more than this many users attempt to spawn at a time, their requests will +# be rejected with a 429 error asking them to try again. Users will have to wait +# for some of the spawning services to finish starting before they can start +# their own. +# +# If set to 0, no limit is enforced. +# Default: 100 +# c.JupyterHub.concurrent_spawn_limit = 100 + +## The config file to load +# Default: 'jupyterhub_config.py' +# c.JupyterHub.config_file = 'jupyterhub_config.py' + +## DEPRECATED: does nothing +# Default: False +# c.JupyterHub.confirm_no_ssl = False + +## Number of days for a login cookie to be valid. Default is two weeks. +# Default: 14 +# c.JupyterHub.cookie_max_age_days = 14 + +## The cookie secret to use to encrypt cookies. +# +# Loaded from the JPY_COOKIE_SECRET env variable by default. +# +# Should be exactly 256 bits (32 bytes). +# Default: b'' +# c.JupyterHub.cookie_secret = b'' + +## File in which to store the cookie secret. +# Default: 'jupyterhub_cookie_secret' +# c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' + +## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) +# Default: '/opt/iiab/jupyter/share/jupyterhub' +# c.JupyterHub.data_files_path = '/opt/iiab/jupyter/share/jupyterhub' + +## Include any kwargs to pass to the database connection. See +# sqlalchemy.create_engine for details. +# Default: {} +# c.JupyterHub.db_kwargs = {} + +## url for the database. e.g. `sqlite:///jupyterhub.sqlite` +# Default: 'sqlite:///jupyterhub.sqlite' +# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' + +## log all database transactions. This has A LOT of output +# Default: False +# c.JupyterHub.debug_db = False + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.debug +# Default: False +# c.JupyterHub.debug_proxy = False + +## If named servers are enabled, default name of server to spawn or open, e.g. by +# user-redirect. +# Default: '' +# c.JupyterHub.default_server_name = '' + +## The default URL for users when they arrive (e.g. when user directs to "/") +# +# By default, redirects users to their own server. +# +# Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler +# object: +# +# :: +# +# def default_url_fn(handler): +# user = handler.current_user +# if user and user.admin: +# return '/hub/admin' +# return '/hub/home' +# +# c.JupyterHub.default_url = default_url_fn +# Default: traitlets.Undefined +# c.JupyterHub.default_url = traitlets.Undefined + +## Dict authority:dict(files). Specify the key, cert, and/or ca file for an +# authority. This is useful for externally managed proxies that wish to use +# internal_ssl. +# +# The files dict has this format (you must specify at least a cert):: +# +# { +# 'key': '/path/to/key.key', +# 'cert': '/path/to/cert.crt', +# 'ca': '/path/to/ca.crt' +# } +# +# The authorities you can override: 'hub-ca', 'notebooks-ca', 'proxy-api-ca', +# 'proxy-client-ca', and 'services-ca'. +# +# Use with internal_ssl +# Default: {} +# c.JupyterHub.external_ssl_authorities = {} + +## Register extra tornado Handlers for jupyterhub. +# +# Should be of the form ``("", Handler)`` +# +# The Hub prefix will be added, so `/my-page` will be served at `/hub/my-page`. +# Default: [] +# c.JupyterHub.extra_handlers = [] + +## DEPRECATED: use output redirection instead, e.g. +# +# jupyterhub &>> /var/log/jupyterhub.log +# Default: '' +# c.JupyterHub.extra_log_file = '' + +## Extra log handlers to set on JupyterHub logger +# Default: [] +# c.JupyterHub.extra_log_handlers = [] + +## Generate certs used for internal ssl +# Default: False +# c.JupyterHub.generate_certs = False + +## Generate default config file +# Default: False +# c.JupyterHub.generate_config = False + +## The URL on which the Hub will listen. This is a private URL for internal +# communication. Typically set in combination with hub_connect_url. If a unix +# socket, hub_connect_url **must** also be set. +# +# For example: +# +# "http://127.0.0.1:8081" +# "unix+http://%2Fsrv%2Fjupyterhub%2Fjupyterhub.sock" +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_bind_url = '' + +## The ip or hostname for proxies and spawners to use for connecting to the Hub. +# +# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different +# from the connect address. +# +# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, otherwise +# use `hub_ip`. +# +# Note: Some spawners or proxy implementations might not support hostnames. +# Check your spawner or proxy documentation to see if they have extra +# requirements. +# +# .. versionadded:: 0.8 +# Default: '' +# c.JupyterHub.hub_connect_ip = '' + +## DEPRECATED +# +# Use hub_connect_url +# +# .. versionadded:: 0.8 +# +# .. deprecated:: 0.9 +# Use hub_connect_url +# Default: 0 +# c.JupyterHub.hub_connect_port = 0 + +## The URL for connecting to the Hub. Spawners, services, and the proxy will use +# this URL to talk to the Hub. +# +# Only needs to be specified if the default hub URL is not connectable (e.g. +# using a unix+http:// bind url). +# +# .. seealso:: +# JupyterHub.hub_connect_ip +# JupyterHub.hub_bind_url +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_connect_url = '' + +## The ip address for the Hub process to *bind* to. +# +# By default, the hub listens on localhost only. This address must be accessible +# from the proxy and user servers. You may need to set this to a public ip or '' +# for all interfaces if the proxy or user servers are in containers or on a +# different host. +# +# See `hub_connect_ip` for cases where the bind and connect address should +# differ, or `hub_bind_url` for setting the full bind URL. +# Default: '127.0.0.1' +# c.JupyterHub.hub_ip = '127.0.0.1' + +## The internal port for the Hub process. +# +# This is the internal port of the hub itself. It should never be accessed +# directly. See JupyterHub.port for the public port to use when accessing +# jupyterhub. It is rare that this port should be set except in cases of port +# conflict. +# +# See also `hub_ip` for the ip and `hub_bind_url` for setting the full bind URL. +# Default: 8081 +# c.JupyterHub.hub_port = 8081 + +## Trigger implicit spawns after this many seconds. +# +# When a user visits a URL for a server that's not running, they are shown a +# page indicating that the requested server is not running with a button to +# spawn the server. +# +# Setting this to a positive value will redirect the user after this many +# seconds, effectively clicking this button automatically for the users, +# automatically beginning the spawn process. +# +# Warning: this can result in errors and surprising behavior when sharing access +# URLs to actual servers, since the wrong server is likely to be started. +# Default: 0 +# c.JupyterHub.implicit_spawn_seconds = 0 + +## Timeout (in seconds) to wait for spawners to initialize +# +# Checking if spawners are healthy can take a long time if many spawners are +# active at hub start time. +# +# If it takes longer than this timeout to check, init_spawner will be left to +# complete in the background and the http server is allowed to start. +# +# A timeout of -1 means wait forever, which can mean a slow startup of the Hub +# but ensures that the Hub is fully consistent by the time it starts responding +# to requests. This matches the behavior of jupyterhub 1.0. +# +# .. versionadded: 1.1.0 +# Default: 10 +# c.JupyterHub.init_spawners_timeout = 10 + +## The location to store certificates automatically created by JupyterHub. +# +# Use with internal_ssl +# Default: 'internal-ssl' +# c.JupyterHub.internal_certs_location = 'internal-ssl' + +## Enable SSL for all internal communication +# +# This enables end-to-end encryption between all JupyterHub components. +# JupyterHub will automatically create the necessary certificate authority and +# sign notebook certificates as they're created. +# Default: False +# c.JupyterHub.internal_ssl = False + +## The public facing ip of the whole JupyterHub application (specifically +# referred to as the proxy). +# +# This is the address on which the proxy will listen. The default is to listen +# on all interfaces. This is the only address through which JupyterHub should be +# accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '' +# c.JupyterHub.ip = '' + +## Supply extra arguments that will be passed to Jinja environment. +# Default: {} +# c.JupyterHub.jinja_environment_options = {} + +## Interval (in seconds) at which to update last-activity timestamps. +# Default: 300 +# c.JupyterHub.last_activity_interval = 300 + +## Dict of 'group': ['usernames'] to load at startup. +# +# This strictly *adds* groups and users to groups. +# +# Loading one set of groups, then starting JupyterHub again with a different set +# will not remove users or groups from previous launches. That must be done +# through the API. +# Default: {} +# c.JupyterHub.load_groups = {} + +## The date format used by logging formatters for %(asctime)s +# See also: Application.log_datefmt +# c.JupyterHub.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# See also: Application.log_format +# c.JupyterHub.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# See also: Application.log_level +# c.JupyterHub.log_level = 30 + +## Specify path to a logo image to override the Jupyter logo in the banner. +# Default: '' +# c.JupyterHub.logo_file = '' + +## Maximum number of concurrent named servers that can be created by a user at a +# time. +# +# Setting this can limit the total resources a user can consume. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.named_server_limit_per_user = 0 + +## File to write PID Useful for daemonizing JupyterHub. +# Default: '' +# c.JupyterHub.pid_file = '' + +## The public facing port of the proxy. +# +# This is the port on which the proxy will listen. This is the only port through +# which JupyterHub should be accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: 8000 +# c.JupyterHub.port = 8000 + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: '' +# c.JupyterHub.proxy_api_ip = '' + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: 0 +# c.JupyterHub.proxy_api_port = 0 + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.auth_token +# Default: '' +# c.JupyterHub.proxy_auth_token = '' + +## Interval (in seconds) at which to check if the proxy is running. +# Default: 30 +# c.JupyterHub.proxy_check_interval = 30 + +## The class to use for configuring the JupyterHub proxy. +# +# Should be a subclass of :class:`jupyterhub.proxy.Proxy`. +# +# .. versionchanged:: 1.0 +# proxies may be registered via entry points, +# e.g. `c.JupyterHub.proxy_class = 'traefik'` +# +# Currently installed: +# - configurable-http-proxy: jupyterhub.proxy.ConfigurableHTTPProxy +# - default: jupyterhub.proxy.ConfigurableHTTPProxy +# Default: 'jupyterhub.proxy.ConfigurableHTTPProxy' +# c.JupyterHub.proxy_class = 'jupyterhub.proxy.ConfigurableHTTPProxy' + +## DEPRECATED since version 0.8. Use ConfigurableHTTPProxy.command +# Default: [] +# c.JupyterHub.proxy_cmd = [] + +## Recreate all certificates used within JupyterHub on restart. +# +# Note: enabling this feature requires restarting all notebook servers. +# +# Use with internal_ssl +# Default: False +# c.JupyterHub.recreate_internal_certs = False + +## Redirect user to server (if running), instead of control panel. +# Default: True +# c.JupyterHub.redirect_to_server = True + +## Purge and reset the database. +# Default: False +# c.JupyterHub.reset_db = False + +## Interval (in seconds) at which to check connectivity of services with web +# endpoints. +# Default: 60 +# c.JupyterHub.service_check_interval = 60 + +## Dict of token:servicename to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services. +# Default: {} +# c.JupyterHub.service_tokens = {} + +## List of service specification dictionaries. +# +# A service +# +# For instance:: +# +# services = [ +# { +# 'name': 'cull_idle', +# 'command': ['/path/to/cull_idle_servers.py'], +# }, +# { +# 'name': 'formgrader', +# 'url': 'http://127.0.0.1:1234', +# 'api_token': 'super-secret', +# 'environment': +# } +# ] +# Default: [] +# c.JupyterHub.services = [] + +## Instead of starting the Application, dump configuration to stdout +# See also: Application.show_config +# c.JupyterHub.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# See also: Application.show_config_json +# c.JupyterHub.show_config_json = False + +## Shuts down all user servers on logout +# Default: False +# c.JupyterHub.shutdown_on_logout = False + +## The class to use for spawning single-user servers. +# +# Should be a subclass of :class:`jupyterhub.spawner.Spawner`. +# +# .. versionchanged:: 1.0 +# spawners may be registered via entry points, +# e.g. `c.JupyterHub.spawner_class = 'localprocess'` +# +# Currently installed: +# - default: jupyterhub.spawner.LocalProcessSpawner +# - localprocess: jupyterhub.spawner.LocalProcessSpawner +# - simple: jupyterhub.spawner.SimpleLocalProcessSpawner +# Default: 'jupyterhub.spawner.LocalProcessSpawner' +# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' + +## Path to SSL certificate file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_key +# Default: '' +# c.JupyterHub.ssl_cert = '' + +## Path to SSL key file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_cert +# Default: '' +# c.JupyterHub.ssl_key = '' + +## Host to send statsd metrics to. An empty string (the default) disables sending +# metrics. +# Default: '' +# c.JupyterHub.statsd_host = '' + +## Port on which to send statsd metrics about the hub +# Default: 8125 +# c.JupyterHub.statsd_port = 8125 + +## Prefix to use for all metrics sent by jupyterhub to statsd +# Default: 'jupyterhub' +# c.JupyterHub.statsd_prefix = 'jupyterhub' + +## Run single-user servers on subdomains of this host. +# +# This should be the full `https://hub.domain.tld[:port]`. +# +# Provides additional cross-site protections for javascript served by single- +# user servers. +# +# Requires `.hub.domain.tld` to resolve to the same host as +# `hub.domain.tld`. +# +# In general, this is most easily achieved with wildcard DNS. +# +# When using SSL (i.e. always) this also requires a wildcard SSL certificate. +# Default: '' +# c.JupyterHub.subdomain_host = '' + +## Paths to search for jinja templates, before using the default templates. +# Default: [] +# c.JupyterHub.template_paths = [] + +## Extra variables to be passed into jinja templates +# Default: {} +# c.JupyterHub.template_vars = {} + +## Extra settings overrides to pass to the tornado application. +# Default: {} +# c.JupyterHub.tornado_settings = {} + +## Trust user-provided tokens (via JupyterHub.service_tokens) to have good +# entropy. +# +# If you are not inserting additional tokens via configuration file, this flag +# has no effect. +# +# In JupyterHub 0.8, internally generated tokens do not pass through additional +# hashing because the hashing is costly and does not increase the entropy of +# already-good UUIDs. +# +# User-provided tokens, on the other hand, are not trusted to have good entropy +# by default, and are passed through many rounds of hashing to stretch the +# entropy of the key (i.e. user-provided tokens are treated as passwords instead +# of random keys). These keys are more costly to check. +# +# If your inserted tokens are generated by a good-quality mechanism, e.g. +# `openssl rand -hex 32`, then you can set this flag to True to reduce the cost +# of checking authentication tokens. +# Default: False +# c.JupyterHub.trust_user_provided_tokens = False + +## Names to include in the subject alternative name. +# +# These names will be used for server name verification. This is useful if +# JupyterHub is being run behind a reverse proxy or services using ssl are on +# different hosts. +# +# Use with internal_ssl +# Default: [] +# c.JupyterHub.trusted_alt_names = [] + +## Downstream proxy IP addresses to trust. +# +# This sets the list of IP addresses that are trusted and skipped when +# processing the `X-Forwarded-For` header. For example, if an external proxy is +# used for TLS termination, its IP address should be added to this list to +# ensure the correct client IP addresses are recorded in the logs instead of the +# proxy server's IP address. +# Default: [] +# c.JupyterHub.trusted_downstream_ips = [] + +## Upgrade the database automatically on start. +# +# Only safe if database is regularly backed up. Only SQLite databases will be +# backed up to a local file automatically. +# Default: False +# c.JupyterHub.upgrade_db = False + +## Callable to affect behavior of /user-redirect/ +# +# Receives 4 parameters: 1. path - URL path that was provided after /user- +# redirect/ 2. request - A Tornado HTTPServerRequest representing the current +# request. 3. user - The currently authenticated user. 4. base_url - The +# base_url of the current hub, for relative redirects +# +# It should return the new URL to redirect to, or None to preserve current +# behavior. +# Default: None +# c.JupyterHub.user_redirect_hook = None + +#------------------------------------------------------------------------------ +# Spawner(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for spawning single-user notebook servers. +# +# Subclass this, and override the following methods: +# +# - load_state - get_state - start - stop - poll +# +# As JupyterHub supports multiple users, an instance of the Spawner subclass is +# created for each user. If there are 20 JupyterHub users, there will be 20 +# instances of the subclass. + +## Extra arguments to be passed to the single-user server. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables here. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: [] +# c.Spawner.args = [] + +## An optional hook function that you can implement to pass `auth_state` to the +# spawner after it has been initialized but before it starts. The `auth_state` +# dictionary may be set by the `.authenticate()` method of the authenticator. +# This hook enables you to pass some or all of that information to your spawner. +# +# Example:: +# +# def userdata_hook(spawner, auth_state): +# spawner.userdata = auth_state["userdata"] +# +# c.Spawner.auth_state_hook = userdata_hook +# Default: None +# c.Spawner.auth_state_hook = None + +## The command used for starting the single-user server. +# +# Provide either a string or a list containing the path to the startup script +# command. Extra arguments, other than this path, should be provided via `args`. +# +# This is usually set if you want to start the single-user server in a different +# python environment (with virtualenv/conda) than JupyterHub itself. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: ['jupyterhub-singleuser'] +# c.Spawner.cmd = ['jupyterhub-singleuser'] + +## Maximum number of consecutive failures to allow before shutting down +# JupyterHub. +# +# This helps JupyterHub recover from a certain class of problem preventing +# launch in contexts where the Hub is automatically restarted (e.g. systemd, +# docker, kubernetes). +# +# A limit of 0 means no limit and consecutive failures will not be tracked. +# Default: 0 +# c.Spawner.consecutive_failure_limit = 0 + +## Minimum number of cpu-cores a single-user notebook server is guaranteed to +# have available. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_guarantee = None + +## Maximum number of cpu-cores a single-user notebook server is allowed to use. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# The single-user notebook server will never be scheduled by the kernel to use +# more cpu-cores than this. There is no guarantee that it can access this many +# cpu-cores. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_limit = None + +## Enable debug-logging of the single-user server +# Default: False +# c.Spawner.debug = False + +## The URL the single-user server should start in. +# +# `{username}` will be expanded to the user's username +# +# Example uses: +# +# - You can set `notebook_dir` to `/` and `default_url` to `/tree/home/{username}` to allow people to +# navigate the whole filesystem from their notebook server, but still start in their home directory. +# - Start with `/notebooks` instead of `/tree` if `default_url` points to a notebook instead of a directory. +# - You can set this to `/lab` to have JupyterLab start by default, rather than Jupyter Notebook. +# Default: '' +# c.Spawner.default_url = '' + +## Disable per-user configuration of single-user servers. +# +# When starting the user's single-user server, any config file found in the +# user's $HOME directory will be ignored. +# +# Note: a user could circumvent this if the user modifies their Python +# environment, such as when they have their own conda environments / virtualenvs +# / containers. +# Default: False +# c.Spawner.disable_user_config = False + +## List of environment variables for the single-user server to inherit from the +# JupyterHub process. +# +# This list is used to ensure that sensitive information in the JupyterHub +# process's environment (such as `CONFIGPROXY_AUTH_TOKEN`) is not passed to the +# single-user server's process. +# Default: ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] +# c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] + +## Extra environment variables to set for the single-user server's process. +# +# Environment variables that end up in the single-user server's process come from 3 sources: +# - This `environment` configurable +# - The JupyterHub process' environment variables that are listed in `env_keep` +# - Variables to establish contact between the single-user notebook and the hub (such as JUPYTERHUB_API_TOKEN) +# +# The `environment` configurable should be set by JupyterHub administrators to +# add installation specific environment variables. It is a dict where the key is +# the name of the environment variable, and the value can be a string or a +# callable. If it is a callable, it will be called with one parameter (the +# spawner instance), and should return a string fairly quickly (no blocking +# operations please!). +# +# Note that the spawner class' interface is not guaranteed to be exactly same +# across upgrades, so if you are using the callable take care to verify it +# continues to work after upgrades! +# +# .. versionchanged:: 1.2 +# environment from this configuration has highest priority, +# allowing override of 'default' env variables, +# such as JUPYTERHUB_API_URL. +# Default: {} +# c.Spawner.environment = {} + +## Timeout (in seconds) before giving up on a spawned HTTP server +# +# Once a server has successfully been spawned, this is the amount of time we +# wait before assuming that the server is unable to accept connections. +# Default: 30 +# c.Spawner.http_timeout = 30 + +## The IP address (or hostname) the single-user server should listen on. +# +# The JupyterHub proxy implementation should be able to send packets to this +# interface. +# Default: '' +# c.Spawner.ip = '' + +## Minimum number of bytes a single-user notebook server is guaranteed to have +# available. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_guarantee = None + +## Maximum number of bytes a single-user notebook server is allowed to use. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# If the single user server tries to allocate more memory than this, it will +# fail. There is no guarantee that the single-user notebook server will be able +# to allocate this much memory - only that it can not allocate more than this. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_limit = None + +## Path to the notebook directory for the single-user server. +# +# The user sees a file listing of this directory when the notebook interface is +# started. The current interface does not easily allow browsing beyond the +# subdirectories in this directory's tree. +# +# `~` will be expanded to the home directory of the user, and {username} will be +# replaced with the name of the user. +# +# Note that this does *not* prevent users from accessing files outside of this +# path! They can do so with many other means. +# Default: '' +# c.Spawner.notebook_dir = '' + +## An HTML form for options a user can specify on launching their server. +# +# The surrounding `` element and the submit button are already provided. +# +# For example: +# +# .. code:: html +# +# Set your key: +# +#
+# Choose a letter: +# +# +# The data from this form submission will be passed on to your spawner in +# `self.user_options` +# +# Instead of a form snippet string, this could also be a callable that takes as +# one parameter the current spawner instance and returns a string. The callable +# will be called asynchronously if it returns a future, rather than a str. Note +# that the interface of the spawner class is not deemed stable across versions, +# so using this functionality might cause your JupyterHub upgrades to break. +# Default: traitlets.Undefined +# c.Spawner.options_form = traitlets.Undefined + +## Interpret HTTP form data +# +# Form data will always arrive as a dict of lists of strings. Override this +# function to understand single-values, numbers, etc. +# +# This should coerce form data into the structure expected by self.user_options, +# which must be a dict, and should be JSON-serializeable, though it can contain +# bytes in addition to standard JSON data types. +# +# This method should not have any side effects. Any handling of `user_options` +# should be done in `.start()` to ensure consistent behavior across servers +# spawned via the API and form submission page. +# +# Instances will receive this data on self.user_options, after passing through +# this function, prior to `Spawner.start`. +# +# .. versionchanged:: 1.0 +# user_options are persisted in the JupyterHub database to be reused +# on subsequent spawns if no options are given. +# user_options is serialized to JSON as part of this persistence +# (with additional support for bytes in case of uploaded file data), +# and any non-bytes non-jsonable values will be replaced with None +# if the user_options are re-used. +# Default: traitlets.Undefined +# c.Spawner.options_from_form = traitlets.Undefined + +## Interval (in seconds) on which to poll the spawner for single-user server's +# status. +# +# At every poll interval, each spawner's `.poll` method is called, which checks +# if the single-user server is still running. If it isn't running, then +# JupyterHub modifies its own state accordingly and removes appropriate routes +# from the configurable proxy. +# Default: 30 +# c.Spawner.poll_interval = 30 + +## The port for single-user servers to listen on. +# +# Defaults to `0`, which uses a randomly allocated port number each time. +# +# If set to a non-zero value, all Spawners will use the same port, which only +# makes sense if each server is on a different address, e.g. in containers. +# +# New in version 0.7. +# Default: 0 +# c.Spawner.port = 0 + +## An optional hook function that you can implement to do work after the spawner +# stops. +# +# This can be set independent of any concrete spawner implementation. +# Default: None +# c.Spawner.post_stop_hook = None + +## An optional hook function that you can implement to do some bootstrapping work +# before the spawner starts. For example, create a directory for your user or +# load initial content. +# +# This can be set independent of any concrete spawner implementation. +# +# This maybe a coroutine. +# +# Example:: +# +# from subprocess import check_call +# def my_hook(spawner): +# username = spawner.user.name +# check_call(['./examples/bootstrap-script/bootstrap.sh', username]) +# +# c.Spawner.pre_spawn_hook = my_hook +# Default: None +# c.Spawner.pre_spawn_hook = None + +## List of SSL alt names +# +# May be set in config if all spawners should have the same value(s), or set at +# runtime by Spawner that know their names. +# Default: [] +# c.Spawner.ssl_alt_names = [] + +## Whether to include DNS:localhost, IP:127.0.0.1 in alt names +# Default: True +# c.Spawner.ssl_alt_names_include_local = True + +## Timeout (in seconds) before giving up on starting of single-user server. +# +# This is the timeout for start to return, not the timeout for the server to +# respond. Callers of spawner.start will assume that startup has failed if it +# takes longer than this. start should return when the server process is started +# and its location is known. +# Default: 60 +# c.Spawner.start_timeout = 60 + +#------------------------------------------------------------------------------ +# Authenticator(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for implementing an authentication provider for JupyterHub + +## Set of users that will have admin rights on this JupyterHub. +# +# Admin users have extra privileges: +# - Use the admin panel to see list of users logged in +# - Add / remove users in some authenticators +# - Restart / halt the hub +# - Start / stop users' single-user servers +# - Can access each individual users' single-user server (if configured) +# +# Admin access should be treated the same way root access is. +# +# Defaults to an empty set, in which case no user has admin access. +# Default: set() +# c.Authenticator.admin_users = set() + +## Set of usernames that are allowed to log in. +# +# Use this with supported authenticators to restrict which users can log in. +# This is an additional list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionchanged:: 1.2 +# `Authenticator.whitelist` renamed to `allowed_users` +# Default: set() +# c.Authenticator.allowed_users = set() + +## The max age (in seconds) of authentication info before forcing a refresh of +# user auth info. +# +# Refreshing auth info allows, e.g. requesting/re-validating auth tokens. +# +# See :meth:`.refresh_user` for what happens when user auth info is refreshed +# (nothing by default). +# Default: 300 +# c.Authenticator.auth_refresh_age = 300 + +## Automatically begin the login process +# +# rather than starting with a "Login with..." link at `/hub/login` +# +# To work, `.login_url()` must give a URL other than the default `/hub/login`, +# such as an oauth handler or another automatic login handler, registered with +# `.get_handlers()`. +# +# .. versionadded:: 0.8 +# Default: False +# c.Authenticator.auto_login = False + +## Set of usernames that are not allowed to log in. +# +# Use this with supported authenticators to restrict which users can not log in. +# This is an additional block list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionadded: 0.9 +# +# .. versionchanged:: 1.2 +# `Authenticator.blacklist` renamed to `blocked_users` +# Default: set() +# c.Authenticator.blocked_users = set() + +## Delete any users from the database that do not pass validation +# +# When JupyterHub starts, `.add_user` will be called on each user in the +# database to verify that all users are still valid. +# +# If `delete_invalid_users` is True, any users that do not pass validation will +# be deleted from the database. Use this if users might be deleted from an +# external system, such as local user accounts. +# +# If False (default), invalid users remain in the Hub's database and a warning +# will be issued. This is the default to avoid data loss due to config changes. +# Default: False +# c.Authenticator.delete_invalid_users = False + +## Enable persisting auth_state (if available). +# +# auth_state will be encrypted and stored in the Hub's database. This can +# include things like authentication tokens, etc. to be passed to Spawners as +# environment variables. +# +# Encrypting auth_state requires the cryptography package. +# +# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one +# (or more, separated by ;) 32B encryption keys. These can be either base64 or +# hex-encoded. +# +# If encryption is unavailable, auth_state cannot be persisted. +# +# New in JupyterHub 0.8 +# Default: False +# c.Authenticator.enable_auth_state = False + +## An optional hook function that you can implement to do some bootstrapping work +# during authentication. For example, loading user account details from an +# external system. +# +# This function is called after the user has passed all authentication checks +# and is ready to successfully authenticate. This function must return the +# authentication dict reguardless of changes to it. +# +# This maybe a coroutine. +# +# .. versionadded: 1.0 +# +# Example:: +# +# import os, pwd +# def my_hook(authenticator, handler, authentication): +# user_data = pwd.getpwnam(authentication['name']) +# spawn_data = { +# 'pw_data': user_data +# 'gid_list': os.getgrouplist(authentication['name'], user_data.pw_gid) +# } +# +# if authentication['auth_state'] is None: +# authentication['auth_state'] = {} +# authentication['auth_state']['spawn_data'] = spawn_data +# +# return authentication +# +# c.Authenticator.post_auth_hook = my_hook +# Default: None +# c.Authenticator.post_auth_hook = None + +## Force refresh of auth prior to spawn. +# +# This forces :meth:`.refresh_user` to be called prior to launching a server, to +# ensure that auth state is up-to-date. +# +# This can be important when e.g. auth tokens that may have expired are passed +# to the spawner via environment variables from auth_state. +# +# If refresh_user cannot refresh the user auth data, launch will fail until the +# user logs in again. +# Default: False +# c.Authenticator.refresh_pre_spawn = False + +## Dictionary mapping authenticator usernames to JupyterHub users. +# +# Primarily used to normalize OAuth user names to local users. +# Default: {} +# c.Authenticator.username_map = {} + +## Regular expression pattern that all valid usernames must match. +# +# If a username does not match the pattern specified here, authentication will +# not be attempted. +# +# If not set, allow any username. +# Default: '' +# c.Authenticator.username_pattern = '' + +## Deprecated, use `Authenticator.allowed_users` +# Default: set() +# c.Authenticator.whitelist = set() + +#------------------------------------------------------------------------------ +# CryptKeeper(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## Encapsulate encryption configuration +# +# Use via the encryption_config singleton below. + +# Default: [] +# c.CryptKeeper.keys = [] + +## The number of threads to allocate for encryption +# Default: 4 +# c.CryptKeeper.n_threads = 4 + +#------------------------------------------------------------------------------ +# Pagination(Configurable) configuration +#------------------------------------------------------------------------------ +## Default number of entries per page for paginated results. +# Default: 100 +# c.Pagination.default_per_page = 100 + +## Maximum number of entries per page for paginated results. +# Default: 250 +# c.Pagination.max_per_page = 250 diff --git a/roles/network/templates/gateway/iiab-gen-iptables b/roles/network/templates/gateway/iiab-gen-iptables index 1175157af..f6d69d252 100755 --- a/roles/network/templates/gateway/iiab-gen-iptables +++ b/roles/network/templates/gateway/iiab-gen-iptables @@ -73,6 +73,7 @@ pbx_data_ports={{ pbx_data_ports }} sugarizer_port={{ sugarizer_port }} transmission_http_port={{ transmission_http_port }} transmission_peer_port={{ transmission_peer_port }} +jupyterhub_port={{ jupyterhub_port }} samba_udp_ports={{ samba_udp_ports }} samba_tcp_mports={{ samba_tcp_mports }} @@ -159,7 +160,8 @@ if [ "$wan" != "none" ]; then $IPTABLES -A INPUT -p tcp --dport $sugarizer_port -m state --state NEW -i $wan -j ACCEPT $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT - $IPTABLES -A INPUT -p tcp --dport $transmission_peer_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $jupyterhub_port -m state --state NEW -i $wan -j ACCEPT fi # 4 = ssh + http-or-https + common IIAB services + Samba From 6a2283bef83b1529992528809209e5b8b58d398d Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:10:49 +0000 Subject: [PATCH 31/62] systemd spawner is working writing to /var/lib/private --- roles/jupyter/tasks/install.yml | 17 +++++++++++++++-- roles/jupyter/templates/jupyter.service | 2 +- roles/jupyter/templates/jupyterhub_config.py | 13 ++++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 0c2526856..353f78cae 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,4 +1,9 @@ -- name: Make the directories to hold notebooks +- name: We need a non-privileged user to write all the notebooks + ansible.builtin.user: + name: web-user + home: /opt/iiab/notebooks + +- name: Make the directories to hold jupyter config file: state: directory path: '{{ item }}' @@ -7,6 +12,12 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' +- name: Make a directory to hold notebooks + file: + state: directory + path: /opt/iiab/notebooks + owner: web-user + - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -35,6 +46,8 @@ - ipywidgets - jupyterhub - jupyterlab + - jupyterhub_firstuseauthenticator + - jupyterhub-systemdspawner virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -45,7 +58,7 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/env/jupyterhub/' + dest: '{{ jupyter_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 363390a9f..f9e5aa798 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -3,7 +3,7 @@ Description=JupyterHub After=syslog.target network.target [Service] -User=hubuser +User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 00c70a126..71d81dbb9 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -114,7 +114,7 @@ # - dummy: jupyterhub.auth.DummyAuthenticator # - pam: jupyterhub.auth.PAMAuthenticator # Default: 'jupyterhub.auth.PAMAuthenticator' -# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' +c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' ## The base URL of the entire application. # @@ -194,7 +194,7 @@ # # Should be exactly 256 bits (32 bytes). # Default: b'' -# c.JupyterHub.cookie_secret = b'' +c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## File in which to store the cookie secret. # Default: 'jupyterhub_cookie_secret' @@ -589,7 +589,7 @@ # - localprocess: jupyterhub.spawner.LocalProcessSpawner # - simple: jupyterhub.spawner.SimpleLocalProcessSpawner # Default: 'jupyterhub.spawner.LocalProcessSpawner' -# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' +c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## Path to SSL certificate file for the public facing interface of the proxy # @@ -1229,3 +1229,10 @@ ## Maximum number of entries per page for paginated results. # Default: 250 # c.Pagination.max_per_page = 250 + +#------------------------------------------------------------------------------ +# Systemdspawner config +#------------------------------------------------------------------------------ +c.SystemdSpawner.dynamic_users = True +c.SystemdSpawner.user_workingdir = '/opt/iiab/notebooks/{USERNAME}' + From 8ac48e150f953696d8af749ba276c9c1a9cb4857 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:19:17 +0000 Subject: [PATCH 32/62] change systemd to more specifially use the venv --- roles/jupyter/templates/jupyter.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index f9e5aa798..8ce535369 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -5,7 +5,7 @@ After=syslog.target network.target [Service] User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target From 9a05f01142d8fa2838e4717f985738b3a9032477 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:33:47 +0000 Subject: [PATCH 33/62] add iiab-admin to the authentication list --- roles/jupyter/templates/jupyterhub_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 71d81dbb9..999715a8f 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() -# c.Authenticator.admin_users = set() + c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From 3896a017a02d23839c0a051bc1ffff86bd7b2dd2 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 05:15:15 +0000 Subject: [PATCH 34/62] remove creation of notebook, spawner puts in /var/lib/private --- roles/jupyter/tasks/enable-or-disable.yml | 16 ++++++++++++++++ roles/jupyter/tasks/install.yml | 12 +----------- roles/jupyter/templates/jupyterhub_config.py | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml index ad8bb17ad..becab8e9a 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -23,3 +23,19 @@ when: not jupyter_enabled +- name: Put the nginx config file in place + template: + src: jupyter-nginx.conf + dest: "{{ nginx_conf_dir }}/" + when: jupyter_enabled + +- name: Disable jupyterhub + file: + path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + state: absent + when: not jupyter_enabled + +- name: Restart 'nginx' systemd service + systemd: + name: nginx + state: restarted diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 353f78cae..6901db83d 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,8 +1,3 @@ -- name: We need a non-privileged user to write all the notebooks - ansible.builtin.user: - name: web-user - home: /opt/iiab/notebooks - - name: Make the directories to hold jupyter config file: state: directory @@ -12,12 +7,6 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' -- name: Make a directory to hold notebooks - file: - state: directory - path: /opt/iiab/notebooks - owner: web-user - - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -59,6 +48,7 @@ template: src: jupyterhub_config.py dest: '{{ jupyter_venv }}/etc/jupyterhub/' + - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 999715a8f..cd0999ca1 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() - c.Authenticator.admin_users = set('iiab-admin') +c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From dd1c0c7ac26101abfa1d144e4c325eeabde906ea Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 17:35:48 +0000 Subject: [PATCH 35/62] getting nginx proxy to work /jupyterhub --- roles/jupyter/templates/jupyter-nginx.conf | 20 ++++++++++++++++++++ roles/jupyter/templates/jupyterhub_config.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 roles/jupyter/templates/jupyter-nginx.conf diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyter/templates/jupyter-nginx.conf new file mode 100644 index 000000000..a9d450c10 --- /dev/null +++ b/roles/jupyter/templates/jupyter-nginx.conf @@ -0,0 +1,20 @@ +location /jupyterhub { + proxy_pass http://127.0.0.1:8000; + proxy_set_header X-Real-IP $remote_addr; + #proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; + + + # websocket headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + #proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Scheme $scheme; + + proxy_buffering off; + } + # Managing requests to verify letsencrypt host + location ~ /.well-known { + allow all; + } diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index cd0999ca1..ade964254 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/' +# c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From b5a3c44d57df606bb4eb72c5fdd2341d3531352f Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 05:07:56 +0000 Subject: [PATCH 36/62] add in README.md --- roles/jupyter/docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 roles/jupyter/docs/README.md diff --git a/roles/jupyter/docs/README.md b/roles/jupyter/docs/README.md new file mode 100644 index 000000000..2878ebaa6 --- /dev/null +++ b/roles/jupyter/docs/README.md @@ -0,0 +1,6 @@ +### Jupyter Notebooks on Rpi Server +* Jupyter Notebooks are widely used in the scientific community. +* This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. +* Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. +* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. +* Students will not have any priviletes outside of their own folder. From 84d67ae6ba324bdfb472dc1b6fefb43d64e216c4 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:24:05 +0000 Subject: [PATCH 37/62] remove the jupyter<->jupyterhub conflict. Make all jupyterhub --- roles/{jupyter => jupyterhub}/defaults/main.yml | 2 +- roles/{jupyter => jupyterhub}/docs/README.md | 0 .../tasks/enable-or-disable.yml | 16 ++++++++-------- roles/{jupyter => jupyterhub}/tasks/install.yml | 12 ++++++------ roles/{jupyter => jupyterhub}/tasks/main.yml | 8 ++++---- .../templates/jupyterhub-nginx.conf} | 0 .../templates/jupyterhub.service} | 4 ++-- .../templates/jupyterhub_config.py | 0 vars/default_vars.yml | 4 ++-- 9 files changed, 23 insertions(+), 23 deletions(-) rename roles/{jupyter => jupyterhub}/defaults/main.yml (77%) rename roles/{jupyter => jupyterhub}/docs/README.md (100%) rename roles/{jupyter => jupyterhub}/tasks/enable-or-disable.yml (69%) rename roles/{jupyter => jupyterhub}/tasks/install.yml (81%) rename roles/{jupyter => jupyterhub}/tasks/main.yml (66%) rename roles/{jupyter/templates/jupyter-nginx.conf => jupyterhub/templates/jupyterhub-nginx.conf} (100%) rename roles/{jupyter/templates/jupyter.service => jupyterhub/templates/jupyterhub.service} (54%) rename roles/{jupyter => jupyterhub}/templates/jupyterhub_config.py (100%) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyterhub/defaults/main.yml similarity index 77% rename from roles/jupyter/defaults/main.yml rename to roles/jupyterhub/defaults/main.yml index b22730df0..d4231ae72 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,4 @@ notebook_dir: /opt/iiab/notebook -jupyter_venv: /opt/iiab/jupyter +jupyterhub_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub jupyterhub_port: 8000 diff --git a/roles/jupyter/docs/README.md b/roles/jupyterhub/docs/README.md similarity index 100% rename from roles/jupyter/docs/README.md rename to roles/jupyterhub/docs/README.md diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyterhub/tasks/enable-or-disable.yml similarity index 69% rename from roles/jupyter/tasks/enable-or-disable.yml rename to roles/jupyterhub/tasks/enable-or-disable.yml index becab8e9a..aacd9a35d 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyterhub/tasks/enable-or-disable.yml @@ -10,8 +10,8 @@ enabled: yes state: restarted with_items: - - jupyter - when: jupyter_enabled + - jupyterhub.service + when: jupyterhub_enabled - name: Disable jupyterhub systemd: @@ -19,21 +19,21 @@ enabled: no state: stopped with_items: - - jupyter - when: not jupyter_enabled + - jupyterhub + when: not jupyterhub_enabled - name: Put the nginx config file in place template: - src: jupyter-nginx.conf + src: jupyterhub-nginx.conf dest: "{{ nginx_conf_dir }}/" - when: jupyter_enabled + when: jupyterhub_enabled - name: Disable jupyterhub file: - path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + path: "{{ nginx_conf_dir }}/jupyterhub-nginx.conf" state: absent - when: not jupyter_enabled + when: not jupyterhub_enabled - name: Restart 'nginx' systemd service systemd: diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyterhub/tasks/install.yml similarity index 81% rename from roles/jupyter/tasks/install.yml rename to roles/jupyterhub/tasks/install.yml index 6901db83d..baae04456 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyterhub/tasks/install.yml @@ -3,9 +3,9 @@ state: directory path: '{{ item }}' with_items: - - '{{ jupyter_venv }}/etc/jupyter' - - '{{ jupyter_venv }}/etc/jupyterhub' - - '{{ jupyter_venv }}/etc/systemd' + - '{{ jupyterhub_venv }}/etc/jupyter' + - '{{ jupyterhub_venv }}/etc/jupyterhub' + - '{{ jupyterhub_venv }}/etc/systemd' - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: @@ -37,7 +37,7 @@ - jupyterlab - jupyterhub_firstuseauthenticator - jupyterhub-systemdspawner - virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv virtualenv_python: python3 @@ -47,9 +47,9 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/etc/jupyterhub/' + dest: '{{ jupyterhub_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: - src: jupyter.service + src: jupyterhub.service dest: /etc/systemd/system/ diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyterhub/tasks/main.yml similarity index 66% rename from roles/jupyter/tasks/main.yml rename to roles/jupyterhub/tasks/main.yml index 137a01b84..9090610a0 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -1,6 +1,6 @@ -- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml +- name: Install Jupyter if jupyterhub_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml include_tasks: install.yml - when: jupyter_installed is undefined + when: jupyterhub_installed is undefined - include_tasks: enable-or-disable.yml @@ -18,6 +18,6 @@ - option: description value: '"Raspberry Pi Jupyter python programming environment"' - option: install - value: "{{ jupyter_install }}" + value: "{{ jupyterhub_install }}" - option: enabled - value: "{{ jupyter_enabled }}" + value: "{{ jupyterhub_enabled }}" diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf similarity index 100% rename from roles/jupyter/templates/jupyter-nginx.conf rename to roles/jupyterhub/templates/jupyterhub-nginx.conf diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyterhub/templates/jupyterhub.service similarity index 54% rename from roles/jupyter/templates/jupyter.service rename to roles/jupyterhub/templates/jupyterhub.service index 8ce535369..3137d0404 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyterhub/templates/jupyterhub.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=root -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyterhub_venv }}/bin" +ExecStart={{ jupyterhub_venv }}/bin/python3 -m jupyterhub -f {{ jupyterhub_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py similarity index 100% rename from roles/jupyter/templates/jupyterhub_config.py rename to roles/jupyterhub/templates/jupyterhub_config.py diff --git a/vars/default_vars.yml b/vars/default_vars.yml index d1fb036e1..c932b98a6 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -564,8 +564,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False -jupyter_install: False -jupyter_enabled: False +jupyterhub_install: False +jupyterhub_enabled: False # 9-LOCAL-ADDONS From 9cd837cea5fcf6c100836ba525961c01ccf09612 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:35:27 +0000 Subject: [PATCH 38/62] remaining jupyter->jupyterhub items --- roles/jupyterhub/defaults/main.yml | 4 +--- roles/jupyterhub/templates/jupyterhub_config.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/roles/jupyterhub/defaults/main.yml b/roles/jupyterhub/defaults/main.yml index d4231ae72..a859f9946 100644 --- a/roles/jupyterhub/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,2 @@ -notebook_dir: /opt/iiab/notebook -jupyterhub_venv: /opt/iiab/jupyter -jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_venv: /opt/iiab/jupyterhub jupyterhub_port: 8000 diff --git a/roles/jupyterhub/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py index ade964254..2eba8b290 100644 --- a/roles/jupyterhub/templates/jupyterhub_config.py +++ b/roles/jupyterhub/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/jupyterhub' +c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From 613d08f499c58e52731aef6542e66921d1beb40b Mon Sep 17 00:00:00 2001 From: George Hunt Date: Mon, 8 Mar 2021 01:57:10 +0000 Subject: [PATCH 39/62] venv runs without jupyterlab-vim --- roles/jupyter/defaults/main.yml | 2 ++ roles/jupyter/tasks/install.yml | 17 +++++++++++++++++ roles/jupyter/tasks/main.yml | 23 +++++++++++++++++++++++ vars/default_vars.yml | 4 ++-- 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 roles/jupyter/defaults/main.yml create mode 100644 roles/jupyter/tasks/install.yml create mode 100644 roles/jupyter/tasks/main.yml diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml new file mode 100644 index 000000000..017b0de30 --- /dev/null +++ b/roles/jupyter/defaults/main.yml @@ -0,0 +1,2 @@ +notebook_dir: /opt/iiab/notebook +jupyter_venv: /opt/iiab/jupyter diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml new file mode 100644 index 000000000..3330ba743 --- /dev/null +++ b/roles/jupyter/tasks/install.yml @@ -0,0 +1,17 @@ +- name: Make the directories to hold notebooks + file: + state: directory + path: '{{ notebook_dir }}' + +- name: Use pip to install into a virtual environment + pip: + name: + - jupyterlab + #- jupyter_vim + virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter + virtualenv_site_packages: no + virtualenv_command: /usr/bin/virtualenv + virtualenv_python: python3 + extra_args: "--no-cache-dir" + when: internet_available + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml new file mode 100644 index 000000000..9f1804b38 --- /dev/null +++ b/roles/jupyter/tasks/main.yml @@ -0,0 +1,23 @@ +- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml + include_tasks: install.yml + when: jupyter_installed is undefined + + +#- include_tasks: enable-or-disable.yml + + +- name: Add 'jupyter' variable values to {{ iiab_ini_file }} + ini_file: + path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini + section: jupyter + option: "{{ item.option }}" + value: "{{ item.value | string }}" + with_items: + - option: name + value: Jupyter + - option: description + value: '"Raspberry Pi Jupyter python programming environment"' + - option: install + value: "{{ jupyter_install }}" + - option: enabled + value: "{{ jupyter_enabled }}" diff --git a/vars/default_vars.yml b/vars/default_vars.yml index c932b98a6..d1fb036e1 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -564,8 +564,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False -jupyterhub_install: False -jupyterhub_enabled: False +jupyter_install: False +jupyter_enabled: False # 9-LOCAL-ADDONS From b008147640009918ea15abe903ed5d34c7850bcd Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 04:57:33 +0000 Subject: [PATCH 40/62] Found instructions for the Littlest Jupyterhub --- roles/jupyter/tasks/enable-or-disable.yml | 25 +++++++++++++++++++++++ roles/jupyter/tasks/install.yml | 19 ++++++++++++++--- roles/jupyter/tasks/main.yml | 2 +- roles/jupyter/templates/jupyter.service | 11 ++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 roles/jupyter/tasks/enable-or-disable.yml create mode 100644 roles/jupyter/templates/jupyter.service diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml new file mode 100644 index 000000000..ad8bb17ad --- /dev/null +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -0,0 +1,25 @@ +- name: systemd daemon-reload + systemd: + daemon_reload: yes + + +# enable or disable +- name: Enable & Restart jupyterhub + systemd: + name: "{{ item }}" + enabled: yes + state: restarted + with_items: + - jupyter + when: jupyter_enabled + +- name: Disable jupyterhub + systemd: + name: "{{ item }}" + enabled: no + state: stopped + with_items: + - jupyter + when: not jupyter_enabled + + diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 3330ba743..4e2981584 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,13 +1,16 @@ - name: Make the directories to hold notebooks file: state: directory - path: '{{ notebook_dir }}' + path: '{{ item }}' + with_items: + - '{{ notebook_dir }}/etc/jupyter' + - '{{ notebook_dir }}/etc/jupyterhub' + - '{{ notebook_dir }}/etc/systemd' - name: Use pip to install into a virtual environment pip: name: - - jupyterlab - #- jupyter_vim + - pip virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -15,3 +18,13 @@ extra_args: "--no-cache-dir" when: internet_available +- name: Fetch the Littlest JupyterHub code + ansible.builtin.git: + repo: '{{ jupyterhub_url }} + dest: '{{ jupyter_venv }}' + +- name: Install a bootstrap.py that permits installation on other than Ubunt + template: + src: bootstrap.py + dest: '{{ jupyter_venv }}' + diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml index 9f1804b38..137a01b84 100644 --- a/roles/jupyter/tasks/main.yml +++ b/roles/jupyter/tasks/main.yml @@ -3,7 +3,7 @@ when: jupyter_installed is undefined -#- include_tasks: enable-or-disable.yml +- include_tasks: enable-or-disable.yml - name: Add 'jupyter' variable values to {{ iiab_ini_file }} diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service new file mode 100644 index 000000000..81cee0dd2 --- /dev/null +++ b/roles/jupyter/templates/jupyter.service @@ -0,0 +1,11 @@ +[Unit] +Description=JupyterHub +After=syslog.target network.target + +[Service] +User=hubuser +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" +ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py + +[Install] +WantedBy=multi-user.target From 617c716ee860531b63106cdaea7974e7d4cafc7b Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 19:56:46 +0000 Subject: [PATCH 41/62] changes to venv --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index 017b0de30..c879b76ac 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,2 +1,3 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter +jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 4e2981584..b311464b6 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -11,6 +11,8 @@ pip: name: - pip + - wheel + - ipywidgets virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv From ce3e4247f21a182a9d6b56526181e8f963e7fa8e Mon Sep 17 00:00:00 2001 From: George Hunt Date: Tue, 9 Mar 2021 22:57:39 +0000 Subject: [PATCH 42/62] displayed the ted notebook on raspi-os --- roles/jupyter/defaults/main.yml | 1 + roles/jupyter/tasks/install.yml | 44 +- roles/jupyter/templates/jupyter.service | 4 +- roles/jupyter/templates/jupyterhub_config.py | 1231 ++++++++++++++++++ 4 files changed, 1266 insertions(+), 14 deletions(-) create mode 100644 roles/jupyter/templates/jupyterhub_config.py diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml index c879b76ac..b22730df0 100644 --- a/roles/jupyter/defaults/main.yml +++ b/roles/jupyter/defaults/main.yml @@ -1,3 +1,4 @@ notebook_dir: /opt/iiab/notebook jupyter_venv: /opt/iiab/jupyter jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_port: 8000 diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index b311464b6..0c2526856 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -3,9 +3,29 @@ state: directory path: '{{ item }}' with_items: - - '{{ notebook_dir }}/etc/jupyter' - - '{{ notebook_dir }}/etc/jupyterhub' - - '{{ notebook_dir }}/etc/systemd' + - '{{ jupyter_venv }}/etc/jupyter' + - '{{ jupyter_venv }}/etc/jupyterhub' + - '{{ jupyter_venv }}/etc/systemd' + +- name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" + set_fact: + nodejs_install: True + nodejs_enabled: True + +- name: NODEJS - run 'nodejs' role (attempt to install & enable Node.js) + include_role: + name: nodejs + +- name: FAIL (STOP THE INSTALL) IF 'nodejs_installed is undefined' + fail: + msg: "Jupyter install cannot proceed, as Node.js is not installed." + when: nodejs_installed is undefined + +- name: use npm to install configurable http proxy + npm: + name: configurable-http-proxy + global: yes + state: latest - name: Use pip to install into a virtual environment pip: @@ -13,6 +33,8 @@ - pip - wheel - ipywidgets + - jupyterhub + - jupyterlab virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -20,13 +42,11 @@ extra_args: "--no-cache-dir" when: internet_available -- name: Fetch the Littlest JupyterHub code - ansible.builtin.git: - repo: '{{ jupyterhub_url }} - dest: '{{ jupyter_venv }}' - -- name: Install a bootstrap.py that permits installation on other than Ubunt +- name: Install the config file for jupyterhub template: - src: bootstrap.py - dest: '{{ jupyter_venv }}' - + src: jupyterhub_config.py + dest: '{{ jupyter_venv }}/env/jupyterhub/' +- name: Use systemd to start jupyterhub + template: + src: jupyter.service + dest: /etc/systemd/system/ diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 81cee0dd2..363390a9f 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -4,8 +4,8 @@ After=syslog.target network.target [Service] User=hubuser -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/iiab/jupyterhub/bin" -ExecStart=/opt/iiab/jupyterhub/bin/jupyterhub -f /opt/iiab/jupyterhub/etc/jupyterhub/jupyterhub_config.py +Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" +ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py new file mode 100644 index 000000000..00c70a126 --- /dev/null +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -0,0 +1,1231 @@ +# Configuration file for jupyterhub. + +#------------------------------------------------------------------------------ +# Application(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## This is an application. + +## The date format used by logging formatters for %(asctime)s +# Default: '%Y-%m-%d %H:%M:%S' +# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# Default: '[%(name)s]%(highlevel)s %(message)s' +# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] +# Default: 30 +# c.Application.log_level = 30 + +## Instead of starting the Application, dump configuration to stdout +# Default: False +# c.Application.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# Default: False +# c.Application.show_config_json = False + +#------------------------------------------------------------------------------ +# JupyterHub(Application) configuration +#------------------------------------------------------------------------------ +## An Application for starting a Multi-User Jupyter Notebook server. + +## Maximum number of concurrent servers that can be active at a time. +# +# Setting this can limit the total resources your users can consume. +# +# An active server is any server that's not fully stopped. It is considered +# active from the time it has been requested until the time that it has +# completely stopped. +# +# If this many user servers are active, users will not be able to launch new +# servers until a server is shutdown. Spawn requests will be rejected with a 429 +# error asking them to try again. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.active_server_limit = 0 + +## Duration (in seconds) to determine the number of active users. +# Default: 1800 +# c.JupyterHub.active_user_window = 1800 + +## Resolution (in seconds) for updating activity +# +# If activity is registered that is less than activity_resolution seconds more +# recent than the current value, the new value will be ignored. +# +# This avoids too many writes to the Hub database. +# Default: 30 +# c.JupyterHub.activity_resolution = 30 + +## Grant admin users permission to access single-user servers. +# +# Users should be properly informed if this is enabled. +# Default: False +# c.JupyterHub.admin_access = False + +## DEPRECATED since version 0.7.2, use Authenticator.admin_users instead. +# Default: set() +# c.JupyterHub.admin_users = set() + +## Allow named single-user servers per user +# Default: False +# c.JupyterHub.allow_named_servers = False + +## Answer yes to any questions (e.g. confirm overwrite) +# Default: False +# c.JupyterHub.answer_yes = False + +## PENDING DEPRECATION: consider using services +# +# Dict of token:username to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services, which authenticate as JupyterHub users. +# +# Consider using services for general services that talk to the JupyterHub API. +# Default: {} +# c.JupyterHub.api_tokens = {} + +## Authentication for prometheus metrics +# Default: True +# c.JupyterHub.authenticate_prometheus = True + +## Class for authenticating users. +# +# This should be a subclass of :class:`jupyterhub.auth.Authenticator` +# +# with an :meth:`authenticate` method that: +# +# - is a coroutine (asyncio or tornado) +# - returns username on success, None on failure +# - takes two arguments: (handler, data), +# where `handler` is the calling web.RequestHandler, +# and `data` is the POST form data from the login page. +# +# .. versionchanged:: 1.0 +# authenticators may be registered via entry points, +# e.g. `c.JupyterHub.authenticator_class = 'pam'` +# +# Currently installed: +# - default: jupyterhub.auth.PAMAuthenticator +# - dummy: jupyterhub.auth.DummyAuthenticator +# - pam: jupyterhub.auth.PAMAuthenticator +# Default: 'jupyterhub.auth.PAMAuthenticator' +# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' + +## The base URL of the entire application. +# +# Add this to the beginning of all JupyterHub URLs. Use base_url to run +# JupyterHub within an existing website. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '/' +# c.JupyterHub.base_url = '/' + +## The public facing URL of the whole JupyterHub application. +# +# This is the address on which the proxy will bind. Sets protocol, ip, base_url +# Default: 'http://:8000' +# c.JupyterHub.bind_url = 'http://:8000' + +## Whether to shutdown the proxy when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the proxy +# running. +# +# Only valid if the proxy was starting by the Hub process. +# +# If both this and cleanup_servers are False, sending SIGINT to the Hub will +# only shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_proxy = True + +## Whether to shutdown single-user servers when the Hub shuts down. +# +# Disable if you want to be able to teardown the Hub while leaving the single- +# user servers running. +# +# If both this and cleanup_proxy are False, sending SIGINT to the Hub will only +# shutdown the Hub, leaving everything else running. +# +# The Hub should be able to resume from database state. +# Default: True +# c.JupyterHub.cleanup_servers = True + +## Maximum number of concurrent users that can be spawning at a time. +# +# Spawning lots of servers at the same time can cause performance problems for +# the Hub or the underlying spawning system. Set this limit to prevent bursts of +# logins from attempting to spawn too many servers at the same time. +# +# This does not limit the number of total running servers. See +# active_server_limit for that. +# +# If more than this many users attempt to spawn at a time, their requests will +# be rejected with a 429 error asking them to try again. Users will have to wait +# for some of the spawning services to finish starting before they can start +# their own. +# +# If set to 0, no limit is enforced. +# Default: 100 +# c.JupyterHub.concurrent_spawn_limit = 100 + +## The config file to load +# Default: 'jupyterhub_config.py' +# c.JupyterHub.config_file = 'jupyterhub_config.py' + +## DEPRECATED: does nothing +# Default: False +# c.JupyterHub.confirm_no_ssl = False + +## Number of days for a login cookie to be valid. Default is two weeks. +# Default: 14 +# c.JupyterHub.cookie_max_age_days = 14 + +## The cookie secret to use to encrypt cookies. +# +# Loaded from the JPY_COOKIE_SECRET env variable by default. +# +# Should be exactly 256 bits (32 bytes). +# Default: b'' +# c.JupyterHub.cookie_secret = b'' + +## File in which to store the cookie secret. +# Default: 'jupyterhub_cookie_secret' +# c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' + +## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) +# Default: '/opt/iiab/jupyter/share/jupyterhub' +# c.JupyterHub.data_files_path = '/opt/iiab/jupyter/share/jupyterhub' + +## Include any kwargs to pass to the database connection. See +# sqlalchemy.create_engine for details. +# Default: {} +# c.JupyterHub.db_kwargs = {} + +## url for the database. e.g. `sqlite:///jupyterhub.sqlite` +# Default: 'sqlite:///jupyterhub.sqlite' +# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' + +## log all database transactions. This has A LOT of output +# Default: False +# c.JupyterHub.debug_db = False + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.debug +# Default: False +# c.JupyterHub.debug_proxy = False + +## If named servers are enabled, default name of server to spawn or open, e.g. by +# user-redirect. +# Default: '' +# c.JupyterHub.default_server_name = '' + +## The default URL for users when they arrive (e.g. when user directs to "/") +# +# By default, redirects users to their own server. +# +# Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler +# object: +# +# :: +# +# def default_url_fn(handler): +# user = handler.current_user +# if user and user.admin: +# return '/hub/admin' +# return '/hub/home' +# +# c.JupyterHub.default_url = default_url_fn +# Default: traitlets.Undefined +# c.JupyterHub.default_url = traitlets.Undefined + +## Dict authority:dict(files). Specify the key, cert, and/or ca file for an +# authority. This is useful for externally managed proxies that wish to use +# internal_ssl. +# +# The files dict has this format (you must specify at least a cert):: +# +# { +# 'key': '/path/to/key.key', +# 'cert': '/path/to/cert.crt', +# 'ca': '/path/to/ca.crt' +# } +# +# The authorities you can override: 'hub-ca', 'notebooks-ca', 'proxy-api-ca', +# 'proxy-client-ca', and 'services-ca'. +# +# Use with internal_ssl +# Default: {} +# c.JupyterHub.external_ssl_authorities = {} + +## Register extra tornado Handlers for jupyterhub. +# +# Should be of the form ``("", Handler)`` +# +# The Hub prefix will be added, so `/my-page` will be served at `/hub/my-page`. +# Default: [] +# c.JupyterHub.extra_handlers = [] + +## DEPRECATED: use output redirection instead, e.g. +# +# jupyterhub &>> /var/log/jupyterhub.log +# Default: '' +# c.JupyterHub.extra_log_file = '' + +## Extra log handlers to set on JupyterHub logger +# Default: [] +# c.JupyterHub.extra_log_handlers = [] + +## Generate certs used for internal ssl +# Default: False +# c.JupyterHub.generate_certs = False + +## Generate default config file +# Default: False +# c.JupyterHub.generate_config = False + +## The URL on which the Hub will listen. This is a private URL for internal +# communication. Typically set in combination with hub_connect_url. If a unix +# socket, hub_connect_url **must** also be set. +# +# For example: +# +# "http://127.0.0.1:8081" +# "unix+http://%2Fsrv%2Fjupyterhub%2Fjupyterhub.sock" +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_bind_url = '' + +## The ip or hostname for proxies and spawners to use for connecting to the Hub. +# +# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different +# from the connect address. +# +# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, otherwise +# use `hub_ip`. +# +# Note: Some spawners or proxy implementations might not support hostnames. +# Check your spawner or proxy documentation to see if they have extra +# requirements. +# +# .. versionadded:: 0.8 +# Default: '' +# c.JupyterHub.hub_connect_ip = '' + +## DEPRECATED +# +# Use hub_connect_url +# +# .. versionadded:: 0.8 +# +# .. deprecated:: 0.9 +# Use hub_connect_url +# Default: 0 +# c.JupyterHub.hub_connect_port = 0 + +## The URL for connecting to the Hub. Spawners, services, and the proxy will use +# this URL to talk to the Hub. +# +# Only needs to be specified if the default hub URL is not connectable (e.g. +# using a unix+http:// bind url). +# +# .. seealso:: +# JupyterHub.hub_connect_ip +# JupyterHub.hub_bind_url +# +# .. versionadded:: 0.9 +# Default: '' +# c.JupyterHub.hub_connect_url = '' + +## The ip address for the Hub process to *bind* to. +# +# By default, the hub listens on localhost only. This address must be accessible +# from the proxy and user servers. You may need to set this to a public ip or '' +# for all interfaces if the proxy or user servers are in containers or on a +# different host. +# +# See `hub_connect_ip` for cases where the bind and connect address should +# differ, or `hub_bind_url` for setting the full bind URL. +# Default: '127.0.0.1' +# c.JupyterHub.hub_ip = '127.0.0.1' + +## The internal port for the Hub process. +# +# This is the internal port of the hub itself. It should never be accessed +# directly. See JupyterHub.port for the public port to use when accessing +# jupyterhub. It is rare that this port should be set except in cases of port +# conflict. +# +# See also `hub_ip` for the ip and `hub_bind_url` for setting the full bind URL. +# Default: 8081 +# c.JupyterHub.hub_port = 8081 + +## Trigger implicit spawns after this many seconds. +# +# When a user visits a URL for a server that's not running, they are shown a +# page indicating that the requested server is not running with a button to +# spawn the server. +# +# Setting this to a positive value will redirect the user after this many +# seconds, effectively clicking this button automatically for the users, +# automatically beginning the spawn process. +# +# Warning: this can result in errors and surprising behavior when sharing access +# URLs to actual servers, since the wrong server is likely to be started. +# Default: 0 +# c.JupyterHub.implicit_spawn_seconds = 0 + +## Timeout (in seconds) to wait for spawners to initialize +# +# Checking if spawners are healthy can take a long time if many spawners are +# active at hub start time. +# +# If it takes longer than this timeout to check, init_spawner will be left to +# complete in the background and the http server is allowed to start. +# +# A timeout of -1 means wait forever, which can mean a slow startup of the Hub +# but ensures that the Hub is fully consistent by the time it starts responding +# to requests. This matches the behavior of jupyterhub 1.0. +# +# .. versionadded: 1.1.0 +# Default: 10 +# c.JupyterHub.init_spawners_timeout = 10 + +## The location to store certificates automatically created by JupyterHub. +# +# Use with internal_ssl +# Default: 'internal-ssl' +# c.JupyterHub.internal_certs_location = 'internal-ssl' + +## Enable SSL for all internal communication +# +# This enables end-to-end encryption between all JupyterHub components. +# JupyterHub will automatically create the necessary certificate authority and +# sign notebook certificates as they're created. +# Default: False +# c.JupyterHub.internal_ssl = False + +## The public facing ip of the whole JupyterHub application (specifically +# referred to as the proxy). +# +# This is the address on which the proxy will listen. The default is to listen +# on all interfaces. This is the only address through which JupyterHub should be +# accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: '' +# c.JupyterHub.ip = '' + +## Supply extra arguments that will be passed to Jinja environment. +# Default: {} +# c.JupyterHub.jinja_environment_options = {} + +## Interval (in seconds) at which to update last-activity timestamps. +# Default: 300 +# c.JupyterHub.last_activity_interval = 300 + +## Dict of 'group': ['usernames'] to load at startup. +# +# This strictly *adds* groups and users to groups. +# +# Loading one set of groups, then starting JupyterHub again with a different set +# will not remove users or groups from previous launches. That must be done +# through the API. +# Default: {} +# c.JupyterHub.load_groups = {} + +## The date format used by logging formatters for %(asctime)s +# See also: Application.log_datefmt +# c.JupyterHub.log_datefmt = '%Y-%m-%d %H:%M:%S' + +## The Logging format template +# See also: Application.log_format +# c.JupyterHub.log_format = '[%(name)s]%(highlevel)s %(message)s' + +## Set the log level by value or name. +# See also: Application.log_level +# c.JupyterHub.log_level = 30 + +## Specify path to a logo image to override the Jupyter logo in the banner. +# Default: '' +# c.JupyterHub.logo_file = '' + +## Maximum number of concurrent named servers that can be created by a user at a +# time. +# +# Setting this can limit the total resources a user can consume. +# +# If set to 0, no limit is enforced. +# Default: 0 +# c.JupyterHub.named_server_limit_per_user = 0 + +## File to write PID Useful for daemonizing JupyterHub. +# Default: '' +# c.JupyterHub.pid_file = '' + +## The public facing port of the proxy. +# +# This is the port on which the proxy will listen. This is the only port through +# which JupyterHub should be accessed by users. +# +# .. deprecated: 0.9 +# Use JupyterHub.bind_url +# Default: 8000 +# c.JupyterHub.port = 8000 + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: '' +# c.JupyterHub.proxy_api_ip = '' + +## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url +# Default: 0 +# c.JupyterHub.proxy_api_port = 0 + +## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.auth_token +# Default: '' +# c.JupyterHub.proxy_auth_token = '' + +## Interval (in seconds) at which to check if the proxy is running. +# Default: 30 +# c.JupyterHub.proxy_check_interval = 30 + +## The class to use for configuring the JupyterHub proxy. +# +# Should be a subclass of :class:`jupyterhub.proxy.Proxy`. +# +# .. versionchanged:: 1.0 +# proxies may be registered via entry points, +# e.g. `c.JupyterHub.proxy_class = 'traefik'` +# +# Currently installed: +# - configurable-http-proxy: jupyterhub.proxy.ConfigurableHTTPProxy +# - default: jupyterhub.proxy.ConfigurableHTTPProxy +# Default: 'jupyterhub.proxy.ConfigurableHTTPProxy' +# c.JupyterHub.proxy_class = 'jupyterhub.proxy.ConfigurableHTTPProxy' + +## DEPRECATED since version 0.8. Use ConfigurableHTTPProxy.command +# Default: [] +# c.JupyterHub.proxy_cmd = [] + +## Recreate all certificates used within JupyterHub on restart. +# +# Note: enabling this feature requires restarting all notebook servers. +# +# Use with internal_ssl +# Default: False +# c.JupyterHub.recreate_internal_certs = False + +## Redirect user to server (if running), instead of control panel. +# Default: True +# c.JupyterHub.redirect_to_server = True + +## Purge and reset the database. +# Default: False +# c.JupyterHub.reset_db = False + +## Interval (in seconds) at which to check connectivity of services with web +# endpoints. +# Default: 60 +# c.JupyterHub.service_check_interval = 60 + +## Dict of token:servicename to be loaded into the database. +# +# Allows ahead-of-time generation of API tokens for use by externally managed +# services. +# Default: {} +# c.JupyterHub.service_tokens = {} + +## List of service specification dictionaries. +# +# A service +# +# For instance:: +# +# services = [ +# { +# 'name': 'cull_idle', +# 'command': ['/path/to/cull_idle_servers.py'], +# }, +# { +# 'name': 'formgrader', +# 'url': 'http://127.0.0.1:1234', +# 'api_token': 'super-secret', +# 'environment': +# } +# ] +# Default: [] +# c.JupyterHub.services = [] + +## Instead of starting the Application, dump configuration to stdout +# See also: Application.show_config +# c.JupyterHub.show_config = False + +## Instead of starting the Application, dump configuration to stdout (as JSON) +# See also: Application.show_config_json +# c.JupyterHub.show_config_json = False + +## Shuts down all user servers on logout +# Default: False +# c.JupyterHub.shutdown_on_logout = False + +## The class to use for spawning single-user servers. +# +# Should be a subclass of :class:`jupyterhub.spawner.Spawner`. +# +# .. versionchanged:: 1.0 +# spawners may be registered via entry points, +# e.g. `c.JupyterHub.spawner_class = 'localprocess'` +# +# Currently installed: +# - default: jupyterhub.spawner.LocalProcessSpawner +# - localprocess: jupyterhub.spawner.LocalProcessSpawner +# - simple: jupyterhub.spawner.SimpleLocalProcessSpawner +# Default: 'jupyterhub.spawner.LocalProcessSpawner' +# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' + +## Path to SSL certificate file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_key +# Default: '' +# c.JupyterHub.ssl_cert = '' + +## Path to SSL key file for the public facing interface of the proxy +# +# When setting this, you should also set ssl_cert +# Default: '' +# c.JupyterHub.ssl_key = '' + +## Host to send statsd metrics to. An empty string (the default) disables sending +# metrics. +# Default: '' +# c.JupyterHub.statsd_host = '' + +## Port on which to send statsd metrics about the hub +# Default: 8125 +# c.JupyterHub.statsd_port = 8125 + +## Prefix to use for all metrics sent by jupyterhub to statsd +# Default: 'jupyterhub' +# c.JupyterHub.statsd_prefix = 'jupyterhub' + +## Run single-user servers on subdomains of this host. +# +# This should be the full `https://hub.domain.tld[:port]`. +# +# Provides additional cross-site protections for javascript served by single- +# user servers. +# +# Requires `.hub.domain.tld` to resolve to the same host as +# `hub.domain.tld`. +# +# In general, this is most easily achieved with wildcard DNS. +# +# When using SSL (i.e. always) this also requires a wildcard SSL certificate. +# Default: '' +# c.JupyterHub.subdomain_host = '' + +## Paths to search for jinja templates, before using the default templates. +# Default: [] +# c.JupyterHub.template_paths = [] + +## Extra variables to be passed into jinja templates +# Default: {} +# c.JupyterHub.template_vars = {} + +## Extra settings overrides to pass to the tornado application. +# Default: {} +# c.JupyterHub.tornado_settings = {} + +## Trust user-provided tokens (via JupyterHub.service_tokens) to have good +# entropy. +# +# If you are not inserting additional tokens via configuration file, this flag +# has no effect. +# +# In JupyterHub 0.8, internally generated tokens do not pass through additional +# hashing because the hashing is costly and does not increase the entropy of +# already-good UUIDs. +# +# User-provided tokens, on the other hand, are not trusted to have good entropy +# by default, and are passed through many rounds of hashing to stretch the +# entropy of the key (i.e. user-provided tokens are treated as passwords instead +# of random keys). These keys are more costly to check. +# +# If your inserted tokens are generated by a good-quality mechanism, e.g. +# `openssl rand -hex 32`, then you can set this flag to True to reduce the cost +# of checking authentication tokens. +# Default: False +# c.JupyterHub.trust_user_provided_tokens = False + +## Names to include in the subject alternative name. +# +# These names will be used for server name verification. This is useful if +# JupyterHub is being run behind a reverse proxy or services using ssl are on +# different hosts. +# +# Use with internal_ssl +# Default: [] +# c.JupyterHub.trusted_alt_names = [] + +## Downstream proxy IP addresses to trust. +# +# This sets the list of IP addresses that are trusted and skipped when +# processing the `X-Forwarded-For` header. For example, if an external proxy is +# used for TLS termination, its IP address should be added to this list to +# ensure the correct client IP addresses are recorded in the logs instead of the +# proxy server's IP address. +# Default: [] +# c.JupyterHub.trusted_downstream_ips = [] + +## Upgrade the database automatically on start. +# +# Only safe if database is regularly backed up. Only SQLite databases will be +# backed up to a local file automatically. +# Default: False +# c.JupyterHub.upgrade_db = False + +## Callable to affect behavior of /user-redirect/ +# +# Receives 4 parameters: 1. path - URL path that was provided after /user- +# redirect/ 2. request - A Tornado HTTPServerRequest representing the current +# request. 3. user - The currently authenticated user. 4. base_url - The +# base_url of the current hub, for relative redirects +# +# It should return the new URL to redirect to, or None to preserve current +# behavior. +# Default: None +# c.JupyterHub.user_redirect_hook = None + +#------------------------------------------------------------------------------ +# Spawner(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for spawning single-user notebook servers. +# +# Subclass this, and override the following methods: +# +# - load_state - get_state - start - stop - poll +# +# As JupyterHub supports multiple users, an instance of the Spawner subclass is +# created for each user. If there are 20 JupyterHub users, there will be 20 +# instances of the subclass. + +## Extra arguments to be passed to the single-user server. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables here. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: [] +# c.Spawner.args = [] + +## An optional hook function that you can implement to pass `auth_state` to the +# spawner after it has been initialized but before it starts. The `auth_state` +# dictionary may be set by the `.authenticate()` method of the authenticator. +# This hook enables you to pass some or all of that information to your spawner. +# +# Example:: +# +# def userdata_hook(spawner, auth_state): +# spawner.userdata = auth_state["userdata"] +# +# c.Spawner.auth_state_hook = userdata_hook +# Default: None +# c.Spawner.auth_state_hook = None + +## The command used for starting the single-user server. +# +# Provide either a string or a list containing the path to the startup script +# command. Extra arguments, other than this path, should be provided via `args`. +# +# This is usually set if you want to start the single-user server in a different +# python environment (with virtualenv/conda) than JupyterHub itself. +# +# Some spawners allow shell-style expansion here, allowing you to use +# environment variables. Most, including the default, do not. Consult the +# documentation for your spawner to verify! +# Default: ['jupyterhub-singleuser'] +# c.Spawner.cmd = ['jupyterhub-singleuser'] + +## Maximum number of consecutive failures to allow before shutting down +# JupyterHub. +# +# This helps JupyterHub recover from a certain class of problem preventing +# launch in contexts where the Hub is automatically restarted (e.g. systemd, +# docker, kubernetes). +# +# A limit of 0 means no limit and consecutive failures will not be tracked. +# Default: 0 +# c.Spawner.consecutive_failure_limit = 0 + +## Minimum number of cpu-cores a single-user notebook server is guaranteed to +# have available. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_guarantee = None + +## Maximum number of cpu-cores a single-user notebook server is allowed to use. +# +# If this value is set to 0.5, allows use of 50% of one CPU. If this value is +# set to 2, allows use of up to 2 CPUs. +# +# The single-user notebook server will never be scheduled by the kernel to use +# more cpu-cores than this. There is no guarantee that it can access this many +# cpu-cores. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.cpu_limit = None + +## Enable debug-logging of the single-user server +# Default: False +# c.Spawner.debug = False + +## The URL the single-user server should start in. +# +# `{username}` will be expanded to the user's username +# +# Example uses: +# +# - You can set `notebook_dir` to `/` and `default_url` to `/tree/home/{username}` to allow people to +# navigate the whole filesystem from their notebook server, but still start in their home directory. +# - Start with `/notebooks` instead of `/tree` if `default_url` points to a notebook instead of a directory. +# - You can set this to `/lab` to have JupyterLab start by default, rather than Jupyter Notebook. +# Default: '' +# c.Spawner.default_url = '' + +## Disable per-user configuration of single-user servers. +# +# When starting the user's single-user server, any config file found in the +# user's $HOME directory will be ignored. +# +# Note: a user could circumvent this if the user modifies their Python +# environment, such as when they have their own conda environments / virtualenvs +# / containers. +# Default: False +# c.Spawner.disable_user_config = False + +## List of environment variables for the single-user server to inherit from the +# JupyterHub process. +# +# This list is used to ensure that sensitive information in the JupyterHub +# process's environment (such as `CONFIGPROXY_AUTH_TOKEN`) is not passed to the +# single-user server's process. +# Default: ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] +# c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] + +## Extra environment variables to set for the single-user server's process. +# +# Environment variables that end up in the single-user server's process come from 3 sources: +# - This `environment` configurable +# - The JupyterHub process' environment variables that are listed in `env_keep` +# - Variables to establish contact between the single-user notebook and the hub (such as JUPYTERHUB_API_TOKEN) +# +# The `environment` configurable should be set by JupyterHub administrators to +# add installation specific environment variables. It is a dict where the key is +# the name of the environment variable, and the value can be a string or a +# callable. If it is a callable, it will be called with one parameter (the +# spawner instance), and should return a string fairly quickly (no blocking +# operations please!). +# +# Note that the spawner class' interface is not guaranteed to be exactly same +# across upgrades, so if you are using the callable take care to verify it +# continues to work after upgrades! +# +# .. versionchanged:: 1.2 +# environment from this configuration has highest priority, +# allowing override of 'default' env variables, +# such as JUPYTERHUB_API_URL. +# Default: {} +# c.Spawner.environment = {} + +## Timeout (in seconds) before giving up on a spawned HTTP server +# +# Once a server has successfully been spawned, this is the amount of time we +# wait before assuming that the server is unable to accept connections. +# Default: 30 +# c.Spawner.http_timeout = 30 + +## The IP address (or hostname) the single-user server should listen on. +# +# The JupyterHub proxy implementation should be able to send packets to this +# interface. +# Default: '' +# c.Spawner.ip = '' + +## Minimum number of bytes a single-user notebook server is guaranteed to have +# available. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_guarantee = None + +## Maximum number of bytes a single-user notebook server is allowed to use. +# +# Allows the following suffixes: +# - K -> Kilobytes +# - M -> Megabytes +# - G -> Gigabytes +# - T -> Terabytes +# +# If the single user server tries to allocate more memory than this, it will +# fail. There is no guarantee that the single-user notebook server will be able +# to allocate this much memory - only that it can not allocate more than this. +# +# **This is a configuration setting. Your spawner must implement support for the +# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** +# implement this support. A custom spawner **must** add support for this setting +# for it to be enforced. +# Default: None +# c.Spawner.mem_limit = None + +## Path to the notebook directory for the single-user server. +# +# The user sees a file listing of this directory when the notebook interface is +# started. The current interface does not easily allow browsing beyond the +# subdirectories in this directory's tree. +# +# `~` will be expanded to the home directory of the user, and {username} will be +# replaced with the name of the user. +# +# Note that this does *not* prevent users from accessing files outside of this +# path! They can do so with many other means. +# Default: '' +# c.Spawner.notebook_dir = '' + +## An HTML form for options a user can specify on launching their server. +# +# The surrounding `` element and the submit button are already provided. +# +# For example: +# +# .. code:: html +# +# Set your key: +# +#
+# Choose a letter: +# +# +# The data from this form submission will be passed on to your spawner in +# `self.user_options` +# +# Instead of a form snippet string, this could also be a callable that takes as +# one parameter the current spawner instance and returns a string. The callable +# will be called asynchronously if it returns a future, rather than a str. Note +# that the interface of the spawner class is not deemed stable across versions, +# so using this functionality might cause your JupyterHub upgrades to break. +# Default: traitlets.Undefined +# c.Spawner.options_form = traitlets.Undefined + +## Interpret HTTP form data +# +# Form data will always arrive as a dict of lists of strings. Override this +# function to understand single-values, numbers, etc. +# +# This should coerce form data into the structure expected by self.user_options, +# which must be a dict, and should be JSON-serializeable, though it can contain +# bytes in addition to standard JSON data types. +# +# This method should not have any side effects. Any handling of `user_options` +# should be done in `.start()` to ensure consistent behavior across servers +# spawned via the API and form submission page. +# +# Instances will receive this data on self.user_options, after passing through +# this function, prior to `Spawner.start`. +# +# .. versionchanged:: 1.0 +# user_options are persisted in the JupyterHub database to be reused +# on subsequent spawns if no options are given. +# user_options is serialized to JSON as part of this persistence +# (with additional support for bytes in case of uploaded file data), +# and any non-bytes non-jsonable values will be replaced with None +# if the user_options are re-used. +# Default: traitlets.Undefined +# c.Spawner.options_from_form = traitlets.Undefined + +## Interval (in seconds) on which to poll the spawner for single-user server's +# status. +# +# At every poll interval, each spawner's `.poll` method is called, which checks +# if the single-user server is still running. If it isn't running, then +# JupyterHub modifies its own state accordingly and removes appropriate routes +# from the configurable proxy. +# Default: 30 +# c.Spawner.poll_interval = 30 + +## The port for single-user servers to listen on. +# +# Defaults to `0`, which uses a randomly allocated port number each time. +# +# If set to a non-zero value, all Spawners will use the same port, which only +# makes sense if each server is on a different address, e.g. in containers. +# +# New in version 0.7. +# Default: 0 +# c.Spawner.port = 0 + +## An optional hook function that you can implement to do work after the spawner +# stops. +# +# This can be set independent of any concrete spawner implementation. +# Default: None +# c.Spawner.post_stop_hook = None + +## An optional hook function that you can implement to do some bootstrapping work +# before the spawner starts. For example, create a directory for your user or +# load initial content. +# +# This can be set independent of any concrete spawner implementation. +# +# This maybe a coroutine. +# +# Example:: +# +# from subprocess import check_call +# def my_hook(spawner): +# username = spawner.user.name +# check_call(['./examples/bootstrap-script/bootstrap.sh', username]) +# +# c.Spawner.pre_spawn_hook = my_hook +# Default: None +# c.Spawner.pre_spawn_hook = None + +## List of SSL alt names +# +# May be set in config if all spawners should have the same value(s), or set at +# runtime by Spawner that know their names. +# Default: [] +# c.Spawner.ssl_alt_names = [] + +## Whether to include DNS:localhost, IP:127.0.0.1 in alt names +# Default: True +# c.Spawner.ssl_alt_names_include_local = True + +## Timeout (in seconds) before giving up on starting of single-user server. +# +# This is the timeout for start to return, not the timeout for the server to +# respond. Callers of spawner.start will assume that startup has failed if it +# takes longer than this. start should return when the server process is started +# and its location is known. +# Default: 60 +# c.Spawner.start_timeout = 60 + +#------------------------------------------------------------------------------ +# Authenticator(LoggingConfigurable) configuration +#------------------------------------------------------------------------------ +## Base class for implementing an authentication provider for JupyterHub + +## Set of users that will have admin rights on this JupyterHub. +# +# Admin users have extra privileges: +# - Use the admin panel to see list of users logged in +# - Add / remove users in some authenticators +# - Restart / halt the hub +# - Start / stop users' single-user servers +# - Can access each individual users' single-user server (if configured) +# +# Admin access should be treated the same way root access is. +# +# Defaults to an empty set, in which case no user has admin access. +# Default: set() +# c.Authenticator.admin_users = set() + +## Set of usernames that are allowed to log in. +# +# Use this with supported authenticators to restrict which users can log in. +# This is an additional list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionchanged:: 1.2 +# `Authenticator.whitelist` renamed to `allowed_users` +# Default: set() +# c.Authenticator.allowed_users = set() + +## The max age (in seconds) of authentication info before forcing a refresh of +# user auth info. +# +# Refreshing auth info allows, e.g. requesting/re-validating auth tokens. +# +# See :meth:`.refresh_user` for what happens when user auth info is refreshed +# (nothing by default). +# Default: 300 +# c.Authenticator.auth_refresh_age = 300 + +## Automatically begin the login process +# +# rather than starting with a "Login with..." link at `/hub/login` +# +# To work, `.login_url()` must give a URL other than the default `/hub/login`, +# such as an oauth handler or another automatic login handler, registered with +# `.get_handlers()`. +# +# .. versionadded:: 0.8 +# Default: False +# c.Authenticator.auto_login = False + +## Set of usernames that are not allowed to log in. +# +# Use this with supported authenticators to restrict which users can not log in. +# This is an additional block list that further restricts users, beyond whatever +# restrictions the authenticator has in place. +# +# If empty, does not perform any additional restriction. +# +# .. versionadded: 0.9 +# +# .. versionchanged:: 1.2 +# `Authenticator.blacklist` renamed to `blocked_users` +# Default: set() +# c.Authenticator.blocked_users = set() + +## Delete any users from the database that do not pass validation +# +# When JupyterHub starts, `.add_user` will be called on each user in the +# database to verify that all users are still valid. +# +# If `delete_invalid_users` is True, any users that do not pass validation will +# be deleted from the database. Use this if users might be deleted from an +# external system, such as local user accounts. +# +# If False (default), invalid users remain in the Hub's database and a warning +# will be issued. This is the default to avoid data loss due to config changes. +# Default: False +# c.Authenticator.delete_invalid_users = False + +## Enable persisting auth_state (if available). +# +# auth_state will be encrypted and stored in the Hub's database. This can +# include things like authentication tokens, etc. to be passed to Spawners as +# environment variables. +# +# Encrypting auth_state requires the cryptography package. +# +# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one +# (or more, separated by ;) 32B encryption keys. These can be either base64 or +# hex-encoded. +# +# If encryption is unavailable, auth_state cannot be persisted. +# +# New in JupyterHub 0.8 +# Default: False +# c.Authenticator.enable_auth_state = False + +## An optional hook function that you can implement to do some bootstrapping work +# during authentication. For example, loading user account details from an +# external system. +# +# This function is called after the user has passed all authentication checks +# and is ready to successfully authenticate. This function must return the +# authentication dict reguardless of changes to it. +# +# This maybe a coroutine. +# +# .. versionadded: 1.0 +# +# Example:: +# +# import os, pwd +# def my_hook(authenticator, handler, authentication): +# user_data = pwd.getpwnam(authentication['name']) +# spawn_data = { +# 'pw_data': user_data +# 'gid_list': os.getgrouplist(authentication['name'], user_data.pw_gid) +# } +# +# if authentication['auth_state'] is None: +# authentication['auth_state'] = {} +# authentication['auth_state']['spawn_data'] = spawn_data +# +# return authentication +# +# c.Authenticator.post_auth_hook = my_hook +# Default: None +# c.Authenticator.post_auth_hook = None + +## Force refresh of auth prior to spawn. +# +# This forces :meth:`.refresh_user` to be called prior to launching a server, to +# ensure that auth state is up-to-date. +# +# This can be important when e.g. auth tokens that may have expired are passed +# to the spawner via environment variables from auth_state. +# +# If refresh_user cannot refresh the user auth data, launch will fail until the +# user logs in again. +# Default: False +# c.Authenticator.refresh_pre_spawn = False + +## Dictionary mapping authenticator usernames to JupyterHub users. +# +# Primarily used to normalize OAuth user names to local users. +# Default: {} +# c.Authenticator.username_map = {} + +## Regular expression pattern that all valid usernames must match. +# +# If a username does not match the pattern specified here, authentication will +# not be attempted. +# +# If not set, allow any username. +# Default: '' +# c.Authenticator.username_pattern = '' + +## Deprecated, use `Authenticator.allowed_users` +# Default: set() +# c.Authenticator.whitelist = set() + +#------------------------------------------------------------------------------ +# CryptKeeper(SingletonConfigurable) configuration +#------------------------------------------------------------------------------ +## Encapsulate encryption configuration +# +# Use via the encryption_config singleton below. + +# Default: [] +# c.CryptKeeper.keys = [] + +## The number of threads to allocate for encryption +# Default: 4 +# c.CryptKeeper.n_threads = 4 + +#------------------------------------------------------------------------------ +# Pagination(Configurable) configuration +#------------------------------------------------------------------------------ +## Default number of entries per page for paginated results. +# Default: 100 +# c.Pagination.default_per_page = 100 + +## Maximum number of entries per page for paginated results. +# Default: 250 +# c.Pagination.max_per_page = 250 From 4f535ef2c9cb2f29fcc82ba7c130c01d797e3d2a Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:10:49 +0000 Subject: [PATCH 43/62] systemd spawner is working writing to /var/lib/private --- roles/jupyter/tasks/install.yml | 17 +++++++++++++++-- roles/jupyter/templates/jupyter.service | 2 +- roles/jupyter/templates/jupyterhub_config.py | 13 ++++++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 0c2526856..353f78cae 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,4 +1,9 @@ -- name: Make the directories to hold notebooks +- name: We need a non-privileged user to write all the notebooks + ansible.builtin.user: + name: web-user + home: /opt/iiab/notebooks + +- name: Make the directories to hold jupyter config file: state: directory path: '{{ item }}' @@ -7,6 +12,12 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' +- name: Make a directory to hold notebooks + file: + state: directory + path: /opt/iiab/notebooks + owner: web-user + - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -35,6 +46,8 @@ - ipywidgets - jupyterhub - jupyterlab + - jupyterhub_firstuseauthenticator + - jupyterhub-systemdspawner virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv @@ -45,7 +58,7 @@ - name: Install the config file for jupyterhub template: src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/env/jupyterhub/' + dest: '{{ jupyter_venv }}/etc/jupyterhub/' - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index 363390a9f..f9e5aa798 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -3,7 +3,7 @@ Description=JupyterHub After=syslog.target network.target [Service] -User=hubuser +User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 00c70a126..71d81dbb9 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -114,7 +114,7 @@ # - dummy: jupyterhub.auth.DummyAuthenticator # - pam: jupyterhub.auth.PAMAuthenticator # Default: 'jupyterhub.auth.PAMAuthenticator' -# c.JupyterHub.authenticator_class = 'jupyterhub.auth.PAMAuthenticator' +c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' ## The base URL of the entire application. # @@ -194,7 +194,7 @@ # # Should be exactly 256 bits (32 bytes). # Default: b'' -# c.JupyterHub.cookie_secret = b'' +c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## File in which to store the cookie secret. # Default: 'jupyterhub_cookie_secret' @@ -589,7 +589,7 @@ # - localprocess: jupyterhub.spawner.LocalProcessSpawner # - simple: jupyterhub.spawner.SimpleLocalProcessSpawner # Default: 'jupyterhub.spawner.LocalProcessSpawner' -# c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' +c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' ## Path to SSL certificate file for the public facing interface of the proxy # @@ -1229,3 +1229,10 @@ ## Maximum number of entries per page for paginated results. # Default: 250 # c.Pagination.max_per_page = 250 + +#------------------------------------------------------------------------------ +# Systemdspawner config +#------------------------------------------------------------------------------ +c.SystemdSpawner.dynamic_users = True +c.SystemdSpawner.user_workingdir = '/opt/iiab/notebooks/{USERNAME}' + From 4b1281c62d0b88543eedb0499c84f8bdbc6cf85a Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:19:17 +0000 Subject: [PATCH 44/62] change systemd to more specifially use the venv --- roles/jupyter/templates/jupyter.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service index f9e5aa798..8ce535369 100644 --- a/roles/jupyter/templates/jupyter.service +++ b/roles/jupyter/templates/jupyter.service @@ -5,7 +5,7 @@ After=syslog.target network.target [Service] User=root Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py +ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py [Install] WantedBy=multi-user.target From b2675f4a4689577f7b8bd3ddd62d36d04c35374f Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 03:33:47 +0000 Subject: [PATCH 45/62] add iiab-admin to the authentication list --- roles/jupyter/templates/jupyterhub_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 71d81dbb9..999715a8f 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() -# c.Authenticator.admin_users = set() + c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From be275ca4aede4fdac16fe241efa56b902b869a42 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 05:15:15 +0000 Subject: [PATCH 46/62] remove creation of notebook, spawner puts in /var/lib/private --- roles/jupyter/tasks/enable-or-disable.yml | 16 ++++++++++++++++ roles/jupyter/tasks/install.yml | 12 +----------- roles/jupyter/templates/jupyterhub_config.py | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml index ad8bb17ad..becab8e9a 100644 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ b/roles/jupyter/tasks/enable-or-disable.yml @@ -23,3 +23,19 @@ when: not jupyter_enabled +- name: Put the nginx config file in place + template: + src: jupyter-nginx.conf + dest: "{{ nginx_conf_dir }}/" + when: jupyter_enabled + +- name: Disable jupyterhub + file: + path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" + state: absent + when: not jupyter_enabled + +- name: Restart 'nginx' systemd service + systemd: + name: nginx + state: restarted diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml index 353f78cae..6901db83d 100644 --- a/roles/jupyter/tasks/install.yml +++ b/roles/jupyter/tasks/install.yml @@ -1,8 +1,3 @@ -- name: We need a non-privileged user to write all the notebooks - ansible.builtin.user: - name: web-user - home: /opt/iiab/notebooks - - name: Make the directories to hold jupyter config file: state: directory @@ -12,12 +7,6 @@ - '{{ jupyter_venv }}/etc/jupyterhub' - '{{ jupyter_venv }}/etc/systemd' -- name: Make a directory to hold notebooks - file: - state: directory - path: /opt/iiab/notebooks - owner: web-user - - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -59,6 +48,7 @@ template: src: jupyterhub_config.py dest: '{{ jupyter_venv }}/etc/jupyterhub/' + - name: Use systemd to start jupyterhub template: src: jupyter.service diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index 999715a8f..cd0999ca1 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -1057,7 +1057,7 @@ c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' # # Defaults to an empty set, in which case no user has admin access. # Default: set() - c.Authenticator.admin_users = set('iiab-admin') +c.Authenticator.admin_users = set('iiab-admin') ## Set of usernames that are allowed to log in. # From 9ccffb95a2ba277164787ab31fad886b96a7d2a4 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Wed, 10 Mar 2021 17:35:48 +0000 Subject: [PATCH 47/62] getting nginx proxy to work /jupyterhub --- roles/jupyter/templates/jupyter-nginx.conf | 20 ++++++++++++++++++++ roles/jupyter/templates/jupyterhub_config.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 roles/jupyter/templates/jupyter-nginx.conf diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyter/templates/jupyter-nginx.conf new file mode 100644 index 000000000..a9d450c10 --- /dev/null +++ b/roles/jupyter/templates/jupyter-nginx.conf @@ -0,0 +1,20 @@ +location /jupyterhub { + proxy_pass http://127.0.0.1:8000; + proxy_set_header X-Real-IP $remote_addr; + #proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; + + + # websocket headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + #proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Scheme $scheme; + + proxy_buffering off; + } + # Managing requests to verify letsencrypt host + location ~ /.well-known { + allow all; + } diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py index cd0999ca1..ade964254 100644 --- a/roles/jupyter/templates/jupyterhub_config.py +++ b/roles/jupyter/templates/jupyterhub_config.py @@ -124,7 +124,7 @@ c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' # .. deprecated: 0.9 # Use JupyterHub.bind_url # Default: '/' -# c.JupyterHub.base_url = '/' +# c.JupyterHub.base_url = '/jupyterhub' ## The public facing URL of the whole JupyterHub application. # From da40d2d162926d005fa0f18f02ff190b9f56bc17 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 05:07:56 +0000 Subject: [PATCH 48/62] add in README.md --- roles/jupyter/docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 roles/jupyter/docs/README.md diff --git a/roles/jupyter/docs/README.md b/roles/jupyter/docs/README.md new file mode 100644 index 000000000..2878ebaa6 --- /dev/null +++ b/roles/jupyter/docs/README.md @@ -0,0 +1,6 @@ +### Jupyter Notebooks on Rpi Server +* Jupyter Notebooks are widely used in the scientific community. +* This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. +* Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. +* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. +* Students will not have any priviletes outside of their own folder. From c2dfe965cca5ed91468ff1552ec4e3ad5aaf927e Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:24:05 +0000 Subject: [PATCH 49/62] remove the jupyter<->jupyterhub conflict. Make all jupyterhub --- roles/jupyter/defaults/main.yml | 4 - roles/jupyter/docs/README.md | 6 - roles/jupyter/tasks/enable-or-disable.yml | 41 - roles/jupyter/tasks/install.yml | 55 - roles/jupyter/tasks/main.yml | 23 - roles/jupyter/templates/jupyter-nginx.conf | 20 - roles/jupyter/templates/jupyter.service | 11 - roles/jupyter/templates/jupyterhub_config.py | 1238 ------------------ roles/jupyterhub/defaults/main.yml | 4 +- vars/default_vars.yml | 4 +- 10 files changed, 5 insertions(+), 1401 deletions(-) delete mode 100644 roles/jupyter/defaults/main.yml delete mode 100644 roles/jupyter/docs/README.md delete mode 100644 roles/jupyter/tasks/enable-or-disable.yml delete mode 100644 roles/jupyter/tasks/install.yml delete mode 100644 roles/jupyter/tasks/main.yml delete mode 100644 roles/jupyter/templates/jupyter-nginx.conf delete mode 100644 roles/jupyter/templates/jupyter.service delete mode 100644 roles/jupyter/templates/jupyterhub_config.py diff --git a/roles/jupyter/defaults/main.yml b/roles/jupyter/defaults/main.yml deleted file mode 100644 index b22730df0..000000000 --- a/roles/jupyter/defaults/main.yml +++ /dev/null @@ -1,4 +0,0 @@ -notebook_dir: /opt/iiab/notebook -jupyter_venv: /opt/iiab/jupyter -jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub -jupyterhub_port: 8000 diff --git a/roles/jupyter/docs/README.md b/roles/jupyter/docs/README.md deleted file mode 100644 index 2878ebaa6..000000000 --- a/roles/jupyter/docs/README.md +++ /dev/null @@ -1,6 +0,0 @@ -### Jupyter Notebooks on Rpi Server -* Jupyter Notebooks are widely used in the scientific community. -* This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. -* Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. -* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. -* Students will not have any priviletes outside of their own folder. diff --git a/roles/jupyter/tasks/enable-or-disable.yml b/roles/jupyter/tasks/enable-or-disable.yml deleted file mode 100644 index becab8e9a..000000000 --- a/roles/jupyter/tasks/enable-or-disable.yml +++ /dev/null @@ -1,41 +0,0 @@ -- name: systemd daemon-reload - systemd: - daemon_reload: yes - - -# enable or disable -- name: Enable & Restart jupyterhub - systemd: - name: "{{ item }}" - enabled: yes - state: restarted - with_items: - - jupyter - when: jupyter_enabled - -- name: Disable jupyterhub - systemd: - name: "{{ item }}" - enabled: no - state: stopped - with_items: - - jupyter - when: not jupyter_enabled - - -- name: Put the nginx config file in place - template: - src: jupyter-nginx.conf - dest: "{{ nginx_conf_dir }}/" - when: jupyter_enabled - -- name: Disable jupyterhub - file: - path: "{{ nginx_conf_dir }}/jupyter-nginx.conf" - state: absent - when: not jupyter_enabled - -- name: Restart 'nginx' systemd service - systemd: - name: nginx - state: restarted diff --git a/roles/jupyter/tasks/install.yml b/roles/jupyter/tasks/install.yml deleted file mode 100644 index 6901db83d..000000000 --- a/roles/jupyter/tasks/install.yml +++ /dev/null @@ -1,55 +0,0 @@ -- name: Make the directories to hold jupyter config - file: - state: directory - path: '{{ item }}' - with_items: - - '{{ jupyter_venv }}/etc/jupyter' - - '{{ jupyter_venv }}/etc/jupyterhub' - - '{{ jupyter_venv }}/etc/systemd' - -- name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" - set_fact: - nodejs_install: True - nodejs_enabled: True - -- name: NODEJS - run 'nodejs' role (attempt to install & enable Node.js) - include_role: - name: nodejs - -- name: FAIL (STOP THE INSTALL) IF 'nodejs_installed is undefined' - fail: - msg: "Jupyter install cannot proceed, as Node.js is not installed." - when: nodejs_installed is undefined - -- name: use npm to install configurable http proxy - npm: - name: configurable-http-proxy - global: yes - state: latest - -- name: Use pip to install into a virtual environment - pip: - name: - - pip - - wheel - - ipywidgets - - jupyterhub - - jupyterlab - - jupyterhub_firstuseauthenticator - - jupyterhub-systemdspawner - virtualenv: "{{ jupyter_venv }}" # /opt/iiab/jupyter - virtualenv_site_packages: no - virtualenv_command: /usr/bin/virtualenv - virtualenv_python: python3 - extra_args: "--no-cache-dir" - when: internet_available - -- name: Install the config file for jupyterhub - template: - src: jupyterhub_config.py - dest: '{{ jupyter_venv }}/etc/jupyterhub/' - -- name: Use systemd to start jupyterhub - template: - src: jupyter.service - dest: /etc/systemd/system/ diff --git a/roles/jupyter/tasks/main.yml b/roles/jupyter/tasks/main.yml deleted file mode 100644 index 137a01b84..000000000 --- a/roles/jupyter/tasks/main.yml +++ /dev/null @@ -1,23 +0,0 @@ -- name: Install Jupyter if jupyter_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml - include_tasks: install.yml - when: jupyter_installed is undefined - - -- include_tasks: enable-or-disable.yml - - -- name: Add 'jupyter' variable values to {{ iiab_ini_file }} - ini_file: - path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: jupyter - option: "{{ item.option }}" - value: "{{ item.value | string }}" - with_items: - - option: name - value: Jupyter - - option: description - value: '"Raspberry Pi Jupyter python programming environment"' - - option: install - value: "{{ jupyter_install }}" - - option: enabled - value: "{{ jupyter_enabled }}" diff --git a/roles/jupyter/templates/jupyter-nginx.conf b/roles/jupyter/templates/jupyter-nginx.conf deleted file mode 100644 index a9d450c10..000000000 --- a/roles/jupyter/templates/jupyter-nginx.conf +++ /dev/null @@ -1,20 +0,0 @@ -location /jupyterhub { - proxy_pass http://127.0.0.1:8000; - proxy_set_header X-Real-IP $remote_addr; - #proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-NginX-Proxy true; - - - # websocket headers - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - #proxy_set_header Connection $connection_upgrade; - proxy_set_header X-Scheme $scheme; - - proxy_buffering off; - } - # Managing requests to verify letsencrypt host - location ~ /.well-known { - allow all; - } diff --git a/roles/jupyter/templates/jupyter.service b/roles/jupyter/templates/jupyter.service deleted file mode 100644 index 8ce535369..000000000 --- a/roles/jupyter/templates/jupyter.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=JupyterHub -After=syslog.target network.target - -[Service] -User=root -Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:{{ jupyter_venv }}/bin" -ExecStart={{ jupyter_venv }}/bin/python3 -m jupyterhub -f {{ jupyter_venv }}/etc/jupyterhub/jupyterhub_config.py - -[Install] -WantedBy=multi-user.target diff --git a/roles/jupyter/templates/jupyterhub_config.py b/roles/jupyter/templates/jupyterhub_config.py deleted file mode 100644 index ade964254..000000000 --- a/roles/jupyter/templates/jupyterhub_config.py +++ /dev/null @@ -1,1238 +0,0 @@ -# Configuration file for jupyterhub. - -#------------------------------------------------------------------------------ -# Application(SingletonConfigurable) configuration -#------------------------------------------------------------------------------ -## This is an application. - -## The date format used by logging formatters for %(asctime)s -# Default: '%Y-%m-%d %H:%M:%S' -# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' - -## The Logging format template -# Default: '[%(name)s]%(highlevel)s %(message)s' -# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' - -## Set the log level by value or name. -# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] -# Default: 30 -# c.Application.log_level = 30 - -## Instead of starting the Application, dump configuration to stdout -# Default: False -# c.Application.show_config = False - -## Instead of starting the Application, dump configuration to stdout (as JSON) -# Default: False -# c.Application.show_config_json = False - -#------------------------------------------------------------------------------ -# JupyterHub(Application) configuration -#------------------------------------------------------------------------------ -## An Application for starting a Multi-User Jupyter Notebook server. - -## Maximum number of concurrent servers that can be active at a time. -# -# Setting this can limit the total resources your users can consume. -# -# An active server is any server that's not fully stopped. It is considered -# active from the time it has been requested until the time that it has -# completely stopped. -# -# If this many user servers are active, users will not be able to launch new -# servers until a server is shutdown. Spawn requests will be rejected with a 429 -# error asking them to try again. -# -# If set to 0, no limit is enforced. -# Default: 0 -# c.JupyterHub.active_server_limit = 0 - -## Duration (in seconds) to determine the number of active users. -# Default: 1800 -# c.JupyterHub.active_user_window = 1800 - -## Resolution (in seconds) for updating activity -# -# If activity is registered that is less than activity_resolution seconds more -# recent than the current value, the new value will be ignored. -# -# This avoids too many writes to the Hub database. -# Default: 30 -# c.JupyterHub.activity_resolution = 30 - -## Grant admin users permission to access single-user servers. -# -# Users should be properly informed if this is enabled. -# Default: False -# c.JupyterHub.admin_access = False - -## DEPRECATED since version 0.7.2, use Authenticator.admin_users instead. -# Default: set() -# c.JupyterHub.admin_users = set() - -## Allow named single-user servers per user -# Default: False -# c.JupyterHub.allow_named_servers = False - -## Answer yes to any questions (e.g. confirm overwrite) -# Default: False -# c.JupyterHub.answer_yes = False - -## PENDING DEPRECATION: consider using services -# -# Dict of token:username to be loaded into the database. -# -# Allows ahead-of-time generation of API tokens for use by externally managed -# services, which authenticate as JupyterHub users. -# -# Consider using services for general services that talk to the JupyterHub API. -# Default: {} -# c.JupyterHub.api_tokens = {} - -## Authentication for prometheus metrics -# Default: True -# c.JupyterHub.authenticate_prometheus = True - -## Class for authenticating users. -# -# This should be a subclass of :class:`jupyterhub.auth.Authenticator` -# -# with an :meth:`authenticate` method that: -# -# - is a coroutine (asyncio or tornado) -# - returns username on success, None on failure -# - takes two arguments: (handler, data), -# where `handler` is the calling web.RequestHandler, -# and `data` is the POST form data from the login page. -# -# .. versionchanged:: 1.0 -# authenticators may be registered via entry points, -# e.g. `c.JupyterHub.authenticator_class = 'pam'` -# -# Currently installed: -# - default: jupyterhub.auth.PAMAuthenticator -# - dummy: jupyterhub.auth.DummyAuthenticator -# - pam: jupyterhub.auth.PAMAuthenticator -# Default: 'jupyterhub.auth.PAMAuthenticator' -c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator' - -## The base URL of the entire application. -# -# Add this to the beginning of all JupyterHub URLs. Use base_url to run -# JupyterHub within an existing website. -# -# .. deprecated: 0.9 -# Use JupyterHub.bind_url -# Default: '/' -# c.JupyterHub.base_url = '/jupyterhub' - -## The public facing URL of the whole JupyterHub application. -# -# This is the address on which the proxy will bind. Sets protocol, ip, base_url -# Default: 'http://:8000' -# c.JupyterHub.bind_url = 'http://:8000' - -## Whether to shutdown the proxy when the Hub shuts down. -# -# Disable if you want to be able to teardown the Hub while leaving the proxy -# running. -# -# Only valid if the proxy was starting by the Hub process. -# -# If both this and cleanup_servers are False, sending SIGINT to the Hub will -# only shutdown the Hub, leaving everything else running. -# -# The Hub should be able to resume from database state. -# Default: True -# c.JupyterHub.cleanup_proxy = True - -## Whether to shutdown single-user servers when the Hub shuts down. -# -# Disable if you want to be able to teardown the Hub while leaving the single- -# user servers running. -# -# If both this and cleanup_proxy are False, sending SIGINT to the Hub will only -# shutdown the Hub, leaving everything else running. -# -# The Hub should be able to resume from database state. -# Default: True -# c.JupyterHub.cleanup_servers = True - -## Maximum number of concurrent users that can be spawning at a time. -# -# Spawning lots of servers at the same time can cause performance problems for -# the Hub or the underlying spawning system. Set this limit to prevent bursts of -# logins from attempting to spawn too many servers at the same time. -# -# This does not limit the number of total running servers. See -# active_server_limit for that. -# -# If more than this many users attempt to spawn at a time, their requests will -# be rejected with a 429 error asking them to try again. Users will have to wait -# for some of the spawning services to finish starting before they can start -# their own. -# -# If set to 0, no limit is enforced. -# Default: 100 -# c.JupyterHub.concurrent_spawn_limit = 100 - -## The config file to load -# Default: 'jupyterhub_config.py' -# c.JupyterHub.config_file = 'jupyterhub_config.py' - -## DEPRECATED: does nothing -# Default: False -# c.JupyterHub.confirm_no_ssl = False - -## Number of days for a login cookie to be valid. Default is two weeks. -# Default: 14 -# c.JupyterHub.cookie_max_age_days = 14 - -## The cookie secret to use to encrypt cookies. -# -# Loaded from the JPY_COOKIE_SECRET env variable by default. -# -# Should be exactly 256 bits (32 bytes). -# Default: b'' -c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' - -## File in which to store the cookie secret. -# Default: 'jupyterhub_cookie_secret' -# c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' - -## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) -# Default: '/opt/iiab/jupyter/share/jupyterhub' -# c.JupyterHub.data_files_path = '/opt/iiab/jupyter/share/jupyterhub' - -## Include any kwargs to pass to the database connection. See -# sqlalchemy.create_engine for details. -# Default: {} -# c.JupyterHub.db_kwargs = {} - -## url for the database. e.g. `sqlite:///jupyterhub.sqlite` -# Default: 'sqlite:///jupyterhub.sqlite' -# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' - -## log all database transactions. This has A LOT of output -# Default: False -# c.JupyterHub.debug_db = False - -## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.debug -# Default: False -# c.JupyterHub.debug_proxy = False - -## If named servers are enabled, default name of server to spawn or open, e.g. by -# user-redirect. -# Default: '' -# c.JupyterHub.default_server_name = '' - -## The default URL for users when they arrive (e.g. when user directs to "/") -# -# By default, redirects users to their own server. -# -# Can be a Unicode string (e.g. '/hub/home') or a callable based on the handler -# object: -# -# :: -# -# def default_url_fn(handler): -# user = handler.current_user -# if user and user.admin: -# return '/hub/admin' -# return '/hub/home' -# -# c.JupyterHub.default_url = default_url_fn -# Default: traitlets.Undefined -# c.JupyterHub.default_url = traitlets.Undefined - -## Dict authority:dict(files). Specify the key, cert, and/or ca file for an -# authority. This is useful for externally managed proxies that wish to use -# internal_ssl. -# -# The files dict has this format (you must specify at least a cert):: -# -# { -# 'key': '/path/to/key.key', -# 'cert': '/path/to/cert.crt', -# 'ca': '/path/to/ca.crt' -# } -# -# The authorities you can override: 'hub-ca', 'notebooks-ca', 'proxy-api-ca', -# 'proxy-client-ca', and 'services-ca'. -# -# Use with internal_ssl -# Default: {} -# c.JupyterHub.external_ssl_authorities = {} - -## Register extra tornado Handlers for jupyterhub. -# -# Should be of the form ``("", Handler)`` -# -# The Hub prefix will be added, so `/my-page` will be served at `/hub/my-page`. -# Default: [] -# c.JupyterHub.extra_handlers = [] - -## DEPRECATED: use output redirection instead, e.g. -# -# jupyterhub &>> /var/log/jupyterhub.log -# Default: '' -# c.JupyterHub.extra_log_file = '' - -## Extra log handlers to set on JupyterHub logger -# Default: [] -# c.JupyterHub.extra_log_handlers = [] - -## Generate certs used for internal ssl -# Default: False -# c.JupyterHub.generate_certs = False - -## Generate default config file -# Default: False -# c.JupyterHub.generate_config = False - -## The URL on which the Hub will listen. This is a private URL for internal -# communication. Typically set in combination with hub_connect_url. If a unix -# socket, hub_connect_url **must** also be set. -# -# For example: -# -# "http://127.0.0.1:8081" -# "unix+http://%2Fsrv%2Fjupyterhub%2Fjupyterhub.sock" -# -# .. versionadded:: 0.9 -# Default: '' -# c.JupyterHub.hub_bind_url = '' - -## The ip or hostname for proxies and spawners to use for connecting to the Hub. -# -# Use when the bind address (`hub_ip`) is 0.0.0.0, :: or otherwise different -# from the connect address. -# -# Default: when `hub_ip` is 0.0.0.0 or ::, use `socket.gethostname()`, otherwise -# use `hub_ip`. -# -# Note: Some spawners or proxy implementations might not support hostnames. -# Check your spawner or proxy documentation to see if they have extra -# requirements. -# -# .. versionadded:: 0.8 -# Default: '' -# c.JupyterHub.hub_connect_ip = '' - -## DEPRECATED -# -# Use hub_connect_url -# -# .. versionadded:: 0.8 -# -# .. deprecated:: 0.9 -# Use hub_connect_url -# Default: 0 -# c.JupyterHub.hub_connect_port = 0 - -## The URL for connecting to the Hub. Spawners, services, and the proxy will use -# this URL to talk to the Hub. -# -# Only needs to be specified if the default hub URL is not connectable (e.g. -# using a unix+http:// bind url). -# -# .. seealso:: -# JupyterHub.hub_connect_ip -# JupyterHub.hub_bind_url -# -# .. versionadded:: 0.9 -# Default: '' -# c.JupyterHub.hub_connect_url = '' - -## The ip address for the Hub process to *bind* to. -# -# By default, the hub listens on localhost only. This address must be accessible -# from the proxy and user servers. You may need to set this to a public ip or '' -# for all interfaces if the proxy or user servers are in containers or on a -# different host. -# -# See `hub_connect_ip` for cases where the bind and connect address should -# differ, or `hub_bind_url` for setting the full bind URL. -# Default: '127.0.0.1' -# c.JupyterHub.hub_ip = '127.0.0.1' - -## The internal port for the Hub process. -# -# This is the internal port of the hub itself. It should never be accessed -# directly. See JupyterHub.port for the public port to use when accessing -# jupyterhub. It is rare that this port should be set except in cases of port -# conflict. -# -# See also `hub_ip` for the ip and `hub_bind_url` for setting the full bind URL. -# Default: 8081 -# c.JupyterHub.hub_port = 8081 - -## Trigger implicit spawns after this many seconds. -# -# When a user visits a URL for a server that's not running, they are shown a -# page indicating that the requested server is not running with a button to -# spawn the server. -# -# Setting this to a positive value will redirect the user after this many -# seconds, effectively clicking this button automatically for the users, -# automatically beginning the spawn process. -# -# Warning: this can result in errors and surprising behavior when sharing access -# URLs to actual servers, since the wrong server is likely to be started. -# Default: 0 -# c.JupyterHub.implicit_spawn_seconds = 0 - -## Timeout (in seconds) to wait for spawners to initialize -# -# Checking if spawners are healthy can take a long time if many spawners are -# active at hub start time. -# -# If it takes longer than this timeout to check, init_spawner will be left to -# complete in the background and the http server is allowed to start. -# -# A timeout of -1 means wait forever, which can mean a slow startup of the Hub -# but ensures that the Hub is fully consistent by the time it starts responding -# to requests. This matches the behavior of jupyterhub 1.0. -# -# .. versionadded: 1.1.0 -# Default: 10 -# c.JupyterHub.init_spawners_timeout = 10 - -## The location to store certificates automatically created by JupyterHub. -# -# Use with internal_ssl -# Default: 'internal-ssl' -# c.JupyterHub.internal_certs_location = 'internal-ssl' - -## Enable SSL for all internal communication -# -# This enables end-to-end encryption between all JupyterHub components. -# JupyterHub will automatically create the necessary certificate authority and -# sign notebook certificates as they're created. -# Default: False -# c.JupyterHub.internal_ssl = False - -## The public facing ip of the whole JupyterHub application (specifically -# referred to as the proxy). -# -# This is the address on which the proxy will listen. The default is to listen -# on all interfaces. This is the only address through which JupyterHub should be -# accessed by users. -# -# .. deprecated: 0.9 -# Use JupyterHub.bind_url -# Default: '' -# c.JupyterHub.ip = '' - -## Supply extra arguments that will be passed to Jinja environment. -# Default: {} -# c.JupyterHub.jinja_environment_options = {} - -## Interval (in seconds) at which to update last-activity timestamps. -# Default: 300 -# c.JupyterHub.last_activity_interval = 300 - -## Dict of 'group': ['usernames'] to load at startup. -# -# This strictly *adds* groups and users to groups. -# -# Loading one set of groups, then starting JupyterHub again with a different set -# will not remove users or groups from previous launches. That must be done -# through the API. -# Default: {} -# c.JupyterHub.load_groups = {} - -## The date format used by logging formatters for %(asctime)s -# See also: Application.log_datefmt -# c.JupyterHub.log_datefmt = '%Y-%m-%d %H:%M:%S' - -## The Logging format template -# See also: Application.log_format -# c.JupyterHub.log_format = '[%(name)s]%(highlevel)s %(message)s' - -## Set the log level by value or name. -# See also: Application.log_level -# c.JupyterHub.log_level = 30 - -## Specify path to a logo image to override the Jupyter logo in the banner. -# Default: '' -# c.JupyterHub.logo_file = '' - -## Maximum number of concurrent named servers that can be created by a user at a -# time. -# -# Setting this can limit the total resources a user can consume. -# -# If set to 0, no limit is enforced. -# Default: 0 -# c.JupyterHub.named_server_limit_per_user = 0 - -## File to write PID Useful for daemonizing JupyterHub. -# Default: '' -# c.JupyterHub.pid_file = '' - -## The public facing port of the proxy. -# -# This is the port on which the proxy will listen. This is the only port through -# which JupyterHub should be accessed by users. -# -# .. deprecated: 0.9 -# Use JupyterHub.bind_url -# Default: 8000 -# c.JupyterHub.port = 8000 - -## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url -# Default: '' -# c.JupyterHub.proxy_api_ip = '' - -## DEPRECATED since version 0.8 : Use ConfigurableHTTPProxy.api_url -# Default: 0 -# c.JupyterHub.proxy_api_port = 0 - -## DEPRECATED since version 0.8: Use ConfigurableHTTPProxy.auth_token -# Default: '' -# c.JupyterHub.proxy_auth_token = '' - -## Interval (in seconds) at which to check if the proxy is running. -# Default: 30 -# c.JupyterHub.proxy_check_interval = 30 - -## The class to use for configuring the JupyterHub proxy. -# -# Should be a subclass of :class:`jupyterhub.proxy.Proxy`. -# -# .. versionchanged:: 1.0 -# proxies may be registered via entry points, -# e.g. `c.JupyterHub.proxy_class = 'traefik'` -# -# Currently installed: -# - configurable-http-proxy: jupyterhub.proxy.ConfigurableHTTPProxy -# - default: jupyterhub.proxy.ConfigurableHTTPProxy -# Default: 'jupyterhub.proxy.ConfigurableHTTPProxy' -# c.JupyterHub.proxy_class = 'jupyterhub.proxy.ConfigurableHTTPProxy' - -## DEPRECATED since version 0.8. Use ConfigurableHTTPProxy.command -# Default: [] -# c.JupyterHub.proxy_cmd = [] - -## Recreate all certificates used within JupyterHub on restart. -# -# Note: enabling this feature requires restarting all notebook servers. -# -# Use with internal_ssl -# Default: False -# c.JupyterHub.recreate_internal_certs = False - -## Redirect user to server (if running), instead of control panel. -# Default: True -# c.JupyterHub.redirect_to_server = True - -## Purge and reset the database. -# Default: False -# c.JupyterHub.reset_db = False - -## Interval (in seconds) at which to check connectivity of services with web -# endpoints. -# Default: 60 -# c.JupyterHub.service_check_interval = 60 - -## Dict of token:servicename to be loaded into the database. -# -# Allows ahead-of-time generation of API tokens for use by externally managed -# services. -# Default: {} -# c.JupyterHub.service_tokens = {} - -## List of service specification dictionaries. -# -# A service -# -# For instance:: -# -# services = [ -# { -# 'name': 'cull_idle', -# 'command': ['/path/to/cull_idle_servers.py'], -# }, -# { -# 'name': 'formgrader', -# 'url': 'http://127.0.0.1:1234', -# 'api_token': 'super-secret', -# 'environment': -# } -# ] -# Default: [] -# c.JupyterHub.services = [] - -## Instead of starting the Application, dump configuration to stdout -# See also: Application.show_config -# c.JupyterHub.show_config = False - -## Instead of starting the Application, dump configuration to stdout (as JSON) -# See also: Application.show_config_json -# c.JupyterHub.show_config_json = False - -## Shuts down all user servers on logout -# Default: False -# c.JupyterHub.shutdown_on_logout = False - -## The class to use for spawning single-user servers. -# -# Should be a subclass of :class:`jupyterhub.spawner.Spawner`. -# -# .. versionchanged:: 1.0 -# spawners may be registered via entry points, -# e.g. `c.JupyterHub.spawner_class = 'localprocess'` -# -# Currently installed: -# - default: jupyterhub.spawner.LocalProcessSpawner -# - localprocess: jupyterhub.spawner.LocalProcessSpawner -# - simple: jupyterhub.spawner.SimpleLocalProcessSpawner -# Default: 'jupyterhub.spawner.LocalProcessSpawner' -c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner' - -## Path to SSL certificate file for the public facing interface of the proxy -# -# When setting this, you should also set ssl_key -# Default: '' -# c.JupyterHub.ssl_cert = '' - -## Path to SSL key file for the public facing interface of the proxy -# -# When setting this, you should also set ssl_cert -# Default: '' -# c.JupyterHub.ssl_key = '' - -## Host to send statsd metrics to. An empty string (the default) disables sending -# metrics. -# Default: '' -# c.JupyterHub.statsd_host = '' - -## Port on which to send statsd metrics about the hub -# Default: 8125 -# c.JupyterHub.statsd_port = 8125 - -## Prefix to use for all metrics sent by jupyterhub to statsd -# Default: 'jupyterhub' -# c.JupyterHub.statsd_prefix = 'jupyterhub' - -## Run single-user servers on subdomains of this host. -# -# This should be the full `https://hub.domain.tld[:port]`. -# -# Provides additional cross-site protections for javascript served by single- -# user servers. -# -# Requires `.hub.domain.tld` to resolve to the same host as -# `hub.domain.tld`. -# -# In general, this is most easily achieved with wildcard DNS. -# -# When using SSL (i.e. always) this also requires a wildcard SSL certificate. -# Default: '' -# c.JupyterHub.subdomain_host = '' - -## Paths to search for jinja templates, before using the default templates. -# Default: [] -# c.JupyterHub.template_paths = [] - -## Extra variables to be passed into jinja templates -# Default: {} -# c.JupyterHub.template_vars = {} - -## Extra settings overrides to pass to the tornado application. -# Default: {} -# c.JupyterHub.tornado_settings = {} - -## Trust user-provided tokens (via JupyterHub.service_tokens) to have good -# entropy. -# -# If you are not inserting additional tokens via configuration file, this flag -# has no effect. -# -# In JupyterHub 0.8, internally generated tokens do not pass through additional -# hashing because the hashing is costly and does not increase the entropy of -# already-good UUIDs. -# -# User-provided tokens, on the other hand, are not trusted to have good entropy -# by default, and are passed through many rounds of hashing to stretch the -# entropy of the key (i.e. user-provided tokens are treated as passwords instead -# of random keys). These keys are more costly to check. -# -# If your inserted tokens are generated by a good-quality mechanism, e.g. -# `openssl rand -hex 32`, then you can set this flag to True to reduce the cost -# of checking authentication tokens. -# Default: False -# c.JupyterHub.trust_user_provided_tokens = False - -## Names to include in the subject alternative name. -# -# These names will be used for server name verification. This is useful if -# JupyterHub is being run behind a reverse proxy or services using ssl are on -# different hosts. -# -# Use with internal_ssl -# Default: [] -# c.JupyterHub.trusted_alt_names = [] - -## Downstream proxy IP addresses to trust. -# -# This sets the list of IP addresses that are trusted and skipped when -# processing the `X-Forwarded-For` header. For example, if an external proxy is -# used for TLS termination, its IP address should be added to this list to -# ensure the correct client IP addresses are recorded in the logs instead of the -# proxy server's IP address. -# Default: [] -# c.JupyterHub.trusted_downstream_ips = [] - -## Upgrade the database automatically on start. -# -# Only safe if database is regularly backed up. Only SQLite databases will be -# backed up to a local file automatically. -# Default: False -# c.JupyterHub.upgrade_db = False - -## Callable to affect behavior of /user-redirect/ -# -# Receives 4 parameters: 1. path - URL path that was provided after /user- -# redirect/ 2. request - A Tornado HTTPServerRequest representing the current -# request. 3. user - The currently authenticated user. 4. base_url - The -# base_url of the current hub, for relative redirects -# -# It should return the new URL to redirect to, or None to preserve current -# behavior. -# Default: None -# c.JupyterHub.user_redirect_hook = None - -#------------------------------------------------------------------------------ -# Spawner(LoggingConfigurable) configuration -#------------------------------------------------------------------------------ -## Base class for spawning single-user notebook servers. -# -# Subclass this, and override the following methods: -# -# - load_state - get_state - start - stop - poll -# -# As JupyterHub supports multiple users, an instance of the Spawner subclass is -# created for each user. If there are 20 JupyterHub users, there will be 20 -# instances of the subclass. - -## Extra arguments to be passed to the single-user server. -# -# Some spawners allow shell-style expansion here, allowing you to use -# environment variables here. Most, including the default, do not. Consult the -# documentation for your spawner to verify! -# Default: [] -# c.Spawner.args = [] - -## An optional hook function that you can implement to pass `auth_state` to the -# spawner after it has been initialized but before it starts. The `auth_state` -# dictionary may be set by the `.authenticate()` method of the authenticator. -# This hook enables you to pass some or all of that information to your spawner. -# -# Example:: -# -# def userdata_hook(spawner, auth_state): -# spawner.userdata = auth_state["userdata"] -# -# c.Spawner.auth_state_hook = userdata_hook -# Default: None -# c.Spawner.auth_state_hook = None - -## The command used for starting the single-user server. -# -# Provide either a string or a list containing the path to the startup script -# command. Extra arguments, other than this path, should be provided via `args`. -# -# This is usually set if you want to start the single-user server in a different -# python environment (with virtualenv/conda) than JupyterHub itself. -# -# Some spawners allow shell-style expansion here, allowing you to use -# environment variables. Most, including the default, do not. Consult the -# documentation for your spawner to verify! -# Default: ['jupyterhub-singleuser'] -# c.Spawner.cmd = ['jupyterhub-singleuser'] - -## Maximum number of consecutive failures to allow before shutting down -# JupyterHub. -# -# This helps JupyterHub recover from a certain class of problem preventing -# launch in contexts where the Hub is automatically restarted (e.g. systemd, -# docker, kubernetes). -# -# A limit of 0 means no limit and consecutive failures will not be tracked. -# Default: 0 -# c.Spawner.consecutive_failure_limit = 0 - -## Minimum number of cpu-cores a single-user notebook server is guaranteed to -# have available. -# -# If this value is set to 0.5, allows use of 50% of one CPU. If this value is -# set to 2, allows use of up to 2 CPUs. -# -# **This is a configuration setting. Your spawner must implement support for the -# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** -# implement this support. A custom spawner **must** add support for this setting -# for it to be enforced. -# Default: None -# c.Spawner.cpu_guarantee = None - -## Maximum number of cpu-cores a single-user notebook server is allowed to use. -# -# If this value is set to 0.5, allows use of 50% of one CPU. If this value is -# set to 2, allows use of up to 2 CPUs. -# -# The single-user notebook server will never be scheduled by the kernel to use -# more cpu-cores than this. There is no guarantee that it can access this many -# cpu-cores. -# -# **This is a configuration setting. Your spawner must implement support for the -# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** -# implement this support. A custom spawner **must** add support for this setting -# for it to be enforced. -# Default: None -# c.Spawner.cpu_limit = None - -## Enable debug-logging of the single-user server -# Default: False -# c.Spawner.debug = False - -## The URL the single-user server should start in. -# -# `{username}` will be expanded to the user's username -# -# Example uses: -# -# - You can set `notebook_dir` to `/` and `default_url` to `/tree/home/{username}` to allow people to -# navigate the whole filesystem from their notebook server, but still start in their home directory. -# - Start with `/notebooks` instead of `/tree` if `default_url` points to a notebook instead of a directory. -# - You can set this to `/lab` to have JupyterLab start by default, rather than Jupyter Notebook. -# Default: '' -# c.Spawner.default_url = '' - -## Disable per-user configuration of single-user servers. -# -# When starting the user's single-user server, any config file found in the -# user's $HOME directory will be ignored. -# -# Note: a user could circumvent this if the user modifies their Python -# environment, such as when they have their own conda environments / virtualenvs -# / containers. -# Default: False -# c.Spawner.disable_user_config = False - -## List of environment variables for the single-user server to inherit from the -# JupyterHub process. -# -# This list is used to ensure that sensitive information in the JupyterHub -# process's environment (such as `CONFIGPROXY_AUTH_TOKEN`) is not passed to the -# single-user server's process. -# Default: ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] -# c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL', 'JUPYTERHUB_SINGLEUSER_APP'] - -## Extra environment variables to set for the single-user server's process. -# -# Environment variables that end up in the single-user server's process come from 3 sources: -# - This `environment` configurable -# - The JupyterHub process' environment variables that are listed in `env_keep` -# - Variables to establish contact between the single-user notebook and the hub (such as JUPYTERHUB_API_TOKEN) -# -# The `environment` configurable should be set by JupyterHub administrators to -# add installation specific environment variables. It is a dict where the key is -# the name of the environment variable, and the value can be a string or a -# callable. If it is a callable, it will be called with one parameter (the -# spawner instance), and should return a string fairly quickly (no blocking -# operations please!). -# -# Note that the spawner class' interface is not guaranteed to be exactly same -# across upgrades, so if you are using the callable take care to verify it -# continues to work after upgrades! -# -# .. versionchanged:: 1.2 -# environment from this configuration has highest priority, -# allowing override of 'default' env variables, -# such as JUPYTERHUB_API_URL. -# Default: {} -# c.Spawner.environment = {} - -## Timeout (in seconds) before giving up on a spawned HTTP server -# -# Once a server has successfully been spawned, this is the amount of time we -# wait before assuming that the server is unable to accept connections. -# Default: 30 -# c.Spawner.http_timeout = 30 - -## The IP address (or hostname) the single-user server should listen on. -# -# The JupyterHub proxy implementation should be able to send packets to this -# interface. -# Default: '' -# c.Spawner.ip = '' - -## Minimum number of bytes a single-user notebook server is guaranteed to have -# available. -# -# Allows the following suffixes: -# - K -> Kilobytes -# - M -> Megabytes -# - G -> Gigabytes -# - T -> Terabytes -# -# **This is a configuration setting. Your spawner must implement support for the -# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** -# implement this support. A custom spawner **must** add support for this setting -# for it to be enforced. -# Default: None -# c.Spawner.mem_guarantee = None - -## Maximum number of bytes a single-user notebook server is allowed to use. -# -# Allows the following suffixes: -# - K -> Kilobytes -# - M -> Megabytes -# - G -> Gigabytes -# - T -> Terabytes -# -# If the single user server tries to allocate more memory than this, it will -# fail. There is no guarantee that the single-user notebook server will be able -# to allocate this much memory - only that it can not allocate more than this. -# -# **This is a configuration setting. Your spawner must implement support for the -# limit to work.** The default spawner, `LocalProcessSpawner`, does **not** -# implement this support. A custom spawner **must** add support for this setting -# for it to be enforced. -# Default: None -# c.Spawner.mem_limit = None - -## Path to the notebook directory for the single-user server. -# -# The user sees a file listing of this directory when the notebook interface is -# started. The current interface does not easily allow browsing beyond the -# subdirectories in this directory's tree. -# -# `~` will be expanded to the home directory of the user, and {username} will be -# replaced with the name of the user. -# -# Note that this does *not* prevent users from accessing files outside of this -# path! They can do so with many other means. -# Default: '' -# c.Spawner.notebook_dir = '' - -## An HTML form for options a user can specify on launching their server. -# -# The surrounding `` element and the submit button are already provided. -# -# For example: -# -# .. code:: html -# -# Set your key: -# -#
-# Choose a letter: -# -# -# The data from this form submission will be passed on to your spawner in -# `self.user_options` -# -# Instead of a form snippet string, this could also be a callable that takes as -# one parameter the current spawner instance and returns a string. The callable -# will be called asynchronously if it returns a future, rather than a str. Note -# that the interface of the spawner class is not deemed stable across versions, -# so using this functionality might cause your JupyterHub upgrades to break. -# Default: traitlets.Undefined -# c.Spawner.options_form = traitlets.Undefined - -## Interpret HTTP form data -# -# Form data will always arrive as a dict of lists of strings. Override this -# function to understand single-values, numbers, etc. -# -# This should coerce form data into the structure expected by self.user_options, -# which must be a dict, and should be JSON-serializeable, though it can contain -# bytes in addition to standard JSON data types. -# -# This method should not have any side effects. Any handling of `user_options` -# should be done in `.start()` to ensure consistent behavior across servers -# spawned via the API and form submission page. -# -# Instances will receive this data on self.user_options, after passing through -# this function, prior to `Spawner.start`. -# -# .. versionchanged:: 1.0 -# user_options are persisted in the JupyterHub database to be reused -# on subsequent spawns if no options are given. -# user_options is serialized to JSON as part of this persistence -# (with additional support for bytes in case of uploaded file data), -# and any non-bytes non-jsonable values will be replaced with None -# if the user_options are re-used. -# Default: traitlets.Undefined -# c.Spawner.options_from_form = traitlets.Undefined - -## Interval (in seconds) on which to poll the spawner for single-user server's -# status. -# -# At every poll interval, each spawner's `.poll` method is called, which checks -# if the single-user server is still running. If it isn't running, then -# JupyterHub modifies its own state accordingly and removes appropriate routes -# from the configurable proxy. -# Default: 30 -# c.Spawner.poll_interval = 30 - -## The port for single-user servers to listen on. -# -# Defaults to `0`, which uses a randomly allocated port number each time. -# -# If set to a non-zero value, all Spawners will use the same port, which only -# makes sense if each server is on a different address, e.g. in containers. -# -# New in version 0.7. -# Default: 0 -# c.Spawner.port = 0 - -## An optional hook function that you can implement to do work after the spawner -# stops. -# -# This can be set independent of any concrete spawner implementation. -# Default: None -# c.Spawner.post_stop_hook = None - -## An optional hook function that you can implement to do some bootstrapping work -# before the spawner starts. For example, create a directory for your user or -# load initial content. -# -# This can be set independent of any concrete spawner implementation. -# -# This maybe a coroutine. -# -# Example:: -# -# from subprocess import check_call -# def my_hook(spawner): -# username = spawner.user.name -# check_call(['./examples/bootstrap-script/bootstrap.sh', username]) -# -# c.Spawner.pre_spawn_hook = my_hook -# Default: None -# c.Spawner.pre_spawn_hook = None - -## List of SSL alt names -# -# May be set in config if all spawners should have the same value(s), or set at -# runtime by Spawner that know their names. -# Default: [] -# c.Spawner.ssl_alt_names = [] - -## Whether to include DNS:localhost, IP:127.0.0.1 in alt names -# Default: True -# c.Spawner.ssl_alt_names_include_local = True - -## Timeout (in seconds) before giving up on starting of single-user server. -# -# This is the timeout for start to return, not the timeout for the server to -# respond. Callers of spawner.start will assume that startup has failed if it -# takes longer than this. start should return when the server process is started -# and its location is known. -# Default: 60 -# c.Spawner.start_timeout = 60 - -#------------------------------------------------------------------------------ -# Authenticator(LoggingConfigurable) configuration -#------------------------------------------------------------------------------ -## Base class for implementing an authentication provider for JupyterHub - -## Set of users that will have admin rights on this JupyterHub. -# -# Admin users have extra privileges: -# - Use the admin panel to see list of users logged in -# - Add / remove users in some authenticators -# - Restart / halt the hub -# - Start / stop users' single-user servers -# - Can access each individual users' single-user server (if configured) -# -# Admin access should be treated the same way root access is. -# -# Defaults to an empty set, in which case no user has admin access. -# Default: set() -c.Authenticator.admin_users = set('iiab-admin') - -## Set of usernames that are allowed to log in. -# -# Use this with supported authenticators to restrict which users can log in. -# This is an additional list that further restricts users, beyond whatever -# restrictions the authenticator has in place. -# -# If empty, does not perform any additional restriction. -# -# .. versionchanged:: 1.2 -# `Authenticator.whitelist` renamed to `allowed_users` -# Default: set() -# c.Authenticator.allowed_users = set() - -## The max age (in seconds) of authentication info before forcing a refresh of -# user auth info. -# -# Refreshing auth info allows, e.g. requesting/re-validating auth tokens. -# -# See :meth:`.refresh_user` for what happens when user auth info is refreshed -# (nothing by default). -# Default: 300 -# c.Authenticator.auth_refresh_age = 300 - -## Automatically begin the login process -# -# rather than starting with a "Login with..." link at `/hub/login` -# -# To work, `.login_url()` must give a URL other than the default `/hub/login`, -# such as an oauth handler or another automatic login handler, registered with -# `.get_handlers()`. -# -# .. versionadded:: 0.8 -# Default: False -# c.Authenticator.auto_login = False - -## Set of usernames that are not allowed to log in. -# -# Use this with supported authenticators to restrict which users can not log in. -# This is an additional block list that further restricts users, beyond whatever -# restrictions the authenticator has in place. -# -# If empty, does not perform any additional restriction. -# -# .. versionadded: 0.9 -# -# .. versionchanged:: 1.2 -# `Authenticator.blacklist` renamed to `blocked_users` -# Default: set() -# c.Authenticator.blocked_users = set() - -## Delete any users from the database that do not pass validation -# -# When JupyterHub starts, `.add_user` will be called on each user in the -# database to verify that all users are still valid. -# -# If `delete_invalid_users` is True, any users that do not pass validation will -# be deleted from the database. Use this if users might be deleted from an -# external system, such as local user accounts. -# -# If False (default), invalid users remain in the Hub's database and a warning -# will be issued. This is the default to avoid data loss due to config changes. -# Default: False -# c.Authenticator.delete_invalid_users = False - -## Enable persisting auth_state (if available). -# -# auth_state will be encrypted and stored in the Hub's database. This can -# include things like authentication tokens, etc. to be passed to Spawners as -# environment variables. -# -# Encrypting auth_state requires the cryptography package. -# -# Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one -# (or more, separated by ;) 32B encryption keys. These can be either base64 or -# hex-encoded. -# -# If encryption is unavailable, auth_state cannot be persisted. -# -# New in JupyterHub 0.8 -# Default: False -# c.Authenticator.enable_auth_state = False - -## An optional hook function that you can implement to do some bootstrapping work -# during authentication. For example, loading user account details from an -# external system. -# -# This function is called after the user has passed all authentication checks -# and is ready to successfully authenticate. This function must return the -# authentication dict reguardless of changes to it. -# -# This maybe a coroutine. -# -# .. versionadded: 1.0 -# -# Example:: -# -# import os, pwd -# def my_hook(authenticator, handler, authentication): -# user_data = pwd.getpwnam(authentication['name']) -# spawn_data = { -# 'pw_data': user_data -# 'gid_list': os.getgrouplist(authentication['name'], user_data.pw_gid) -# } -# -# if authentication['auth_state'] is None: -# authentication['auth_state'] = {} -# authentication['auth_state']['spawn_data'] = spawn_data -# -# return authentication -# -# c.Authenticator.post_auth_hook = my_hook -# Default: None -# c.Authenticator.post_auth_hook = None - -## Force refresh of auth prior to spawn. -# -# This forces :meth:`.refresh_user` to be called prior to launching a server, to -# ensure that auth state is up-to-date. -# -# This can be important when e.g. auth tokens that may have expired are passed -# to the spawner via environment variables from auth_state. -# -# If refresh_user cannot refresh the user auth data, launch will fail until the -# user logs in again. -# Default: False -# c.Authenticator.refresh_pre_spawn = False - -## Dictionary mapping authenticator usernames to JupyterHub users. -# -# Primarily used to normalize OAuth user names to local users. -# Default: {} -# c.Authenticator.username_map = {} - -## Regular expression pattern that all valid usernames must match. -# -# If a username does not match the pattern specified here, authentication will -# not be attempted. -# -# If not set, allow any username. -# Default: '' -# c.Authenticator.username_pattern = '' - -## Deprecated, use `Authenticator.allowed_users` -# Default: set() -# c.Authenticator.whitelist = set() - -#------------------------------------------------------------------------------ -# CryptKeeper(SingletonConfigurable) configuration -#------------------------------------------------------------------------------ -## Encapsulate encryption configuration -# -# Use via the encryption_config singleton below. - -# Default: [] -# c.CryptKeeper.keys = [] - -## The number of threads to allocate for encryption -# Default: 4 -# c.CryptKeeper.n_threads = 4 - -#------------------------------------------------------------------------------ -# Pagination(Configurable) configuration -#------------------------------------------------------------------------------ -## Default number of entries per page for paginated results. -# Default: 100 -# c.Pagination.default_per_page = 100 - -## Maximum number of entries per page for paginated results. -# Default: 250 -# c.Pagination.max_per_page = 250 - -#------------------------------------------------------------------------------ -# Systemdspawner config -#------------------------------------------------------------------------------ -c.SystemdSpawner.dynamic_users = True -c.SystemdSpawner.user_workingdir = '/opt/iiab/notebooks/{USERNAME}' - diff --git a/roles/jupyterhub/defaults/main.yml b/roles/jupyterhub/defaults/main.yml index a859f9946..d4231ae72 100644 --- a/roles/jupyterhub/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,2 +1,4 @@ -jupyterhub_venv: /opt/iiab/jupyterhub +notebook_dir: /opt/iiab/notebook +jupyterhub_venv: /opt/iiab/jupyter +jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub jupyterhub_port: 8000 diff --git a/vars/default_vars.yml b/vars/default_vars.yml index d1fb036e1..c932b98a6 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -564,8 +564,8 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False -jupyter_install: False -jupyter_enabled: False +jupyterhub_install: False +jupyterhub_enabled: False # 9-LOCAL-ADDONS From a17197f087be5c2cce02fbad838f3db532d83a56 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 11 Mar 2021 22:35:27 +0000 Subject: [PATCH 50/62] remaining jupyter->jupyterhub items --- roles/jupyterhub/defaults/main.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/roles/jupyterhub/defaults/main.yml b/roles/jupyterhub/defaults/main.yml index d4231ae72..a859f9946 100644 --- a/roles/jupyterhub/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,4 +1,2 @@ -notebook_dir: /opt/iiab/notebook -jupyterhub_venv: /opt/iiab/jupyter -jupyterhub_url: https://github.com/jupyterhub/the-littlest-jupyterhub +jupyterhub_venv: /opt/iiab/jupyterhub jupyterhub_port: 8000 From 01e9496fcb03a94d3f1eeebf7826eaf32be53f65 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 1 Apr 2021 13:22:04 +0000 Subject: [PATCH 51/62] update README --- roles/jupyterhub/docs/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/roles/jupyterhub/docs/README.md b/roles/jupyterhub/docs/README.md index 2878ebaa6..9285bfa1b 100644 --- a/roles/jupyterhub/docs/README.md +++ b/roles/jupyterhub/docs/README.md @@ -3,4 +3,5 @@ * This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. * Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. * Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. -* Students will not have any priviletes outside of their own folder. +* Students will not have any privileges outside of their own folder. +* They may upload jupyter notebooks from a local machine, and download the current state of their work via a normal browser download. From d0e8e048347bf46c02a2cdb0da9c5cd0c489fe40 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Mon, 12 Apr 2021 04:47:31 +0100 Subject: [PATCH 52/62] seems able to save files -- but storage is not in library as requested --- roles/jupyterhub/templates/jupyterhub-nginx.conf | 2 +- roles/jupyterhub/templates/jupyterhub_config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/jupyterhub/templates/jupyterhub-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf index a9d450c10..32c999261 100644 --- a/roles/jupyterhub/templates/jupyterhub-nginx.conf +++ b/roles/jupyterhub/templates/jupyterhub-nginx.conf @@ -1,7 +1,7 @@ location /jupyterhub { proxy_pass http://127.0.0.1:8000; proxy_set_header X-Real-IP $remote_addr; - #proxy_set_header Host $host; + proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; diff --git a/roles/jupyterhub/templates/jupyterhub_config.py b/roles/jupyterhub/templates/jupyterhub_config.py index 2eba8b290..d78f82f80 100644 --- a/roles/jupyterhub/templates/jupyterhub_config.py +++ b/roles/jupyterhub/templates/jupyterhub_config.py @@ -211,7 +211,7 @@ c.JupyterHub.cookie_secret = b'helloiiabitsrainingb123456789012' ## url for the database. e.g. `sqlite:///jupyterhub.sqlite` # Default: 'sqlite:///jupyterhub.sqlite' -# c.JupyterHub.db_url = 'sqlite:///jupyterhub.sqlite' +c.JupyterHub.db_url = 'sqlite:///{{ jupyterhub_venv }}/jupyterhub.sqlite' ## log all database transactions. This has A LOT of output # Default: False From 9d23766c90b0ca006251999e5ab81a0e6a961494 Mon Sep 17 00:00:00 2001 From: George Hunt Date: Thu, 15 Apr 2021 17:27:33 +0100 Subject: [PATCH 53/62] need jupyterhub_port in default vars --- vars/default_vars.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/vars/default_vars.yml b/vars/default_vars.yml index c932b98a6..853afa608 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -566,6 +566,7 @@ vnstat_enabled: False jupyterhub_install: False jupyterhub_enabled: False +jupyterhub_port: 8000 # 9-LOCAL-ADDONS From 3fe1f66de065d2869316b14e9d9ceffdc7eb2c48 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 15 Apr 2021 18:14:14 +0000 Subject: [PATCH 54/62] Packaging for PR #2719 to promote JupyterHub Notebooks --- roles/6-generic-apps/tasks/main.yml | 5 ++++ roles/jupyterhub/{docs => }/README.md | 9 ++++--- roles/jupyterhub/tasks/main.yml | 25 +++++++++++++++++-- .../templates/gateway/iiab-gen-iptables | 2 +- vars/default_vars.yml | 8 +++--- vars/local_vars_big.yml | 4 +++ vars/local_vars_medium.yml | 4 +++ vars/local_vars_min.yml | 4 +++ 8 files changed, 51 insertions(+), 10 deletions(-) rename roles/jupyterhub/{docs => }/README.md (52%) diff --git a/roles/6-generic-apps/tasks/main.yml b/roles/6-generic-apps/tasks/main.yml index 7e5bc884c..d1bdc56a1 100644 --- a/roles/6-generic-apps/tasks/main.yml +++ b/roles/6-generic-apps/tasks/main.yml @@ -31,6 +31,11 @@ name: gitea when: gitea_install +- name: JUPYTERHUB + include_role: + name: jupyterhub + when: jupyterhub_install + - name: LOKOLE include_role: name: lokole diff --git a/roles/jupyterhub/docs/README.md b/roles/jupyterhub/README.md similarity index 52% rename from roles/jupyterhub/docs/README.md rename to roles/jupyterhub/README.md index 9285bfa1b..92aa09749 100644 --- a/roles/jupyterhub/docs/README.md +++ b/roles/jupyterhub/README.md @@ -1,7 +1,8 @@ -### Jupyter Notebooks on Rpi Server +### JupyterHub programming environment with student Notebooks + * Jupyter Notebooks are widely used in the scientific community. -* This IIAB package permits individal users to start using their own notebook on the server without needing an individual server account. +* This IIAB package permits individual users to start using their own notebook on the server, without needing an individual server account. * Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. -* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. +* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. * Students will not have any privileges outside of their own folder. -* They may upload jupyter notebooks from a local machine, and download the current state of their work via a normal browser download. +* They may upload Jupyter Notebooks from a local machine, and download the current state of their work via a normal browser download. diff --git a/roles/jupyterhub/tasks/main.yml b/roles/jupyterhub/tasks/main.yml index 9090610a0..0ec1045ec 100644 --- a/roles/jupyterhub/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -1,3 +1,24 @@ +# "How do i fail a task in Ansible if the variable contains a boolean value? +# I want to perform input validation for Ansible playbooks" +# https://stackoverflow.com/questions/46664127/how-do-i-fail-a-task-in-ansible-if-the-variable-contains-a-boolean-value-i-want/46667499#46667499 + +# We assume 0-init/tasks/validate_vars.yml has DEFINITELY been run, so no need +# to re-check whether vars are defined here. As Ansible vars cannot be unset: +# https://serverfault.com/questions/856729/how-to-destroy-delete-unset-a-variable-value-in-ansible + +- name: Assert that "jupyterhub_install is sameas true" (boolean not string etc) + assert: + that: jupyterhub_install is sameas true + fail_msg: "PLEASE SET 'jupyterhub_install: True' e.g. IN: /etc/iiab/local_vars.yml" + quiet: yes + +- name: Assert that "jupyterhub_enabled | type_debug == 'bool'" (boolean not string etc) + assert: + that: jupyterhub_enabled | type_debug == 'bool' + fail_msg: "PLEASE GIVE VARIABLE 'jupyterhub_enabled' A PROPER (UNQUOTED) ANSIBLE BOOLEAN VALUE e.g. IN: /etc/iiab/local_vars.yml" + quiet: yes + + - name: Install Jupyter if jupyterhub_installed not defined, e.g. in {{ iiab_state_file }} # /etc/iiab/iiab_state.yml include_tasks: install.yml when: jupyterhub_installed is undefined @@ -14,9 +35,9 @@ value: "{{ item.value | string }}" with_items: - option: name - value: Jupyter + value: JupyterHub - option: description - value: '"Raspberry Pi Jupyter python programming environment"' + value: '"High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing — A New Way to Think About Programming allowing students to integrate science experiments results and program output within their notebook/document/blog."' - option: install value: "{{ jupyterhub_install }}" - option: enabled diff --git a/roles/network/templates/gateway/iiab-gen-iptables b/roles/network/templates/gateway/iiab-gen-iptables index 95d9fea94..8380304fa 100755 --- a/roles/network/templates/gateway/iiab-gen-iptables +++ b/roles/network/templates/gateway/iiab-gen-iptables @@ -159,7 +159,7 @@ if [ "$wan" != "none" ]; then $IPTABLES -A INPUT -p tcp --dport $sugarizer_port -m state --state NEW -i $wan -j ACCEPT $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT - $IPTABLES -A INPUT -p tcp --dport $transmission_http_port -m state --state NEW -i $wan -j ACCEPT + $IPTABLES -A INPUT -p tcp --dport $transmission_peer_port -m state --state NEW -i $wan -j ACCEPT $IPTABLES -A INPUT -p tcp --dport $jupyterhub_port -m state --state NEW -i $wan -j ACCEPT fi diff --git a/vars/default_vars.yml b/vars/default_vars.yml index 853afa608..87dfd0444 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -380,6 +380,11 @@ gitea_enabled: False gitea_url: /gitea gitea_port: 61734 +# JupyterHub programming environment with student Notebooks +jupyterhub_install: False +jupyterhub_enabled: False +jupyterhub_port: 8000 + # Lokole (email for rural communities) from https://ascoderu.ca lokole_install: False lokole_enabled: False @@ -564,9 +569,6 @@ phpmyadmin_enabled: False vnstat_install: False vnstat_enabled: False -jupyterhub_install: False -jupyterhub_enabled: False -jupyterhub_port: 8000 # 9-LOCAL-ADDONS diff --git a/vars/local_vars_big.yml b/vars/local_vars_big.yml index 3c244b915..e9fe79195 100644 --- a/vars/local_vars_big.yml +++ b/vars/local_vars_big.yml @@ -253,6 +253,10 @@ elgg_enabled: True gitea_install: True gitea_enabled: True +# JupyterHub programming environment with student Notebooks +jupyterhub_install: True +jupyterhub_enabled: True + # Lokole (email for rural communities) from https://ascoderu.ca lokole_install: True lokole_enabled: True diff --git a/vars/local_vars_medium.yml b/vars/local_vars_medium.yml index 887b0a165..e201b0669 100644 --- a/vars/local_vars_medium.yml +++ b/vars/local_vars_medium.yml @@ -253,6 +253,10 @@ elgg_enabled: False gitea_install: False gitea_enabled: False +# JupyterHub programming environment with student Notebooks +jupyterhub_install: False +jupyterhub_enabled: False + # Lokole (email for rural communities) from https://ascoderu.ca lokole_install: False lokole_enabled: False diff --git a/vars/local_vars_min.yml b/vars/local_vars_min.yml index 10dab276c..db25fa66d 100644 --- a/vars/local_vars_min.yml +++ b/vars/local_vars_min.yml @@ -253,6 +253,10 @@ elgg_enabled: False gitea_install: False gitea_enabled: False +# JupyterHub programming environment with student Notebooks +jupyterhub_install: False +jupyterhub_enabled: False + # Lokole (email for rural communities) from https://ascoderu.ca lokole_install: False lokole_enabled: False From f6d42953e71e99f42057e77cf831d025141c0a03 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 15 Apr 2021 18:44:19 +0000 Subject: [PATCH 55/62] Refine Docs roles/jupyterhub/README.md & JupyterHub's iiab.ini description --- roles/jupyterhub/README.md | 10 ++++++---- roles/jupyterhub/tasks/main.yml | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/roles/jupyterhub/README.md b/roles/jupyterhub/README.md index 92aa09749..357d4a156 100644 --- a/roles/jupyterhub/README.md +++ b/roles/jupyterhub/README.md @@ -1,8 +1,10 @@ -### JupyterHub programming environment with student Notebooks +## JupyterHub programming environment with student Notebooks + +#### High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing — A New Way to Think About Programming — allowing students to integrate science experiment results and program output within their notebook/document/blog: * Jupyter Notebooks are widely used in the scientific community. -* This IIAB package permits individual users to start using their own notebook on the server, without needing an individual server account. -* Once a user signs in with a user name, and password, these credentials are stored, and are used thereafter to gain access to the user's files. -* Individual folders are created for all student work in the path /var/lib/protected/. Individual students will only be able to see their own work in that directory. +* This IIAB package permits individual users to start using their own notebook on the server (http://box.lan/jupyterhub) without needing an individual server account. +* Once a user signs in with a username and password, these credentials are stored, and are used thereafter to gain access to the user's files. +* Individual folders are created for all student work in the path `/var/lib/protected/` — individual students will only be able to see their own work in that directory. * Students will not have any privileges outside of their own folder. * They may upload Jupyter Notebooks from a local machine, and download the current state of their work via a normal browser download. diff --git a/roles/jupyterhub/tasks/main.yml b/roles/jupyterhub/tasks/main.yml index 0ec1045ec..56807c2ea 100644 --- a/roles/jupyterhub/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -37,7 +37,7 @@ - option: name value: JupyterHub - option: description - value: '"High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing — A New Way to Think About Programming allowing students to integrate science experiments results and program output within their notebook/document/blog."' + value: '"High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing — A New Way to Think About Programming — allowing students to integrate science experiment results and program output within their notebook/document/blog."' - option: install value: "{{ jupyterhub_install }}" - option: enabled From eac3b86097396d78a2776e3d1f2c7b167dd7f793 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 15 Apr 2021 19:21:35 +0000 Subject: [PATCH 56/62] Lint for readability & maintainability --- roles/jupyterhub/defaults/main.yml | 10 ++- roles/jupyterhub/tasks/enable-or-disable.yml | 17 ++--- roles/jupyterhub/tasks/install.yml | 76 +++++++++++-------- roles/jupyterhub/tasks/main.yml | 4 +- .../templates/jupyterhub-nginx.conf | 3 +- vars/default_vars.yml | 1 + 6 files changed, 63 insertions(+), 48 deletions(-) diff --git a/roles/jupyterhub/defaults/main.yml b/roles/jupyterhub/defaults/main.yml index a859f9946..60a53efa4 100644 --- a/roles/jupyterhub/defaults/main.yml +++ b/roles/jupyterhub/defaults/main.yml @@ -1,2 +1,8 @@ -jupyterhub_venv: /opt/iiab/jupyterhub -jupyterhub_port: 8000 +# jupyterhub_install: False +# jupyterhub_enabled: False + +# jupyterhub_venv: /opt/iiab/jupyterhub +# jupyterhub_port: 8000 + +# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml +# If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! diff --git a/roles/jupyterhub/tasks/enable-or-disable.yml b/roles/jupyterhub/tasks/enable-or-disable.yml index aacd9a35d..1c8a720cc 100644 --- a/roles/jupyterhub/tasks/enable-or-disable.yml +++ b/roles/jupyterhub/tasks/enable-or-disable.yml @@ -3,33 +3,28 @@ daemon_reload: yes -# enable or disable -- name: Enable & Restart jupyterhub +- name: Enable & Restart jupyterhub.service systemd: - name: "{{ item }}" + name: jupyterhub enabled: yes state: restarted - with_items: - - jupyterhub.service when: jupyterhub_enabled -- name: Disable jupyterhub +- name: Disable jupyterhub.service systemd: - name: "{{ item }}" + name: jupyterhub enabled: no state: stopped - with_items: - - jupyterhub when: not jupyterhub_enabled -- name: Put the nginx config file in place +- name: 'Install from template: {{ nginx_conf_dir }}/jupyterhub-nginx.conf' template: src: jupyterhub-nginx.conf dest: "{{ nginx_conf_dir }}/" when: jupyterhub_enabled -- name: Disable jupyterhub +- name: Disable {{ nginx_conf_dir }}/jupyterhub-nginx.conf file: path: "{{ nginx_conf_dir }}/jupyterhub-nginx.conf" state: absent diff --git a/roles/jupyterhub/tasks/install.yml b/roles/jupyterhub/tasks/install.yml index baae04456..26ea0cb01 100644 --- a/roles/jupyterhub/tasks/install.yml +++ b/roles/jupyterhub/tasks/install.yml @@ -1,12 +1,3 @@ -- name: Make the directories to hold jupyter config - file: - state: directory - path: '{{ item }}' - with_items: - - '{{ jupyterhub_venv }}/etc/jupyter' - - '{{ jupyterhub_venv }}/etc/jupyterhub' - - '{{ jupyterhub_venv }}/etc/systemd' - - name: "Set 'nodejs_install: True' and 'nodejs_enabled: True'" set_fact: nodejs_install: True @@ -18,38 +9,61 @@ - name: FAIL (STOP THE INSTALL) IF 'nodejs_installed is undefined' fail: - msg: "Jupyter install cannot proceed, as Node.js is not installed." + msg: "JupyterHub install cannot proceed, as Node.js is not installed." when: nodejs_installed is undefined -- name: use npm to install configurable http proxy - npm: - name: configurable-http-proxy - global: yes - state: latest -- name: Use pip to install into a virtual environment +- name: Make the directories to hold JupyterHub config + file: + state: directory + path: '{{ item }}' + with_items: + - '{{ jupyterhub_venv }}/etc/jupyter' + - '{{ jupyterhub_venv }}/etc/jupyterhub' + - '{{ jupyterhub_venv }}/etc/systemd' + +- name: Use npm to install configurable-http-proxy + npm: + name: configurable-http-proxy + global: yes + state: latest + +- name: 'Use pip to install into a virtual environment: {{ jupyterhub_venv }}' pip: name: - - pip - - wheel - - ipywidgets - - jupyterhub - - jupyterlab - - jupyterhub_firstuseauthenticator - - jupyterhub-systemdspawner + - pip + - wheel + - ipywidgets + - jupyterhub + - jupyterlab + - jupyterhub_firstuseauthenticator + - jupyterhub-systemdspawner virtualenv: "{{ jupyterhub_venv }}" # /opt/iiab/jupyter virtualenv_site_packages: no virtualenv_command: /usr/bin/virtualenv virtualenv_python: python3 extra_args: "--no-cache-dir" when: internet_available - -- name: Install the config file for jupyterhub - template: - src: jupyterhub_config.py - dest: '{{ jupyterhub_venv }}/etc/jupyterhub/' -- name: Use systemd to start jupyterhub +- name: 'Install from template: {{ jupyterhub_venv }}/etc/jupyterhub/jupyterhub_config.py' template: - src: jupyterhub.service - dest: /etc/systemd/system/ + src: jupyterhub_config.py + dest: '{{ jupyterhub_venv }}/etc/jupyterhub/' + +- name: 'Install from template: /etc/systemd/system/jupyterhub.service' + template: + src: jupyterhub.service + dest: /etc/systemd/system/ + + +# RECORD JupyterHub AS INSTALLED + +- name: "Set 'jupyterhub_installed: True'" + set_fact: + jupyterhub_installed: True + +- name: "Add 'jupyterhub_installed: True' to {{ iiab_state_file }}" + lineinfile: + path: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml + regexp: '^jupyterhub_installed' + line: 'jupyterhub_installed: True' diff --git a/roles/jupyterhub/tasks/main.yml b/roles/jupyterhub/tasks/main.yml index 56807c2ea..86460681e 100644 --- a/roles/jupyterhub/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -38,7 +38,7 @@ value: JupyterHub - option: description value: '"High Schools may want to consider JupyterHub to integrate coding with dynamic interactive graphing — A New Way to Think About Programming — allowing students to integrate science experiment results and program output within their notebook/document/blog."' - - option: install + - option: jupyterhub_install value: "{{ jupyterhub_install }}" - - option: enabled + - option: jupyterhub_enabled value: "{{ jupyterhub_enabled }}" diff --git a/roles/jupyterhub/templates/jupyterhub-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf index 32c999261..0c97d4caf 100644 --- a/roles/jupyterhub/templates/jupyterhub-nginx.conf +++ b/roles/jupyterhub/templates/jupyterhub-nginx.conf @@ -1,11 +1,10 @@ -location /jupyterhub { +location /jupyterhub { proxy_pass http://127.0.0.1:8000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; - # websocket headers proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/vars/default_vars.yml b/vars/default_vars.yml index 87dfd0444..ac70d7509 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -383,6 +383,7 @@ gitea_port: 61734 # JupyterHub programming environment with student Notebooks jupyterhub_install: False jupyterhub_enabled: False +jupyterhub_venv: /opt/iiab/jupyterhub jupyterhub_port: 8000 # Lokole (email for rural communities) from https://ascoderu.ca From 67d191be8a9a6f640aced2ecfedc6a49330bb428 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 15 Apr 2021 19:32:11 +0000 Subject: [PATCH 57/62] Update 0-init/tasks/validate_vars.yml w/ JupyterHub --- roles/0-init/tasks/validate_vars.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/roles/0-init/tasks/validate_vars.yml b/roles/0-init/tasks/validate_vars.yml index 25b0fda19..44fac82b8 100644 --- a/roles/0-init/tasks/validate_vars.yml +++ b/roles/0-init/tasks/validate_vars.yml @@ -63,7 +63,7 @@ # # 2020-11-04: Fix validation of 5 core dependencies, for ./runrole etc -- name: Set vars_checklist for 40 + 40 + up-to-40 vars ("XYZ_install" + "XYZ_enabled" + "XYZ_installed") to be checked +- name: Set vars_checklist for 46 + 46 + 41 vars ("XYZ_install" + "XYZ_enabled" + "XYZ_installed") to be checked set_fact: vars_checklist: - hostapd @@ -92,6 +92,7 @@ #- ejabberd # Unmaintained - elgg - gitea + - jupyterhub - lokole - mediawiki - mosquitto From f793f0c230ae2935a0fca7eee082a08ee78d94ba Mon Sep 17 00:00:00 2001 From: root Date: Thu, 15 Apr 2021 19:41:31 +0000 Subject: [PATCH 58/62] Use 'jupyterhub' instead of 'jupyter' in /etc/iiab/iiab.ini --- roles/jupyterhub/tasks/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/jupyterhub/tasks/main.yml b/roles/jupyterhub/tasks/main.yml index 86460681e..01acf8154 100644 --- a/roles/jupyterhub/tasks/main.yml +++ b/roles/jupyterhub/tasks/main.yml @@ -27,10 +27,10 @@ - include_tasks: enable-or-disable.yml -- name: Add 'jupyter' variable values to {{ iiab_ini_file }} +- name: Add 'jupyterhub' variable values to {{ iiab_ini_file }} ini_file: path: "{{ iiab_ini_file }}" # /etc/iiab/iiab.ini - section: jupyter + section: jupyterhub option: "{{ item.option }}" value: "{{ item.value | string }}" with_items: From 19a7af08e5ca777b7e98f8e1f1c97e5229822b33 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 15 Apr 2021 20:16:40 +0000 Subject: [PATCH 59/62] Update roles/nginx/README.md + Lint jupyterhub-nginx.conf --- .../templates/jupyterhub-nginx.conf | 33 ++++++++++--------- roles/nginx/README.md | 5 +-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/roles/jupyterhub/templates/jupyterhub-nginx.conf b/roles/jupyterhub/templates/jupyterhub-nginx.conf index 0c97d4caf..301ab2a41 100644 --- a/roles/jupyterhub/templates/jupyterhub-nginx.conf +++ b/roles/jupyterhub/templates/jupyterhub-nginx.conf @@ -1,19 +1,20 @@ location /jupyterhub { - proxy_pass http://127.0.0.1:8000; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-NginX-Proxy true; + proxy_pass http://127.0.0.1:8000; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; - # websocket headers - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - #proxy_set_header Connection $connection_upgrade; - proxy_set_header X-Scheme $scheme; + # websocket headers + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + #proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Scheme $scheme; - proxy_buffering off; - } - # Managing requests to verify letsencrypt host - location ~ /.well-known { - allow all; - } + proxy_buffering off; +} + +# Managing requests to verify letsencrypt host +location ~ /.well-known { + allow all; +} diff --git a/roles/nginx/README.md b/roles/nginx/README.md index e23a8cbb1..84fa21a1b 100644 --- a/roles/nginx/README.md +++ b/roles/nginx/README.md @@ -10,12 +10,13 @@ 2. Without PHP available via FastCGI, any function at all for PHP-based applications validates NGINX. -3. Current state of IIAB App/Service migrations as of 2020-09-24: +3. Current state of IIAB App/Service migrations as of 2021-04-15: 1. These support "Native" NGINX but ***NOT*** Apache * Admin Console * captiveportal * IIAB documentation (http://box/info) + * JupyterHub * osm-vector-maps * OER2Go/RACHEL modules * usb_lib @@ -54,4 +55,4 @@ * transmission * vnstat -[*] The 4 above starred roles could use improvement, as of 2020-09-24. +[*] The 4 above starred roles could use improvement, as of 2021-04-15. From 5010821b8efd0466b4fbb0e02a798c86a40f9ca1 Mon Sep 17 00:00:00 2001 From: A Holt Date: Fri, 16 Apr 2021 05:30:30 -0400 Subject: [PATCH 60/62] Elgg 2.3.16 -> 2.3.17 --- roles/elgg/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/elgg/defaults/main.yml b/roles/elgg/defaults/main.yml index 66404ba00..24d621f6f 100644 --- a/roles/elgg/defaults/main.yml +++ b/roles/elgg/defaults/main.yml @@ -8,7 +8,7 @@ # If nec, change them by editing /etc/iiab/local_vars.yml prior to installing! elgg_xx: elgg -elgg_version: 2.3.16 +elgg_version: 2.3.17 # elgg_mysql_password: defined in default_vars elgg_url: /elgg From c5a2ac92c6ea98be6e94b5de5a4e42651e9a8e8b Mon Sep 17 00:00:00 2001 From: A Holt Date: Fri, 16 Apr 2021 07:11:46 -0400 Subject: [PATCH 61/62] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 004e10d08..52b213077 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ To learn more about our open community architecture for "offline" education, sta ## Versions -Pre-releases of Internet-in-a-Box (IIAB) undergo continuous QA / continuous deployment and are strongly recommended. +Pre-releases of Internet-in-a-Box (IIAB) undergo continuous QA / continuous deployment and are **strongly recommended!** Install our latest pre-release using the 1-line installer at: [download.iiab.io](http://download.iiab.io/) From b1a7e1d08ab223b5e744be59d4595f25e045cd02 Mon Sep 17 00:00:00 2001 From: A Holt Date: Fri, 16 Apr 2021 07:15:23 -0400 Subject: [PATCH 62/62] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 52b213077..7ae406e37 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ To learn more about our open community architecture for "offline" education, sta ## Versions -Pre-releases of Internet-in-a-Box (IIAB) undergo continuous QA / continuous deployment and are **strongly recommended!** +Pre-releases of Internet-in-a-Box (IIAB) undergo continuous QA / continuous integration / continuous deployment and are **strongly recommended!** Install our latest pre-release using the 1-line installer at: [download.iiab.io](http://download.iiab.io/) -You can also consider the official releases at: [github.com/iiab/iiab/releases](https://github.com/iiab/iiab/releases) +You can also consider earlier official releases at: [github.com/iiab/iiab/releases](https://github.com/iiab/iiab/releases) -For older versions, see: [github.com/xsce](http://github.com/xsce), [schoolserver.org](http://schoolserver.org) +For much older versions, see: [github.com/xsce](http://github.com/xsce), [schoolserver.org](http://schoolserver.org)