[refactor] Introduce multi-mode startup and registry-based images
- Replace monolithic build flow with three operating modes: pull (default), local-build, publish - Add version.txt for image tagging and multi-platform builds via buildx (--publish) - Switch builder to tarball-based Quarto install for better cross-platform reliability - Update docker-compose.yml and jupyterhub_config.py to use environment variables for image names, defaulting to registry images - Refactor start-jupyterhub.sh: modular functions for image management, clearer flag handling and error messages - Simplify Readme.md with structured tables instead of dense paragraphs, clarify data persistence and R package workflow
This commit is contained in:
+301
-129
@@ -1,39 +1,61 @@
|
||||
#!/bin/bash
|
||||
|
||||
# JupyterHub startup script for labs
|
||||
# Usage: ./start-jupyterhub.sh [--no-build|--offline] [--force-rebuild] [--stop-server] [--update-lectures] [--build-obidoc]
|
||||
#
|
||||
# Modes (mutually exclusive):
|
||||
# (default) Pull images from registry and start
|
||||
# --local-build Build images locally and start (no push)
|
||||
# --publish Build multi-arch images, push to registry, and start
|
||||
#
|
||||
# Usage: ./start-jupyterhub.sh [mode] [options]
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
DOCKER_DIR="${SCRIPT_DIR}/obijupyterhub/"
|
||||
BUILDER_IMAGE="obijupyterhub-builder:latest"
|
||||
|
||||
REGISTRY="registry.metabarcoding.org/metabarschool"
|
||||
PLATFORMS="linux/amd64,linux/arm64"
|
||||
BUILDX_BUILDER_NAME="obijupyterhub-buildx"
|
||||
|
||||
# Colors for display
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
NC='\033[0m'
|
||||
|
||||
# Operating mode
|
||||
LOCAL_BUILD=false
|
||||
PUBLISH=false
|
||||
|
||||
# Build options (meaningful in --local-build mode)
|
||||
NO_BUILD=false
|
||||
FORCE_REBUILD=false
|
||||
STOP_SERVER=false
|
||||
UPDATE_LECTURES=false
|
||||
BUILD_OBIDOC=false
|
||||
REBUILD_BUILDER=false
|
||||
REBUILD_STUDENT=false
|
||||
REBUILD_HUB=false
|
||||
|
||||
# Actions
|
||||
STOP_SERVER=false
|
||||
UPDATE_LECTURES=false
|
||||
BUILD_OBIDOC=false
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: ./start-jupyterhub.sh [options]
|
||||
Usage: ./start-jupyterhub.sh [mode] [options]
|
||||
|
||||
Options:
|
||||
--no-build | --offline Skip Docker image builds (use existing images)
|
||||
--force-rebuild Rebuild all images without cache
|
||||
Modes (mutually exclusive, default is pull-from-registry):
|
||||
--local-build Build images locally and start (no push to registry)
|
||||
--publish Build multi-arch images, push to registry, and start
|
||||
|
||||
Build options (--local-build only):
|
||||
--no-build | --offline Skip all image operations (use existing local images)
|
||||
--force-rebuild Rebuild all local images without cache
|
||||
--rebuild-builder Force rebuild the builder image only
|
||||
--rebuild-student Force rebuild the student image only
|
||||
--rebuild-hub Force rebuild the JupyterHub image only
|
||||
|
||||
Actions:
|
||||
--stop-server Stop the stack and remove student containers, then exit
|
||||
--update-lectures Rebuild the course website only (no Docker stop/start)
|
||||
--build-obidoc Force rebuild of obidoc documentation
|
||||
@@ -41,70 +63,89 @@ Options:
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
dockercompose=$(which docker-compose || echo 'docker compose')
|
||||
|
||||
dockercompose=$(which docker-compose 2>/dev/null || echo 'docker compose')
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--no-build|--offline) NO_BUILD=true ;;
|
||||
--force-rebuild) FORCE_REBUILD=true ;;
|
||||
--rebuild-builder) REBUILD_BUILDER=true ;;
|
||||
--rebuild-student) REBUILD_STUDENT=true ;;
|
||||
--rebuild-hub) REBUILD_HUB=true ;;
|
||||
--stop-server) STOP_SERVER=true ;;
|
||||
--update-lectures) UPDATE_LECTURES=true ;;
|
||||
--build-obidoc) BUILD_OBIDOC=true ;;
|
||||
--local-build) LOCAL_BUILD=true ;;
|
||||
--publish) PUBLISH=true ;;
|
||||
--no-build|--offline) NO_BUILD=true ;;
|
||||
--force-rebuild) FORCE_REBUILD=true; LOCAL_BUILD=true ;;
|
||||
--rebuild-builder) REBUILD_BUILDER=true; LOCAL_BUILD=true ;;
|
||||
--rebuild-student) REBUILD_STUDENT=true; LOCAL_BUILD=true ;;
|
||||
--rebuild-hub) REBUILD_HUB=true; LOCAL_BUILD=true ;;
|
||||
--stop-server) STOP_SERVER=true ;;
|
||||
--update-lectures) UPDATE_LECTURES=true ;;
|
||||
--build-obidoc) BUILD_OBIDOC=true ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown option: $1" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if $LOCAL_BUILD && $PUBLISH; then
|
||||
echo "Error: --local-build and --publish cannot be used together" >&2
|
||||
exit 1
|
||||
fi
|
||||
if $STOP_SERVER && $UPDATE_LECTURES; then
|
||||
echo "Error: --stop-server and --update-lectures cannot be used together" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting JupyterHub for Lab"
|
||||
echo "=============================="
|
||||
echo ""
|
||||
# ---------------------------------------------------------------------------
|
||||
# Image name helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
echo -e "${BLUE}Building the volume directories...${NC}"
|
||||
pushd "${SCRIPT_DIR}/jupyterhub_volumes" >/dev/null
|
||||
mkdir -p caddy/data
|
||||
mkdir -p caddy/config
|
||||
mkdir -p course/bin
|
||||
mkdir -p course/R_packages
|
||||
mkdir -p jupyterhub
|
||||
mkdir -p shared
|
||||
mkdir -p users
|
||||
mkdir -p web/obidoc
|
||||
mkdir -p builder/R_packages
|
||||
popd >/dev/null
|
||||
local_image_name() {
|
||||
case "$1" in
|
||||
hub) echo "jupyterhub-hub:latest" ;;
|
||||
student) echo "jupyterhub-student:latest" ;;
|
||||
builder) echo "obijupyterhub-builder:latest" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
pushd "${DOCKER_DIR}" >/dev/null
|
||||
registry_image_name() {
|
||||
echo "${REGISTRY}/obijupyterhub-$1:${2:-latest}"
|
||||
}
|
||||
|
||||
# Check we're in the right directory
|
||||
if [ ! -f "Dockerfile" ] || [ ! -f "docker-compose.yml" ]; then
|
||||
echo "Error: Run this script from the jupyterhub-tp/ directory"
|
||||
exit 1
|
||||
dockerfile_for() {
|
||||
case "$1" in
|
||||
hub) echo "Dockerfile.hub" ;;
|
||||
student) echo "Dockerfile" ;;
|
||||
builder) echo "Dockerfile.builder" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
read_version() {
|
||||
local vfile="${SCRIPT_DIR}/version.txt"
|
||||
if [ ! -f "$vfile" ]; then
|
||||
echo "Error: version.txt not found at ${vfile}" >&2
|
||||
exit 1
|
||||
fi
|
||||
tr -d '[:space:]' < "$vfile"
|
||||
}
|
||||
|
||||
# Set image names based on mode
|
||||
if $LOCAL_BUILD; then
|
||||
BUILDER_IMAGE=$(local_image_name builder)
|
||||
HUB_IMAGE=$(local_image_name hub)
|
||||
STUDENT_IMAGE=$(local_image_name student)
|
||||
else
|
||||
BUILDER_IMAGE=$(registry_image_name builder)
|
||||
HUB_IMAGE=$(registry_image_name hub)
|
||||
STUDENT_IMAGE=$(registry_image_name student)
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Utility
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
get_file_timestamp() {
|
||||
local file="$1"
|
||||
case "$(uname -s)" in
|
||||
Linux)
|
||||
stat -c %Y "$file"
|
||||
;;
|
||||
Darwin)
|
||||
# BSD stat : -f pour format, %m = timestamp modification
|
||||
stat -f %m "$file"
|
||||
;;
|
||||
*)
|
||||
echo "Système non supporté" >&2
|
||||
return 1
|
||||
;;
|
||||
Linux) stat -c %Y "$file" ;;
|
||||
Darwin) stat -f %m "$file" ;;
|
||||
*) echo "Système non supporté" >&2; return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -115,22 +156,21 @@ check_if_image_needs_rebuild() {
|
||||
|
||||
echo -e "${BLUE}Checking image ${image_name}...${NC}"
|
||||
|
||||
# Check if image exists
|
||||
if ! docker image inspect "$image_name" >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Docker image ${image_name} doesn't exist.${NC}"
|
||||
return 0 # Need to build (image doesn't exist)
|
||||
return 0
|
||||
fi
|
||||
|
||||
# If force rebuild (global or per-image), always rebuild
|
||||
if $FORCE_REBUILD || $force; then
|
||||
echo -e "${YELLOW}Docker image build is forced.${NC}"
|
||||
return 0 # Need to rebuild
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Compare Dockerfile modification time with image creation time
|
||||
if [ -f "$dockerfile" ]; then
|
||||
local dockerfile_mtime=$(get_file_timestamp "$dockerfile" 2>/dev/null || echo 0)
|
||||
local image_created=$(docker image inspect "$image_name" --format='{{.Created}}' 2>/dev/null \
|
||||
local dockerfile_mtime
|
||||
dockerfile_mtime=$(get_file_timestamp "$dockerfile" 2>/dev/null || echo 0)
|
||||
local image_created
|
||||
image_created=$(docker image inspect "$image_name" --format='{{.Created}}' 2>/dev/null \
|
||||
| sed -E 's/\.[0-9]+//' \
|
||||
| (read d; if [[ "$(uname -s)" == "Darwin" ]]; then date -ju -f "%Y-%m-%dT%H:%M:%S" "${d%Z}" +%s; else date -d "$d" +%s; fi) 2>/dev/null || echo 0)
|
||||
|
||||
@@ -139,31 +179,138 @@ check_if_image_needs_rebuild() {
|
||||
|
||||
if [ "$dockerfile_mtime" -gt "$image_created" ]; then
|
||||
echo -e "${YELLOW}Dockerfile is newer than image, rebuild needed${NC}"
|
||||
return 0 # Need to rebuild
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1 # No need to rebuild
|
||||
return 1
|
||||
}
|
||||
|
||||
build_builder_image() {
|
||||
if check_if_image_needs_rebuild "$BUILDER_IMAGE" "Dockerfile.builder" "$REBUILD_BUILDER"; then
|
||||
local build_flag=()
|
||||
if $FORCE_REBUILD || $REBUILD_BUILDER; then
|
||||
build_flag+=(--no-cache)
|
||||
fi
|
||||
# ---------------------------------------------------------------------------
|
||||
# Builder image (local-build mode)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
build_builder_image() {
|
||||
if check_if_image_needs_rebuild "$(local_image_name builder)" "Dockerfile.builder" "$REBUILD_BUILDER"; then
|
||||
local build_flag=()
|
||||
if $FORCE_REBUILD || $REBUILD_BUILDER; then build_flag+=(--no-cache); fi
|
||||
echo ""
|
||||
echo -e "${BLUE}Building builder image...${NC}"
|
||||
docker build "${build_flag[@]}" -t "$BUILDER_IMAGE" -f Dockerfile.builder .
|
||||
docker build "${build_flag[@]}" -t "$(local_image_name builder)" -f Dockerfile.builder .
|
||||
else
|
||||
echo -e "${BLUE}Builder image is up to date, skipping build.${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run a command inside the builder container with the workspace mounted
|
||||
# R packages are persisted in jupyterhub_volumes/builder/R_packages
|
||||
# R_LIBS includes both the builder packages (attachment) and the mounted volume
|
||||
# ---------------------------------------------------------------------------
|
||||
# Student + Hub images (local-build mode)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
build_images() {
|
||||
if $NO_BUILD; then
|
||||
echo -e "${YELLOW}Skipping image builds (offline/no-build mode).${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
if check_if_image_needs_rebuild "$(local_image_name student)" "Dockerfile" "$REBUILD_STUDENT"; then
|
||||
local student_flag=()
|
||||
if $FORCE_REBUILD || $REBUILD_STUDENT; then student_flag+=(--no-cache); fi
|
||||
echo ""
|
||||
echo -e "${BLUE}Building student image...${NC}"
|
||||
docker build "${student_flag[@]}" -t "$(local_image_name student)" -f Dockerfile .
|
||||
else
|
||||
echo -e "${BLUE}Student image is up to date, skipping build.${NC}"
|
||||
fi
|
||||
|
||||
if check_if_image_needs_rebuild "$(local_image_name hub)" "Dockerfile.hub" "$REBUILD_HUB"; then
|
||||
local hub_flag=()
|
||||
if $FORCE_REBUILD || $REBUILD_HUB; then hub_flag+=(--no-cache); fi
|
||||
echo ""
|
||||
echo -e "${BLUE}Building JupyterHub image...${NC}"
|
||||
docker build "${hub_flag[@]}" -t "$(local_image_name hub)" -f Dockerfile.hub .
|
||||
else
|
||||
echo -e "${BLUE}JupyterHub image is up to date, skipping build.${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pull images from registry (default mode)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
pull_images() {
|
||||
if $NO_BUILD; then
|
||||
echo -e "${YELLOW}Skipping image pull (offline/no-build mode).${NC}"
|
||||
return
|
||||
fi
|
||||
echo ""
|
||||
echo -e "${BLUE}Pulling images from registry...${NC}"
|
||||
docker pull "$BUILDER_IMAGE"
|
||||
docker pull "$HUB_IMAGE"
|
||||
docker pull "$STUDENT_IMAGE"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Multi-arch build + push to registry (--publish mode)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ensure_buildx_builder() {
|
||||
docker buildx inspect "$BUILDX_BUILDER_NAME" >/dev/null 2>&1 \
|
||||
|| docker buildx create --name "$BUILDX_BUILDER_NAME" --driver docker-container --bootstrap
|
||||
}
|
||||
|
||||
publish_images() {
|
||||
local version
|
||||
version=$(read_version)
|
||||
|
||||
# docker buildx --push uses Docker's own credential store, independent of
|
||||
# skopeo. Verify auth early to get a clear error before a long build.
|
||||
echo -e "${BLUE}Checking registry authentication...${NC}"
|
||||
local registry_host="${REGISTRY%%/*}"
|
||||
if ! docker login "$registry_host" >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Not logged in to ${registry_host}. Running docker login...${NC}"
|
||||
docker login "$registry_host" || {
|
||||
echo "Error: authentication to ${registry_host} failed." >&2
|
||||
echo "Run: docker login ${registry_host}" >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}Publishing images (version ${version}) to ${REGISTRY}${NC}"
|
||||
echo -e "${BLUE}Platforms: ${PLATFORMS}${NC}"
|
||||
|
||||
ensure_buildx_builder
|
||||
|
||||
local names=(builder student hub)
|
||||
local dockerfiles=(Dockerfile.builder Dockerfile Dockerfile.hub)
|
||||
|
||||
for i in "${!names[@]}"; do
|
||||
local name="${names[$i]}"
|
||||
local df="${dockerfiles[$i]}"
|
||||
local remote="${REGISTRY}/obijupyterhub-${name}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}Building and pushing ${name} image...${NC}"
|
||||
docker buildx build \
|
||||
--builder "$BUILDX_BUILDER_NAME" \
|
||||
--platform "$PLATFORMS" \
|
||||
--tag "${remote}:latest" \
|
||||
--tag "${remote}:${version}" \
|
||||
--file "${df}" \
|
||||
--push \
|
||||
.
|
||||
echo -e "${GREEN} ${remote}:latest${NC}"
|
||||
echo -e "${GREEN} ${remote}:${version}${NC}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}All images published (version ${version}).${NC}"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Builder container (for website / docs)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
run_in_builder() {
|
||||
docker run --rm \
|
||||
-v "${SCRIPT_DIR}:/workspace" \
|
||||
@@ -174,45 +321,39 @@ run_in_builder() {
|
||||
bash -c "$1"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stack management
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
stop_stack() {
|
||||
echo -e "${BLUE}Stopping existing containers...${NC}"
|
||||
${dockercompose} down 2>/dev/null || true
|
||||
HUB_IMAGE="$HUB_IMAGE" STUDENT_IMAGE="$STUDENT_IMAGE" \
|
||||
${dockercompose} down 2>/dev/null || true
|
||||
|
||||
echo -e "${BLUE}Cleaning up student containers...${NC}"
|
||||
docker ps -aq --filter name=jupyter- | xargs -r docker rm -f 2>/dev/null || true
|
||||
}
|
||||
|
||||
build_images() {
|
||||
if $NO_BUILD; then
|
||||
echo -e "${YELLOW}Skipping image builds (offline/no-build mode).${NC}"
|
||||
return
|
||||
fi
|
||||
build_website() {
|
||||
echo ""
|
||||
echo -e "${BLUE}Building web site (in builder container)...${NC}"
|
||||
run_in_builder '
|
||||
set -e
|
||||
echo "-> Detecting and installing R dependencies..."
|
||||
Rscript /workspace/tools/install_quarto_deps.R /workspace/web_src
|
||||
|
||||
# Check and build student image
|
||||
if check_if_image_needs_rebuild "jupyterhub-student:latest" "Dockerfile" "$REBUILD_STUDENT"; then
|
||||
local student_flag=()
|
||||
if $FORCE_REBUILD || $REBUILD_STUDENT; then
|
||||
student_flag+=(--no-cache)
|
||||
fi
|
||||
echo ""
|
||||
echo -e "${BLUE}Building student image...${NC}"
|
||||
docker build "${student_flag[@]}" -t jupyterhub-student:latest -f Dockerfile .
|
||||
else
|
||||
echo -e "${BLUE}Student image is up to date, skipping build.${NC}"
|
||||
fi
|
||||
|
||||
# Check and build JupyterHub image
|
||||
if check_if_image_needs_rebuild "jupyterhub-hub:latest" "Dockerfile.hub" "$REBUILD_HUB"; then
|
||||
local hub_flag=()
|
||||
if $FORCE_REBUILD || $REBUILD_HUB; then
|
||||
hub_flag+=(--no-cache)
|
||||
fi
|
||||
echo ""
|
||||
echo -e "${BLUE}Building JupyterHub image...${NC}"
|
||||
docker build "${hub_flag[@]}" -t jupyterhub-hub:latest -f Dockerfile.hub .
|
||||
else
|
||||
echo -e "${BLUE}JupyterHub image is up to date, skipping build.${NC}"
|
||||
fi
|
||||
echo "-> Rendering Quarto site..."
|
||||
cd /workspace/web_src
|
||||
quarto render
|
||||
find . -name "*.pdf" -print | while read pdfname; do
|
||||
dest="/workspace/jupyterhub_volumes/web/pages/${pdfname}"
|
||||
dirdest=$(dirname "$dest")
|
||||
mkdir -p "$dirdest"
|
||||
cp "$pdfname" "$dest"
|
||||
done
|
||||
python3 /workspace/tools/generate_pdf_galleries.py
|
||||
python3 /workspace/tools/generate_pages_json.py
|
||||
'
|
||||
}
|
||||
|
||||
build_obidoc() {
|
||||
@@ -255,32 +396,11 @@ build_obidoc() {
|
||||
'
|
||||
}
|
||||
|
||||
build_website() {
|
||||
echo ""
|
||||
echo -e "${BLUE}Building web site (in builder container)...${NC}"
|
||||
run_in_builder '
|
||||
set -e
|
||||
echo "-> Detecting and installing R dependencies..."
|
||||
Rscript /workspace/tools/install_quarto_deps.R /workspace/web_src
|
||||
|
||||
echo "-> Rendering Quarto site..."
|
||||
cd /workspace/web_src
|
||||
quarto render
|
||||
find . -name "*.pdf" -print | while read pdfname; do
|
||||
dest="/workspace/jupyterhub_volumes/web/pages/${pdfname}"
|
||||
dirdest=$(dirname "$dest")
|
||||
mkdir -p "$dirdest"
|
||||
cp "$pdfname" "$dest"
|
||||
done
|
||||
python3 /workspace/tools/generate_pdf_galleries.py
|
||||
python3 /workspace/tools/generate_pages_json.py
|
||||
'
|
||||
}
|
||||
|
||||
start_stack() {
|
||||
echo ""
|
||||
echo -e "${BLUE}Starting JupyterHub...${NC}"
|
||||
${dockercompose} up -d --remove-orphans
|
||||
HUB_IMAGE="$HUB_IMAGE" STUDENT_IMAGE="$STUDENT_IMAGE" \
|
||||
${dockercompose} up -d --remove-orphans
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}Waiting for JupyterHub to start...${NC}"
|
||||
@@ -289,13 +409,19 @@ start_stack() {
|
||||
|
||||
print_success() {
|
||||
if docker ps | grep -q jupyterhub; then
|
||||
local version
|
||||
version=$(read_version 2>/dev/null || echo "?")
|
||||
echo ""
|
||||
echo -e "${GREEN}JupyterHub is running!${NC}"
|
||||
echo -e "${GREEN}JupyterHub is running! (version ${version})${NC}"
|
||||
echo ""
|
||||
echo "-------------------------------------------"
|
||||
echo -e "${GREEN}JupyterHub available at: http://localhost:8888${NC}"
|
||||
echo "-------------------------------------------"
|
||||
echo ""
|
||||
echo "Images in use:"
|
||||
echo " Hub: ${HUB_IMAGE}"
|
||||
echo " Student: ${STUDENT_IMAGE}"
|
||||
echo ""
|
||||
echo "Password: metabar2025"
|
||||
echo "Students can connect with any username"
|
||||
echo ""
|
||||
@@ -322,6 +448,38 @@ print_success() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Setup volume directories
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
echo "Starting JupyterHub for Lab"
|
||||
echo "=============================="
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}Building the volume directories...${NC}"
|
||||
pushd "${SCRIPT_DIR}/jupyterhub_volumes" >/dev/null
|
||||
mkdir -p caddy/data
|
||||
mkdir -p caddy/config
|
||||
mkdir -p course/bin
|
||||
mkdir -p course/R_packages
|
||||
mkdir -p jupyterhub
|
||||
mkdir -p shared
|
||||
mkdir -p users
|
||||
mkdir -p web/obidoc
|
||||
mkdir -p builder/R_packages
|
||||
popd >/dev/null
|
||||
|
||||
pushd "${DOCKER_DIR}" >/dev/null
|
||||
|
||||
if [ ! -f "Dockerfile" ] || [ ! -f "docker-compose.yml" ]; then
|
||||
echo "Error: Run this script from the OBIJupyterHub directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main flow
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if $STOP_SERVER; then
|
||||
stop_stack
|
||||
popd >/dev/null
|
||||
@@ -329,15 +487,29 @@ if $STOP_SERVER; then
|
||||
fi
|
||||
|
||||
if $UPDATE_LECTURES; then
|
||||
build_builder_image
|
||||
if $LOCAL_BUILD; then
|
||||
build_builder_image
|
||||
elif ! $NO_BUILD; then
|
||||
docker pull "$BUILDER_IMAGE" 2>/dev/null \
|
||||
|| echo -e "${YELLOW}Could not pull builder image, using local cache.${NC}"
|
||||
fi
|
||||
build_website
|
||||
popd >/dev/null
|
||||
exit 0
|
||||
fi
|
||||
|
||||
stop_stack
|
||||
build_builder_image
|
||||
build_images
|
||||
|
||||
if $PUBLISH; then
|
||||
publish_images
|
||||
pull_images # pull the freshly published images into the local daemon
|
||||
elif $LOCAL_BUILD; then
|
||||
build_builder_image
|
||||
build_images
|
||||
else
|
||||
pull_images # default: pull from registry
|
||||
fi
|
||||
|
||||
build_website
|
||||
build_obidoc
|
||||
start_stack
|
||||
|
||||
Reference in New Issue
Block a user