chore: use generic examples in volume-renamer help

This commit is contained in:
stellarshenson
2026-01-06 23:12:59 +01:00
parent 2618f699f5
commit 936fa523ca
5 changed files with 149 additions and 163 deletions

View File

@@ -3,6 +3,6 @@ Additional tools and scripts that help with the hub maintenance
- `certs-installer` - scripts for certificates installation in Root CA Truststore (Windows & Linux)
- `docker_volume_backupper` - script that backs docker volumes (use regex for name)
- `traefik-host-based-routing` - deployment template with local Traefik and self-signed certificates
- `volume-migration` - scripts to rename volumes and migrate user data between usernames
- `volume-renamer` - scripts to rename volumes and migrate user data between usernames

View File

@@ -1,12 +0,0 @@
#!/bin/bash
# List all JupyterHub user volumes
echo "JupyterHub user volumes:"
echo ""
docker volume ls --format '{{.Name}}' | grep -E '^jupyterlab-' | sort | while read -r VOL; do
SIZE=$(docker run --rm -v "$VOL":/data alpine sh -c "du -sh /data 2>/dev/null | cut -f1" 2>/dev/null || echo "?")
printf " %-50s %s\n" "$VOL" "$SIZE"
done
echo ""

View File

@@ -1,76 +0,0 @@
#!/bin/bash
# Migrate all JupyterHub user volumes from one username to another
# Handles: home, workspace, cache volumes
set -e
SCRIPT_DIR="$(dirname "$0")"
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $0 <old-username> <new-username> [--delete-source]"
echo ""
echo "Migrates JupyterHub user volumes:"
echo " - jupyterlab-{username}_home"
echo " - jupyterlab-{username}_workspace"
echo " - jupyterlab-{username}_cache"
echo ""
echo "Options:"
echo " --delete-source Delete source volumes after successful copy"
echo ""
echo "Example:"
echo " $0 john john.doe"
echo " $0 john john.doe --delete-source"
exit 1
fi
OLD_USER="$1"
NEW_USER="$2"
DELETE_FLAG=""
if [ "$3" = "--delete-source" ]; then
DELETE_FLAG="--delete-source"
fi
VOLUME_SUFFIXES="home workspace cache"
echo "Migrating volumes for user: $OLD_USER -> $NEW_USER"
echo ""
# Check which volumes exist
VOLUMES_TO_MIGRATE=""
for SUFFIX in $VOLUME_SUFFIXES; do
SOURCE="jupyterlab-${OLD_USER}_${SUFFIX}"
if docker volume inspect "$SOURCE" >/dev/null 2>&1; then
VOLUMES_TO_MIGRATE="$VOLUMES_TO_MIGRATE $SUFFIX"
echo " Found: $SOURCE"
else
echo " Skip: $SOURCE (not found)"
fi
done
if [ -z "$VOLUMES_TO_MIGRATE" ]; then
echo ""
echo "No volumes found for user: $OLD_USER"
exit 0
fi
echo ""
read -p "Proceed with migration? [y/N] " CONFIRM
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
echo "Aborted"
exit 0
fi
echo ""
# Migrate each volume
for SUFFIX in $VOLUMES_TO_MIGRATE; do
SOURCE="jupyterlab-${OLD_USER}_${SUFFIX}"
TARGET="jupyterlab-${NEW_USER}_${SUFFIX}"
echo "--- Migrating $SUFFIX volume ---"
"$SCRIPT_DIR/rename-volume.sh" "$SOURCE" "$TARGET" $DELETE_FLAG
echo ""
done
echo "User volume migration complete: $OLD_USER -> $NEW_USER"

View File

@@ -1,74 +0,0 @@
#!/bin/bash
# Rename a Docker volume by copying data to a new volume
set -e
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $0 <source-volume> <target-volume> [--delete-source]"
echo ""
echo "Options:"
echo " --delete-source Delete source volume after successful copy"
echo ""
echo "Example:"
echo " $0 jupyterlab-olduser_home jupyterlab-newuser_home"
echo " $0 jupyterlab-olduser_home jupyterlab-newuser_home --delete-source"
exit 1
fi
SOURCE="$1"
TARGET="$2"
DELETE_SOURCE=false
if [ "$3" = "--delete-source" ]; then
DELETE_SOURCE=true
fi
# Check source volume exists
if ! docker volume inspect "$SOURCE" >/dev/null 2>&1; then
echo "ERROR: Source volume '$SOURCE' does not exist"
exit 1
fi
# Check target volume doesn't exist
if docker volume inspect "$TARGET" >/dev/null 2>&1; then
echo "ERROR: Target volume '$TARGET' already exists"
echo "Delete it first or choose a different name"
exit 1
fi
echo "Renaming volume:"
echo " Source: $SOURCE"
echo " Target: $TARGET"
echo ""
# Create target volume
echo "Creating target volume..."
docker volume create "$TARGET"
# Copy data using alpine container
echo "Copying data..."
CONTAINER_NAME="volume_copy_$(date +%s)_$$"
if docker run --rm \
--name "$CONTAINER_NAME" \
-v "$SOURCE":/source:ro \
-v "$TARGET":/target \
alpine \
sh -c "cp -a /source/. /target/"; then
echo "Data copied successfully"
else
echo "ERROR: Copy failed"
docker volume rm "$TARGET" 2>/dev/null || true
exit 1
fi
# Delete source if requested
if [ "$DELETE_SOURCE" = true ]; then
echo "Deleting source volume..."
docker volume rm "$SOURCE"
echo "Source volume deleted"
fi
echo ""
echo "Volume rename complete: $SOURCE -> $TARGET"

View File

@@ -0,0 +1,148 @@
#!/bin/bash
# Rename Docker volumes from one user pattern to another
# Handles Docker's dot-to-hex encoding (. becomes -2e)
set -e
show_help() {
cat << EOF
Usage: $0 [--dry-run] [--keep-orig] <source-pattern> <target-username>
Rename Docker volumes from one user to another (. encoded as -2e).
--dry-run Show mappings without changes
--keep-orig Keep original volumes
Example: $0 --dry-run oldnick first.last
jupyterlab-oldnick_home -> jupyterlab-first-2elast_home
EOF
exit 0
}
# Parse arguments
DRY_RUN=false
KEEP_ORIG=false
POSITIONAL=()
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
DRY_RUN=true
shift
;;
--keep-orig)
KEEP_ORIG=true
shift
;;
-h|--help)
show_help
;;
-*)
echo "Unknown option: $1"
echo "Use --help for usage"
exit 1
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done
# Check required arguments
if [ ${#POSITIONAL[@]} -lt 2 ]; then
show_help
fi
SOURCE_PATTERN="${POSITIONAL[0]}"
TARGET_USER="${POSITIONAL[1]}"
# Encode dots as -2e for Docker volume names
TARGET_ENCODED=$(echo "$TARGET_USER" | sed 's/\./-2e/g')
# Find matching volumes
VOLUMES=$(docker volume ls --format '{{.Name}}' | grep -E "jupyterlab-${SOURCE_PATTERN}[_-]" || true)
if [ -z "$VOLUMES" ]; then
echo "No volumes found matching pattern: jupyterlab-${SOURCE_PATTERN}[_-]*"
exit 0
fi
echo "Volume rename mappings:"
echo ""
# Build mapping list
declare -a SOURCES
declare -a TARGETS
while IFS= read -r VOL; do
# Replace source pattern with encoded target
NEW_VOL=$(echo "$VOL" | sed "s/jupyterlab-${SOURCE_PATTERN}/jupyterlab-${TARGET_ENCODED}/")
SOURCES+=("$VOL")
TARGETS+=("$NEW_VOL")
echo " $VOL"
echo " -> $NEW_VOL"
echo ""
done <<< "$VOLUMES"
if [ "$DRY_RUN" = true ]; then
echo "[DRY RUN] No changes made"
exit 0
fi
echo "---"
if [ "$KEEP_ORIG" = true ]; then
echo "Mode: copy (original volumes will be kept)"
else
echo "Mode: move (original volumes will be deleted)"
fi
echo ""
read -p "Proceed with rename? [y/N] " CONFIRM
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
echo "Aborted"
exit 0
fi
echo ""
# Perform renames
for i in "${!SOURCES[@]}"; do
SOURCE="${SOURCES[$i]}"
TARGET="${TARGETS[$i]}"
echo "Renaming: $SOURCE -> $TARGET"
# Check target doesn't exist
if docker volume inspect "$TARGET" >/dev/null 2>&1; then
echo " ERROR: Target volume already exists, skipping"
continue
fi
# Create target volume
docker volume create "$TARGET" >/dev/null
# Copy data
CONTAINER_NAME="vol_copy_$(date +%s)_$$_$i"
if docker run --rm \
--name "$CONTAINER_NAME" \
-v "$SOURCE":/source:ro \
-v "$TARGET":/target \
alpine \
sh -c "cp -a /source/. /target/" 2>/dev/null; then
echo " Copied successfully"
# Remove original if not keeping
if [ "$KEEP_ORIG" = false ]; then
docker volume rm "$SOURCE" >/dev/null
echo " Original removed"
fi
else
echo " ERROR: Copy failed"
docker volume rm "$TARGET" 2>/dev/null || true
fi
done
echo ""
echo "Done"