Files
OBIJupyterHub/start-jupyterhub.sh
2025-11-26 09:47:20 +01:00

227 lines
6.4 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# JupyterHub startup script for labs
# Usage: ./start-jupyterhub.sh [--no-build|--offline] [--force-rebuild] [--stop-server] [--update-lectures] [--build-obidoc]
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DOCKER_DIR="${SCRIPT_DIR}/obijupyterhub/"
# Colors for display
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
NO_BUILD=false
FORCE_REBUILD=false
STOP_SERVER=false
UPDATE_LECTURES=false
BUILD_OBIDOC=false
usage() {
cat <<EOF
Usage: ./start-jupyterhub.sh [options]
Options:
--no-build | --offline Skip Docker image builds (use existing images)
--force-rebuild Rebuild images without cache
--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
-h, --help Show this help
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--no-build|--offline) NO_BUILD=true ;;
--force-rebuild) FORCE_REBUILD=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 $STOP_SERVER && $UPDATE_LECTURES; then
echo "❌ --stop-server and --update-lectures cannot be used together" >&2
exit 1
fi
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
mkdir -p course/bin
mkdir -p course/R_packages
mkdir -p jupyterhub
mkdir -p shared
mkdir -p users
mkdir -p web/obidoc
popd >/dev/null
pushd "${DOCKER_DIR}" >/dev/null
# 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
fi
stop_stack() {
echo -e "${BLUE}📦 Stopping existing containers...${NC}"
docker-compose 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
local build_flag=()
if $FORCE_REBUILD; then
build_flag+=(--no-cache)
fi
echo ""
echo -e "${BLUE}🔨 Building student image...${NC}"
docker build "${build_flag[@]}" -t jupyterhub-student:latest -f Dockerfile .
echo ""
echo -e "${BLUE}🔨 Building JupyterHub image...${NC}"
docker build "${build_flag[@]}" -t jupyterhub-hub:latest -f Dockerfile.hub .
}
build_obidoc() {
local dest="${SCRIPT_DIR}/jupyterhub_volumes/web/obidoc"
if $NO_BUILD; then
echo -e "${YELLOW}⏭️ Skipping obidoc build in offline/no-build mode.${NC}"
return
fi
local needs_build=false
if $BUILD_OBIDOC; then
needs_build=true
elif [ -z "$(ls -A "$dest" 2>/dev/null)" ]; then
needs_build=true
fi
if ! $needs_build; then
echo -e "${BLUE} obidoc already present; skipping rebuild (use --build-obidoc to force).${NC}"
return
fi
echo ""
echo -e "${BLUE}🔨 Building obidoc documentation...${NC}"
BUILD_DIR=$(mktemp -d -p .)
pushd "$BUILD_DIR" >/dev/null
git clone --recurse-submodules \
--remote-submodules \
-j 8 \
https://github.com/metabarcoding/obitools4-doc.git
pushd obitools4-doc >/dev/null
hugo -D build --baseURL "/obidoc/"
mkdir -p "$dest"
rm -rf "${dest:?}/"*
mv public/* "$dest"
popd >/dev/null
popd >/dev/null
rm -rf
}
build_website() {
echo ""
echo -e "${BLUE}🔨 Building web site...${NC}"
pushd ../web_src >/dev/null
quarto render
find . -name '*.pdf' -print \
| while read pdfname ; do
dest="../jupyterhub_volumes/web/pages/${pdfname}"
dirdest=$(dirname "$dest")
mkdir -p "$dirdest"
echo "cp '${pdfname}' '${dest}'"
done \
| bash
python3 ../tools/generate_pdf_galleries.py
python3 ../tools/generate_pages_json.py
popd >/dev/null
}
start_stack() {
echo ""
echo -e "${BLUE}🚀 Starting JupyterHub...${NC}"
docker-compose up -d --remove-orphans
echo ""
echo -e "${YELLOW}⏳ Waiting for JupyterHub to start...${NC}"
sleep 3
}
print_success() {
if docker ps | grep -q jupyterhub; then
echo ""
echo -e "${GREEN}✅ JupyterHub is running!${NC}"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "${GREEN}🌐 JupyterHub available at: http://localhost:8888${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📝 Password: metabar2025"
echo "👥 Students can connect with any username"
echo ""
echo "🔑 Admin account:"
echo " Username: admin"
echo " Password: admin2025"
echo ""
echo "📂 Each student will have access to:"
echo " - work/ : personal workspace (everything saved)"
echo " - work/R_packages/ : personal R packages (writable)"
echo " - work/shared/ : shared workspace"
echo " - work/course/ : course files (read-only)"
echo " - work/course/R_packages/ : shared R packages by prof (read-only)"
echo " - work/course/bin/ : shared executables (in PATH)"
echo ""
echo "🔍 To view logs: docker-compose logs -f jupyterhub"
echo "🛑 To stop: docker-compose down"
echo ""
else
echo ""
echo -e "${YELLOW}⚠️ JupyterHub container doesn't seem to be starting${NC}"
echo "Check logs with: docker-compose logs jupyterhub"
exit 1
fi
}
if $STOP_SERVER; then
stop_stack
popd >/dev/null
exit 0
fi
if $UPDATE_LECTURES; then
build_website
popd >/dev/null
exit 0
fi
stop_stack
build_images
build_website
build_obidoc
start_stack
popd >/dev/null
print_success