From c5446783ec377db421c19af08c6edd5b3f5ce202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= <46165813+ericgaspar@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:50:58 +0100 Subject: [PATCH] fix --- conf/app-sudoers | 1 + conf/jupyterhub_config.py | 8 ++-- ...pawner-singleuser\nsudospawner-singleuser" | 12 +++++ conf/systemd.service | 1 + hooks/post_user_create | 18 ++++++++ manifest.toml | 7 +++ scripts/change_url | 16 ++++++- scripts/install | 44 ++++++++++++++----- scripts/remove | 2 + scripts/restore | 25 ++++++++++- 10 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 conf/app-sudoers create mode 100644 "conf/sudospawner-singleuser\nsudospawner-singleuser\nsudospawner-singleuser" create mode 100644 hooks/post_user_create diff --git a/conf/app-sudoers b/conf/app-sudoers new file mode 100644 index 0000000..dde8e5e --- /dev/null +++ b/conf/app-sudoers @@ -0,0 +1 @@ +__APP__ ALL=(%__APP__.main) NOPASSWD: __INSTALL_DIR__/.venv/bin/sudospawner \ No newline at end of file diff --git a/conf/jupyterhub_config.py b/conf/jupyterhub_config.py index 71574e7..f8af4a1 100644 --- a/conf/jupyterhub_config.py +++ b/conf/jupyterhub_config.py @@ -171,7 +171,7 @@ c.JupyterHub.bind_url = 'http://:__PORT____PATH__' #c.JupyterHub.cookie_secret_file = 'jupyterhub_cookie_secret' ## The location of jupyterhub data files (e.g. /usr/local/share/jupyterhub) -#c.JupyterHub.data_files_path = '/opt/jupyterlab/.venv/share/jupyterhub' +c.JupyterHub.data_files_path = '__INSTALL_DIR__/.venv/share/jupyterhub' ## Include any kwargs to pass to the database connection. See # sqlalchemy.create_engine for details. @@ -469,7 +469,7 @@ c.ConfigurableHTTPProxy.api_url = 'http://127.0.0.1:__PORT_HTTP_PROXY__' # - default: jupyterhub.spawner.LocalProcessSpawner # - simple: jupyterhub.spawner.SimpleLocalProcessSpawner # - localprocess: jupyterhub.spawner.LocalProcessSpawner -#c.JupyterHub.spawner_class = 'jupyterhub.spawner.LocalProcessSpawner' +c.JupyterHub.spawner_class = 'sudospawner.SudoSpawner' ## Path to SSL certificate file for the public facing interface of the proxy # @@ -685,7 +685,7 @@ c.Spawner.default_url = '/lab' # This whitelist 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. -#c.Spawner.env_keep = ['PATH', 'PYTHONPATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV', 'VIRTUAL_ENV', 'LANG', 'LC_ALL'] +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. # @@ -762,7 +762,7 @@ c.Spawner.default_url = '/lab' # # Note that this does *not* prevent users from accessing files outside of this # path! They can do so with many other means. -#c.Spawner.notebook_dir = '' +c.Spawner.notebook_dir = '~' ## An HTML form for options a user can specify on launching their server. # diff --git "a/conf/sudospawner-singleuser\nsudospawner-singleuser\nsudospawner-singleuser" "b/conf/sudospawner-singleuser\nsudospawner-singleuser\nsudospawner-singleuser" new file mode 100644 index 0000000..dfd9b9d --- /dev/null +++ "b/conf/sudospawner-singleuser\nsudospawner-singleuser\nsudospawner-singleuser" @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e + +if [ __ENABLE_EXTENSIONS__ -eq 1 ]; then + export JUPYTERLAB_DIR="$HOME/.local/share/__APP__/lab" + export PATH="__NODEJS_PATH__:$PATH" +fi + + +# Delegate the notebook server launch to the jupyterhub-singleuser script. +# this is how most sudospawner-singleuser scripts should end. +exec "$(dirname "$0")/jupyterhub-singleuser" $@ \ No newline at end of file diff --git a/conf/systemd.service b/conf/systemd.service index 61f2bcc..84d84b2 100644 --- a/conf/systemd.service +++ b/conf/systemd.service @@ -10,6 +10,7 @@ Group=__APP__ WorkingDirectory=__INSTALL_DIR__/ Environment="LC_ALL=C.UTF-8" Environment="LANG=C.UTF-8" +Environment="JUPYTERHUB_SINGLEUSER_APP=jupyter_server.serverapp.ServerApp" Environment="__YNH_NODE_LOAD_PATH__:__INSTALL_DIR__/.venv/bin" ExecStart=__INSTALL_DIR__/.venv/bin/jupyterhub -f __INSTALL_DIR__/config/jupyterhub_config.py --upgrade-db Restart=always diff --git a/hooks/post_user_create b/hooks/post_user_create new file mode 100644 index 0000000..c87255e --- /dev/null +++ b/hooks/post_user_create @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -e + +source /usr/share/yunohost/helpers + +app="${0//.\/50-}" +user=$1 + +install_dir="$(ynh_app_setting_get --app=$app --key=install_dir)" +enable_extensions="$(ynh_app_setting_get --app=$app --key=enable_extensions)" + +ynh_use_nodejs + +if [ $enable_extensions -eq 1 ]; then + export JUPYTERLAB_DIR="$(getent passwd $user | cut -d: -f6)/.local/share/$app/lab" + node_path="$nodejs_path:$(sudo -u $user sh -c 'echo $PATH')" + sudo -u $user env "PATH=$node_path:$PATH" "$install_dir/.venv/bin/jupyter" lab build --app-dir="$JUPYTERLAB_DIR" +fi diff --git a/manifest.toml b/manifest.toml index 2da1482..03b087f 100644 --- a/manifest.toml +++ b/manifest.toml @@ -47,6 +47,13 @@ ram.runtime = "50M" type = "boolean" default = true + [install.enable_extensions] + ask.en = "Allow users to install extensions?" + ask.fr = "Permettre aux utilisateurs d'installer des extensions ?" + type = "boolean" + default = true + + [resources] [resources.ports] main.default = 8080 diff --git a/scripts/change_url b/scripts/change_url index d87c813..e812890 100644 --- a/scripts/change_url +++ b/scripts/change_url @@ -34,7 +34,21 @@ ynh_change_url_nginx_config domain=$new_domain path=${new_path%/} -ynh_add_config --template="../conf/jupyterhub_config.py" --destination="$install_dir/config/jupyterhub_config.py" +mkdir -p "$install_dir/config" + +ynh_use_nodejs +ynh_add_config --template="jupyterhub_config.py" --destination="$install_dir/config/jupyterhub_config.py" +ynh_add_config --template="jupyter_server_config.py" --destination="$install_dir/config/jupyter_server_config.py" +ynh_add_config --template="app-sudoers" --destination="/etc/sudoers.d/$app-sudoers" +ynh_add_config --template="sudospawner-singleuser" --destination="$install_dir/.venv/bin/sudospawner-singleuser" + +chmod 550 "$install_dir/.venv/bin/sudospawner-singleuser" +chown -R $app:$app "$install_dir" +chmod -R g=u,g-w,o-rwx "$install_dir" +setfacl -nR -m g:$app.main:rx -m d:g:$app.main:rx "$install_dir/.venv" +setfacl -n -m g:$app.main:x "$install_dir" +chown root:root "/etc/sudoers.d/$app-sudoers" +chmod 440 "/etc/sudoers.d/$app-sudoers" #================================================= # GENERIC FINALISATION diff --git a/scripts/install b/scripts/install index 9573839..5ebed93 100644 --- a/scripts/install +++ b/scripts/install @@ -26,11 +26,16 @@ python3 -m pip install pipenv #================================================= ynh_script_progression --message="Building app..." -mkdir -p "$install_dir" +# Set permissions to app files +mkdir -p "$install_dir/.venv" +chown -R $app:$app "$install_dir" +chmod -R g=u,g-w,o-rwx "$install_dir" +setfacl -nR -m g:$app.main:rx -m d:g:$app.main:rx "$install_dir/.venv" +setfacl -n -m g:$app.main:x "$install_dir" -pushd $install_dir - mkdir -p .venv - PIPENV_VENV_IN_PROJECT="enabled" PIPENV_SKIP_LOCK=true ynh_exec_warn_less python3 -m pipenv install jupyterlab==$jupyterlab_version jupyterhub notebook jupyterhub-ldapauthenticator pyzmq jupyterlab-language-pack-fr-FR +pushd "$install_dir" + sudo -u $app PIPENV_VENV_IN_PROJECT="enabled" PIPENV_SKIP_LOCK=true python3 -m pipenv install jupyterlab==$jupyterlab_version jupyterhub notebook jupyter-server jupyterhub-ldapauthenticator pyzmq jupyterlab-language-pack-fr-FR sudospawner 2>&1 + sudo -u $app python3 -m pipenv run jupyterhub upgrade-db 2>&1 popd #================================================= @@ -39,15 +44,34 @@ popd ynh_script_progression --message="Adding a configuration file..." mkdir -p "$install_dir/config" - path=${path%/} -ynh_add_config --template="../conf/jupyterhub_config.py" --destination="$install_dir/config/jupyterhub_config.py" -ynh_add_config --template="../conf/jupyter_notebook_config.py" --destination="$install_dir/config/jupyter_notebook_config.py" +ynh_add_config --template="jupyterhub_config.py" --destination="$install_dir/config/jupyterhub_config.py" +ynh_add_config --template="jupyter_server_config.py" --destination="$install_dir/config/jupyter_server_config.py" +ynh_add_config --template="app-sudoers" --destination="/etc/sudoers.d/$app-sudoers" +ynh_add_config --template="sudospawner-singleuser" --destination="$install_dir/.venv/bin/sudospawner-singleuser" -chmod 750 "$install_dir" -chmod -R o-rwx "$install_dir" -chown -R $app:www-data "$install_dir" +chmod 550 "$install_dir/.venv/bin/sudospawner-singleuser" +chown -R $app:$app "$install_dir" +chmod -R g=u,g-w,o-rwx "$install_dir" +setfacl -nR -m g:$app.main:rx -m d:g:$app.main:rx "$install_dir/.venv" +setfacl -n -m g:$app.main:x "$install_dir" +chown root:root "/etc/sudoers.d/$app-sudoers" +chmod 440 "/etc/sudoers.d/$app-sudoers" + +#================================================= +# BUILD USER LABS +#================================================= +ynh_script_progression --message="Building JupyterLab for each user..." --weight=10 + +if [ $enable_extensions -eq 1 ]; then + ynh_use_nodejs + for user in $(ynh_user_list); do + JUPYTERLAB_DIR="$(getent passwd $user | cut -d: -f6)/.local/share/$app/lab" + node_path="$nodejs_path:$(sudo -u $user sh -c 'echo $PATH')" + sudo -u $user env "PATH=$node_path" "$install_dir/.venv/bin/jupyter" lab build --app-dir="$JUPYTERLAB_DIR" + done +fi #================================================= # SYSTEM CONFIGURATION diff --git a/scripts/remove b/scripts/remove index 5336e41..f2bf196 100644 --- a/scripts/remove +++ b/scripts/remove @@ -31,6 +31,8 @@ ynh_remove_nginx_config ynh_remove_nodejs +ynh_secure_remove "/etc/sudoers.d/$app-sudoers" + #================================================= # END OF SCRIPT #================================================= diff --git a/scripts/restore b/scripts/restore index 08d11f0..8a7ff15 100644 --- a/scripts/restore +++ b/scripts/restore @@ -17,8 +17,13 @@ ynh_script_progression --message="Restoring the app main directory..." --weight= ynh_restore_file --origin_path="$install_dir" -chown -R root: $install_dir/ -chown -R $admin: $install_dir/.venv/ +mkdir -p "$install_dir/.venv" + +chown -R $app:$app "$install_dir" +chmod -R g=u,g-w,o-rwx "$install_dir" + +setfacl -nR -m g:$app.main:rx -m d:g:$app.main:rx "$install_dir/.venv" +setfacl -n -m g:$app.main:x "$install_dir" #================================================= # SPECIFIC RESTORATION @@ -45,6 +50,22 @@ systemctl enable $app.service --quiet yunohost service add $app --description="$app daemon" +#================================================= +# RESTORE SUDOERS +#================================================= +ynh_script_progression --message="Restoring sudoers configuration..." --weight=2 + +ynh_restore_file --origin_path="/etc/sudoers.d/$app-sudoers" + +# Set permissions on app files +chmod 550 "$install_dir/.venv/bin/sudospawner-singleuser" +chown -R $app:$app "$install_dir" +chmod -R g=u,g-w,o-rwx "$install_dir" +setfacl -nR -m g:$app.main:rx -m d:g:$app.main:rx "$install_dir/.venv" +setfacl -n -m g:$app.main:x "$install_dir" +chown root:root "/etc/sudoers.d/$app-sudoers" +chmod 440 "/etc/sudoers.d/$app-sudoers" + #================================================= # GENERIC FINALIZATION #=================================================