Skip to content

Instantly share code, notes, and snippets.

@darkarnium
Last active July 17, 2022 21:42
Show Gist options
  • Save darkarnium/d56eb29d12dd00a65b83391e42d5604d to your computer and use it in GitHub Desktop.
Save darkarnium/d56eb29d12dd00a65b83391e42d5604d to your computer and use it in GitHub Desktop.
JupyterLab Helper - Installs, configures, and runs JupyterLab in a container.
#!/bin/bash
#
# NOTE: This script enables the JupterLab Extension Manager and installs extensions.
# There are code-execution risks with this, so make sure you only use trusted
# extensions and you're comfortable with these extensions before running!
#
# This script wrappers the JupterLab Docker container. It defines a few Docker volume
# mounts to ensure that JupyterLab configuration and notebooks are persisted between
# restarts.
#
# Additionally, it defines a requirements.txt which is automatically pip installed at
# container start to ensure that all dependencies are available between restarts, and
# installs JupyterLab extensions at the same time.
#
# If the lab container version changes, plugins and their associated Python dependencies
# may need updating.
LAB_CONTAINER="jupyter/base-notebook:lab-3.1.10"
function wait_for_jupyterlab {
while [ 1 ]; do
curl -s -m5 -o /dev/null -f http://127.0.0.1:8888
if [ $? -eq 0 ]; then
break
fi
echo -n "."
sleep 1
done
}
# Ensure the required directory structure exists.
mkdir -p "${PWD}/jupyterlab/work"
mkdir -p "${PWD}/jupyterlab/configuration"
mkdir -p "${PWD}/jupyterlab/start-up"
# Create the requirements list, if not present.
if [ ! -e "${PWD}/jupyterlab/requirements.txt" ]; then
cat > "${PWD}/jupyterlab/requirements.txt" <<EOF
requests
boto3
jmespath
python-lsp-server[all]
black
isort
pandas
jupyterlab-lsp==3.8.1
jupyterlab_code_formatter==1.4.10
jupyterlab_widgets==1.1.1
ipycytoscape==1.3.3
networkx==2.8.4
EOF
fi
# Create the bootstrap script, if not present.
if [ ! -e "${PWD}/jupyterlab/start-up/packages.sh" ]; then
cat > "${PWD}/jupyterlab/start-up/packages.sh" <<EOF
#!/bin/sh
pip install -r /home/jovyan/requirements.txt
jupyter labextension install @ryantam626/jupyterlab_code_formatter@1.4.10
jupyter labextension install @krassowski/jupyterlab-lsp@3.8.1
EOF
chmod a+x "${PWD}/jupyterlab/start-up/packages.sh"
fi
# Flag whether a restart is required after start-up. This is used as some extensions
# require a full restart of JupterLab before they will function. We set this based on
# the installation of configuration, rather than the plugin itself, for simplicity but
# at the cost of accuracy if no configuration is added for a given plugin.
JL_RECONFIG=0
# Install advanced settings, if not present.
CF_SETTINGS="${PWD}/jupyterlab/configuration/lab/user-settings/@ryantam626/jupyterlab_code_formatter/settings.jupyterlab-settings"
NE_SETTINGS="${PWD}/jupyterlab/configuration/lab/user-settings/@jupyterlab/notebook-extension/tracker.jupyterlab-settings"
EM_SETTINGS="${PWD}/jupyterlab/configuration/lab/user-settings/@jupyterlab/extensionmanager-extension/plugin.jupyterlab-settings"
if [ ! -e "${CF_SETTINGS}" ]; then
mkdir -p "`dirname ${CF_SETTINGS}`"
JL_RECONFIG=1
cat > "${CF_SETTINGS}" <<EOF
{
"formatOnSave": true,
"preferences": {
"default_formatter": {
"python": ["isort", "black"]
}
}
}
EOF
fi
if [ ! -e "${NE_SETTINGS}" ]; then
mkdir -p "`dirname ${NE_SETTINGS}`"
JL_RECONFIG=1
cat > "${NE_SETTINGS}" <<EOF
{
"codeCellConfig": {
"rulers": [88]
}
}
EOF
fi
if [ ! -e "${EM_SETTINGS}" ]; then
mkdir -p "`dirname ${EM_SETTINGS}`"
JL_RECONFIG=1
cat > "${EM_SETTINGS}" <<EOF
{
"disclaimed": true
}
EOF
fi
# Attempt to start any existing container.
docker start JupyterLab > /dev/null 2>&1
# No container? Start one.
if [ $? -ne 0 ]; then
docker run \
-itd \
--name JupyterLab \
-p 127.0.0.1:8888:8888 \
-e JUPYTER_ENABLE_LAB=yes \
-e RESTARTABLE=yes \
-u root \
-e GRANT_SUDO=yes \
-v"${PWD}/jupyterlab/work":/home/jovyan/work \
-v"${PWD}/jupyterlab/configuration":/home/jovyan/.jupyter \
-v"${PWD}/jupyterlab/requirements.txt":/home/jovyan/requirements.txt \
-v"${PWD}/jupyterlab/start-up":/usr/local/bin/start-notebook.d/ \
-v /var/run/docker.sock:/var/run/docker.sock \
"${LAB_CONTAINER}"
fi
# Get token and print to STDOUT.
echo -n 'INFO: Waiting for JupyterLab to start...'
wait_for_jupyterlab
echo "DONE"
# If the JupterLab configuration has been changed, restart the container to make sure
# everything is correct.
if [ $JL_RECONFIG -gt 0 ]; then
echo -n 'INFO: JupterLab restarting due to configuration change...'
docker restart JupyterLab > /dev/null 2>&1
wait_for_jupyterlab
fi
echo "DONE"
# Grab the JupyterLab token / URL.
echo -n 'INFO: Fetching JupyterLab token from logs...'
JUPYTER_URL=$(docker logs JupyterLab | grep -Eio 'http.*?token=[0-9a-f]+' | tail -n 1)
echo "DONE"
# Finally good to go!
echo "INFO: JupyterLab available at ${JUPYTER_URL}"
echo 'INFO: Attempting to open JupyterLab in browser...'
if [ -n "$(which open)" ]; then
open "${JUPYTER_URL}"
else
echo "INFO: No 'open' on this system, not opening browser."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment