198 lines
7.9 KiB
Bash
Executable file
198 lines
7.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# scripts/3_cleanup.sh — Step 3: Post-migration cleanup
|
|
# Run ONLY after verifying that the Docker deployment is working correctly.
|
|
# Frees disk space by removing build artifacts and source files now in volumes.
|
|
#
|
|
# Usage:
|
|
# bash 3_cleanup.sh # interactive — prompts before each rm
|
|
# bash 3_cleanup.sh --yes # skip confirmation prompts (use with care)
|
|
set -euo pipefail
|
|
|
|
REPO_DIR="/opt/sandbox-notebookllamalm-nextjs"
|
|
VOLUME_PREFIX="sandbox-notebookllamalm-nextjs_"
|
|
BACKEND_SVC="notebookllama-backend"
|
|
FRONTEND_SVC="notebookllama-frontend"
|
|
BACKEND_PORT=9000
|
|
FRONTEND_PORT=4000
|
|
AUTO_YES=false
|
|
|
|
# ── Parse args ────────────────────────────────────────────────────────────────
|
|
for arg in "$@"; do
|
|
[[ "$arg" == "--yes" ]] && AUTO_YES=true
|
|
done
|
|
|
|
# ── Colors ──────────────────────────────────────────────────────────────────
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
|
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
step() { echo -e "\n${CYAN}══ $* ${NC}"; }
|
|
|
|
# ── Confirm helper ────────────────────────────────────────────────────────────
|
|
confirm() {
|
|
local prompt="$1"
|
|
if $AUTO_YES; then
|
|
info "${prompt} — auto-confirmed (--yes)"
|
|
return 0
|
|
fi
|
|
echo -en "${YELLOW}${prompt} [y/N]: ${NC}"
|
|
read -r answer
|
|
[[ "$answer" =~ ^[Yy]$ ]]
|
|
}
|
|
|
|
cd "$REPO_DIR"
|
|
|
|
# ── Step 1: Verify all containers are running ─────────────────────────────────
|
|
step "1 / Verify Docker containers"
|
|
|
|
EXPECTED_SERVICES=(postgres redis backend frontend)
|
|
ALL_RUNNING=true
|
|
|
|
for svc in "${EXPECTED_SERVICES[@]}"; do
|
|
STATUS=$(docker compose ps --format '{{.Service}} {{.State}}' 2>/dev/null \
|
|
| grep "^${svc} " | awk '{print $2}' || echo "missing")
|
|
if [[ "$STATUS" == "running" ]]; then
|
|
info " ${svc}: running"
|
|
else
|
|
error " ${svc}: ${STATUS:-not found}"
|
|
ALL_RUNNING=false
|
|
fi
|
|
done
|
|
|
|
if ! $ALL_RUNNING; then
|
|
error "Not all containers are running. Fix the deployment before cleaning up."
|
|
echo " docker compose ps"
|
|
exit 1
|
|
fi
|
|
|
|
# Double-check via HTTP
|
|
check_alive() {
|
|
local name="$1"; local url="$2"
|
|
local code
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>/dev/null || echo "000")
|
|
if [[ "$code" == "200" ]]; then
|
|
info " ${name}: HTTP 200 OK"
|
|
else
|
|
warn " ${name}: HTTP ${code} — proceeding anyway (container is up)"
|
|
fi
|
|
}
|
|
check_alive "Backend" "http://localhost:${BACKEND_PORT}/api/health"
|
|
check_alive "Frontend" "http://localhost:${FRONTEND_PORT}/notebookllama"
|
|
|
|
# ── Step 2: Verify data in podcasts_data volume ────────────────────────────────
|
|
step "2 / Verify data in Docker volumes"
|
|
|
|
PODCASTS_VOLUME="${VOLUME_PREFIX}podcasts_data"
|
|
UPLOADS_VOLUME="${VOLUME_PREFIX}uploads_data"
|
|
|
|
VOL_MP3=$(docker run --rm -v "${PODCASTS_VOLUME}:/d:ro" alpine \
|
|
sh -c 'find /d -name "*.mp3" | wc -l' 2>/dev/null || echo "0")
|
|
SRC_MP3=$(find backend/conversations -name '*.mp3' 2>/dev/null | wc -l | tr -d ' ')
|
|
|
|
info "podcasts_data volume: ${VOL_MP3} MP3 file(s)"
|
|
info "backend/conversations source: ${SRC_MP3} MP3 file(s)"
|
|
|
|
if [[ "$VOL_MP3" -lt "$SRC_MP3" ]]; then
|
|
error "Volume has fewer MP3s (${VOL_MP3}) than source (${SRC_MP3}). Copy may be incomplete."
|
|
error "Aborting cleanup. Re-run 2_deploy.sh or copy manually."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$SRC_MP3" -gt 0 && "$VOL_MP3" -ge "$SRC_MP3" ]]; then
|
|
info "Volume data matches source — safe to remove source files"
|
|
elif [[ "$SRC_MP3" -eq 0 ]]; then
|
|
info "No MP3 files in source directory (already cleaned or never populated)"
|
|
fi
|
|
|
|
# ── Step 3: Remove source MP3s (now in volume) ────────────────────────────────
|
|
step "3 / Remove backend/conversations/ (data is in Docker volume)"
|
|
|
|
if [[ -d "backend/conversations" ]] && [[ -n "$(ls -A backend/conversations 2>/dev/null)" ]]; then
|
|
CONV_SIZE=$(du -sh backend/conversations | cut -f1)
|
|
warn "Will delete: backend/conversations/ (${CONV_SIZE})"
|
|
if confirm "Delete backend/conversations/?"; then
|
|
sudo rm -rf backend/conversations/
|
|
info "Deleted backend/conversations/"
|
|
else
|
|
info "Skipped — keeping backend/conversations/"
|
|
fi
|
|
else
|
|
info "backend/conversations/ is empty or does not exist — nothing to remove"
|
|
fi
|
|
|
|
# ── Step 4: Remove build artifacts ────────────────────────────────────────────
|
|
step "4 / Remove build artifacts (Docker builds its own)"
|
|
|
|
remove_dir() {
|
|
local path="$1"
|
|
local label="$2"
|
|
if [[ -d "$path" ]]; then
|
|
local size
|
|
size=$(du -sh "$path" 2>/dev/null | cut -f1)
|
|
warn "Will delete: ${path} (${size}) — ${label}"
|
|
if confirm "Delete ${path}?"; then
|
|
sudo rm -rf "$path"
|
|
info "Deleted ${path}"
|
|
else
|
|
info "Skipped — keeping ${path}"
|
|
fi
|
|
else
|
|
info "${path} does not exist — skipping"
|
|
fi
|
|
}
|
|
|
|
remove_dir "frontend/.next" "Next.js build cache (Docker builds its own)"
|
|
remove_dir "frontend/node_modules" "Node.js deps (Docker installs its own)"
|
|
remove_dir "backend/.venv" "Python virtualenv (Docker uses uv)"
|
|
|
|
# ── Step 5: Prune dangling Docker images ──────────────────────────────────────
|
|
step "5 / Prune dangling Docker images"
|
|
|
|
if confirm "Run docker image prune -f (remove dangling images)?"; then
|
|
docker image prune -f
|
|
info "Dangling images removed"
|
|
else
|
|
info "Skipped image prune"
|
|
fi
|
|
|
|
# ── Step 6: Show freed disk space ────────────────────────────────────────────
|
|
step "6 / Disk usage"
|
|
|
|
df -h /opt
|
|
echo ""
|
|
info "Docker disk usage:"
|
|
docker system df
|
|
|
|
# ── Step 7: Finalize systemd ──────────────────────────────────────────────────
|
|
step "7 / Finalize systemd"
|
|
|
|
for svc in "$BACKEND_SVC" "$FRONTEND_SVC"; do
|
|
if sudo systemctl is-enabled --quiet "$svc" 2>/dev/null; then
|
|
warn "${svc} is still enabled — disabling now..."
|
|
sudo systemctl disable "$svc"
|
|
info " → disabled"
|
|
else
|
|
info "${svc}: already disabled"
|
|
fi
|
|
done
|
|
|
|
sudo systemctl daemon-reload
|
|
info "systemd daemon reloaded"
|
|
|
|
# ── Done ──────────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
info "── Cleanup complete ──────────────────────────────────────────────"
|
|
echo ""
|
|
info "Docker containers (should all be running):"
|
|
docker compose ps
|
|
echo ""
|
|
info "Docker volumes (should still exist):"
|
|
docker volume ls | grep "$VOLUME_PREFIX" || true
|
|
echo ""
|
|
info "Note: .service files in the repository have NOT been deleted."
|
|
echo " They serve as a reference in case you need to roll back to systemd."
|
|
echo ""
|
|
info "Docker containers are configured with 'restart: unless-stopped' and will"
|
|
info "start automatically when the server reboots — no systemd required."
|
|
echo ""
|
|
info "Cleanup finished at $(date)"
|