#!/usr/bin/env bash set -euo pipefail # Gitea restore helper — restores a gitea-dump zip into a running Gitea deployment # # Prerequisites: # - Gitea deployed on the target cluster (Helm chart via ArgoCD) # - kubectl context pointing to the target cluster # - A gitea-dump zip file (from gitea-backup.sh download or CronJob) # # Usage: # ./scripts/gitea-restore.sh # # What it does: # 1. Scales Gitea down to 0 # 2. Restores the PostgreSQL database from gitea-db.sql # 3. Restores Git repositories to the data PVC # 4. Scales Gitea back up NAMESPACE="gitea" DEPLOYMENT="gitea" PG_STATEFULSET="gitea-postgresql" PVC="gitea-shared-storage" HELPER_POD="gitea-restore-helper" HELPER_IMAGE="alpine:3.20" PG_USER="gitea" PG_DB="gitea" DUMP_FILE="${1:?Usage: $0 }" if [ ! -f "$DUMP_FILE" ]; then echo "Error: file not found: $DUMP_FILE" exit 1 fi echo "=== Gitea Restore ===" echo "Dump file: $DUMP_FILE" echo "" # --- Safety prompt --- read -r -p "This will OVERWRITE the Gitea database and repositories on the current cluster. Continue? [y/N] " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "Aborted." exit 0 fi cleanup() { kubectl -n "$NAMESPACE" delete pod "$HELPER_POD" --ignore-not-found --grace-period=0 > /dev/null 2>&1 || true } trap cleanup EXIT # --- Step 1: Extract dump locally --- RESTORE_DIR=$(mktemp -d) echo "" echo "[1/5] Extracting dump..." unzip -q "$DUMP_FILE" -d "$RESTORE_DIR" # Detect SQL dump file (gitea-db.sql or gitea-dump-*.sql) SQL_FILE=$(find "$RESTORE_DIR" -maxdepth 1 -name '*.sql' | head -1) if [ -z "$SQL_FILE" ]; then echo "Error: no .sql file found in dump." rm -rf "$RESTORE_DIR" exit 1 fi # Detect repos — either a "repos" folder or gitea-repo.zip if [ -d "$RESTORE_DIR/repos" ]; then REPOS_SOURCE="dir" REPOS_PATH="$RESTORE_DIR/repos" elif [ -f "$RESTORE_DIR/gitea-repo.zip" ]; then REPOS_SOURCE="zip" REPOS_PATH="$RESTORE_DIR/gitea-repo.zip" else echo "Error: no repos/ directory or gitea-repo.zip found in dump." rm -rf "$RESTORE_DIR" exit 1 fi echo " Found: $(basename "$SQL_FILE") ($(du -h "$SQL_FILE" | cut -f1))" echo " Found: repos ($REPOS_SOURCE)" [ -d "$RESTORE_DIR/data" ] && echo " Found: data/" [ -f "$RESTORE_DIR/app.ini" ] && echo " Found: app.ini (managed by Helm, skipping)" # --- Step 2: Scale down Gitea --- echo "" echo "[2/5] Scaling down Gitea..." kubectl -n "$NAMESPACE" scale deployment "$DEPLOYMENT" --replicas=0 kubectl -n "$NAMESPACE" rollout status deployment "$DEPLOYMENT" --timeout=60s 2>/dev/null || true echo " Waiting for pods to terminate..." kubectl -n "$NAMESPACE" wait --for=delete pod -l app.kubernetes.io/name=gitea --timeout=120s 2>/dev/null || true echo " Gitea is down." # --- Step 3: Restore database --- echo "" echo "[3/5] Restoring database..." # Drop and recreate to ensure clean state kubectl -n "$NAMESPACE" exec "${PG_STATEFULSET}-0" -- \ psql -U "$PG_USER" -d postgres -c "DROP DATABASE IF EXISTS ${PG_DB};" 2>/dev/null kubectl -n "$NAMESPACE" exec "${PG_STATEFULSET}-0" -- \ psql -U "$PG_USER" -d postgres -c "CREATE DATABASE ${PG_DB} OWNER ${PG_USER};" 2>/dev/null kubectl -n "$NAMESPACE" exec -i "${PG_STATEFULSET}-0" -- \ psql -U "$PG_USER" -d "$PG_DB" < "$SQL_FILE" > /dev/null echo " Database restored." # --- Step 4: Restore repositories --- echo "" echo "[4/5] Restoring repositories..." # Need a helper pod on the same node as the PVC (RWO) cleanup kubectl -n "$NAMESPACE" run "$HELPER_POD" --restart=Never \ --image="$HELPER_IMAGE" \ --overrides="{ \"spec\":{ \"containers\":[{ \"name\":\"$HELPER_POD\", \"image\":\"$HELPER_IMAGE\", \"command\":[\"sleep\",\"3600\"], \"volumeMounts\":[{\"name\":\"data\",\"mountPath\":\"/data\"}] }], \"volumes\":[{ \"name\":\"data\", \"persistentVolumeClaim\":{\"claimName\":\"$PVC\"} }] } }" > /dev/null 2>&1 kubectl -n "$NAMESPACE" wait --for=condition=Ready "pod/$HELPER_POD" --timeout=120s > /dev/null 2>&1 # Clear existing repos kubectl -n "$NAMESPACE" exec "$HELPER_POD" -- sh -c "rm -rf /data/gitea/repositories/*" 2>/dev/null || true # Upload repos — tar via stdin since kubectl cp needs tar in the container echo " Uploading repositories..." if [ "$REPOS_SOURCE" = "dir" ]; then # repos/ directory — tar and stream into the PVC tar -cf - -C "$REPOS_PATH" . | kubectl -n "$NAMESPACE" exec -i "$HELPER_POD" -- sh -c "tar -xf - -C /data/gitea/repositories/" else # gitea-repo.zip — stream and extract cat "$REPOS_PATH" | kubectl -n "$NAMESPACE" exec -i "$HELPER_POD" -- sh -c "cat > /tmp/gitea-repo.zip && unzip -q -o /tmp/gitea-repo.zip -d /data/gitea/repositories/ && rm /tmp/gitea-repo.zip" fi # Restore data/ directory (avatars, attachments, LFS, etc.) if present if [ -d "$RESTORE_DIR/data" ]; then echo " Uploading data (avatars, attachments, LFS)..." tar -cf - -C "$RESTORE_DIR/data" . | kubectl -n "$NAMESPACE" exec -i "$HELPER_POD" -- sh -c "tar -xf - -C /data/gitea/" fi # Fix ownership kubectl -n "$NAMESPACE" exec "$HELPER_POD" -- chown -R 1000:1000 /data/gitea/ echo " Repositories restored." # --- Step 5: Scale back up --- echo "" echo "[5/5] Scaling Gitea back up..." kubectl -n "$NAMESPACE" scale deployment "$DEPLOYMENT" --replicas=1 kubectl -n "$NAMESPACE" rollout status deployment "$DEPLOYMENT" --timeout=120s # Cleanup temp dir rm -rf "$RESTORE_DIR" echo "" echo "=== Restore complete ===" echo "Gitea should be back online with restored data." echo "Verify at your Gitea URL that repos and users are present."