70 lines
2.5 KiB
Bash
Executable File
70 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# gitea-backup.sh — Daily Gitea backup to Wasabi S3.
|
|
# Mirrors all repos + dumps the Gitea SQLite DB + config.
|
|
# Schedule: Daily at 4 AM ET via cron (no_agent)
|
|
set -euo pipefail
|
|
|
|
SSH_KEY="/root/.ssh/itpp-infra"
|
|
APP2="root@152.53.39.202"
|
|
S3_BUCKET="s3://hermes-vps-backups/gitea"
|
|
ENDPOINT="https://s3.us-east-1.wasabisys.com"
|
|
TS="$(date -u +%Y%m%d-%H%M%S)"
|
|
STAGE="/tmp/gitea-backup-${TS}"
|
|
TOKEN="1761daa2c537fb72b365e54619208329d8e3ad33"
|
|
RETENTION_DAYS=30
|
|
|
|
if [ -f /opt/awscli-venv/bin/activate ]; then
|
|
source /opt/awscli-venv/bin/activate
|
|
fi
|
|
|
|
log() { echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] $*"; }
|
|
|
|
log "Starting Gitea backup"
|
|
mkdir -p "$STAGE/repos" "$STAGE/db"
|
|
|
|
# 1. Mirror all repos via git clone --mirror
|
|
log "Mirroring repos..."
|
|
REPO_LIST=$(curl -sk "https://git.itpropartner.com/api/v1/user/repos" \
|
|
-H "Authorization: token ${TOKEN}" 2>/dev/null | \
|
|
python3 -c "import json,sys; [print(r['name']) for r in json.load(sys.stdin)]" 2>/dev/null)
|
|
|
|
COUNT=0
|
|
for repo in $REPO_LIST; do
|
|
git clone --mirror "https://ippadmin:${TOKEN}@git.itpropartner.com/ippadmin/${repo}.git" \
|
|
"$STAGE/repos/${repo}.git" >/dev/null 2>&1 && COUNT=$((COUNT+1)) || log "WARN: clone failed for $repo"
|
|
done
|
|
log "Mirrored ${COUNT} repos"
|
|
|
|
# 2. Dump Gitea DB + config from app2
|
|
log "Backing up Gitea DB..."
|
|
ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=yes "$APP2" \
|
|
"docker cp gitea:/data/gitea/gitea.db /tmp/gitea.db && docker cp gitea:/data/gitea/conf/app.ini /tmp/gitea-app.ini" 2>/dev/null
|
|
|
|
scp -q -i "$SSH_KEY" -o BatchMode=yes \
|
|
"$APP2:/tmp/gitea.db" "$STAGE/db/gitea.db" 2>/dev/null || log "WARN: scp db failed"
|
|
scp -q -i "$SSH_KEY" -o BatchMode=yes \
|
|
"$APP2:/tmp/gitea-app.ini" "$STAGE/db/app.ini" 2>/dev/null || log "WARN: scp config failed"
|
|
|
|
SIZE=$(du -sh "$STAGE" 2>/dev/null | cut -f1)
|
|
log "Staged: ${SIZE}"
|
|
|
|
# 3. Upload to S3
|
|
log "Uploading to S3..."
|
|
aws s3 sync "$STAGE/" "${S3_BUCKET}/daily/${TS}/" \
|
|
--endpoint-url "$ENDPOINT" >/dev/null 2>&1 || { log "FATAL: S3 upload failed"; exit 1; }
|
|
log "Uploaded: ${S3_BUCKET}/daily/${TS}/"
|
|
|
|
# 4. Cleanup old backups
|
|
aws s3 ls "${S3_BUCKET}/daily/" --endpoint-url "$ENDPOINT" 2>/dev/null | \
|
|
awk -v cutoff="$(date -d "${RETENTION_DAYS} days ago" -u +%Y-%m-%d)" \
|
|
'$1 < cutoff {print $2}' | while read -r old; do
|
|
aws s3 rm "${S3_BUCKET}/daily/${old}" --recursive --endpoint-url "$ENDPOINT" >/dev/null 2>&1
|
|
log "Purged: $old"
|
|
done
|
|
|
|
# 5. Cleanup local staging
|
|
ssh -i "$SSH_KEY" -o BatchMode=yes "$APP2" "rm -f /tmp/gitea.db /tmp/gitea-app.ini" 2>/dev/null
|
|
rm -rf "$STAGE"
|
|
|
|
log "Backup complete: ${COUNT} repos"
|