Files
weval-l99/wevia-snap-archiver.sh
2026-04-13 12:43:21 +02:00

106 lines
5.0 KiB
Bash
Executable File

#!/bin/bash
# WEVIA Snapshot Archiver v2 — Bash (robust, no Python deps)
# Usage: bash wevia-snap-archiver.sh <snap_id> <tag> <release_name>
# set -e
SNAP_ID="$1"
TAG="$2"
REL_NAME="$3"
HZ="xUcbvWMjkMgetuTU0llazUgB85jc7aQBLMhQ79NZ1Yf7j2TRF598DfNxoVrMnVOj"
GH="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"
LOG="/tmp/snap-$TAG.log"
log() { echo "[$(date +%H:%M:%S)] $1" | tee -a "$LOG"; }
log "=== ARCHIVING SNAPSHOT $SNAP_ID$TAG ==="
# 1. Create temp server
log "Creating temp server..."
RESULT=$(curl -s -X POST "https://api.hetzner.cloud/v1/servers" \
-H "Authorization: Bearer $HZ" -H "Content-Type: application/json" \
-d "{\"name\":\"temp-$TAG\",\"server_type\":\"ccx23\",\"image\":$SNAP_ID,\"location\":\"hel1\",\"start_after_create\":true,\"ssh_keys\":[109134687],\"networks\":[12033255]}")
SRV_ID=$(echo "$RESULT" | python3 -c "import sys,json;print(json.load(sys.stdin)['server']['id'])" 2>/dev/null)
PUB_IP=$(echo "$RESULT" | python3 -c "import sys,json;print(json.load(sys.stdin)['server']['public_net']['ipv4']['ip'])" 2>/dev/null)
log "Server $SRV_ID IP=$PUB_IP"
# 2. Wait for creation (max 20 min)
log "Waiting for server creation..."
for i in $(seq 1 60); do
sleep 20
STATUS=$(curl -s "https://api.hetzner.cloud/v1/servers/$SRV_ID" -H "Authorization: Bearer $HZ" | python3 -c "import sys,json;print(json.load(sys.stdin)['server']['status'])" 2>/dev/null)
PROGRESS=$(curl -s "https://api.hetzner.cloud/v1/servers/$SRV_ID/actions?per_page=3" -H "Authorization: Bearer $HZ" | python3 -c "import sys,json;acts=json.load(sys.stdin)['actions'];print(all(a['status']=='success' for a in acts))" 2>/dev/null)
log " [$i] status=$STATUS done=$PROGRESS"
[ "$PROGRESS" = "True" ] && break
done
# 3. Rescue mode
log "Poweroff..."
curl -s -X POST "https://api.hetzner.cloud/v1/servers/$SRV_ID/actions/poweroff" -H "Authorization: Bearer $HZ" > /dev/null
sleep 25
log "Enable rescue..."
RESCUE_PW=$(curl -s -X POST "https://api.hetzner.cloud/v1/servers/$SRV_ID/actions/enable_rescue" \
-H "Authorization: Bearer $HZ" -H "Content-Type: application/json" \
-d '{"type":"linux64","ssh_keys":[109134687]}' | python3 -c "import sys,json;print(json.load(sys.stdin)['root_password'])" 2>/dev/null)
log "Rescue PW: $RESCUE_PW"
sleep 10
log "Poweron..."
curl -s -X POST "https://api.hetzner.cloud/v1/servers/$SRV_ID/actions/poweron" -H "Authorization: Bearer $HZ" > /dev/null
sleep 90
# 4. SSH to rescue
log "Connecting to rescue..."
CONNECTED=$(sshpass -p "$RESCUE_PW" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=20 root@$PUB_IP 'echo OK' 2>/dev/null)
if [ "$CONNECTED" != "OK" ]; then
log "RESCUE SSH FAILED — retrying in 60s..."
sleep 60
CONNECTED=$(sshpass -p "$RESCUE_PW" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=20 root@$PUB_IP 'echo OK' 2>/dev/null)
fi
if [ "$CONNECTED" != "OK" ]; then
log "FATAL: Cannot connect to rescue. Cleaning up."
curl -s -X DELETE "https://api.hetzner.cloud/v1/servers/$SRV_ID" -H "Authorization: Bearer $HZ" > /dev/null
exit 1
fi
log "CONNECTED! Mounting disk..."
sshpass -p "$RESCUE_PW" ssh -o StrictHostKeyChecking=no root@$PUB_IP 'mkdir -p /mnt/data && mount /dev/sda1 /mnt/data' 2>/dev/null
# 5. Scan + archive
log "Scanning..."
CONTENT=$(sshpass -p "$RESCUE_PW" ssh -o StrictHostKeyChecking=no root@$PUB_IP 'du -sh /mnt/data/opt/* /mnt/data/var/www/* 2>/dev/null | sort -rh | head -20' 2>/dev/null)
log "$CONTENT"
VAULT="/opt/wevads/vault/$TAG"
mkdir -p "$VAULT"
for ARCH in "opt-all:opt/" "www-all:var/www/" "configs:var/spool/cron/ etc/ssh/ root/" "postgresql:var/lib/postgresql/"; do
NAME="${ARCH%%:*}"
PATHS="${ARCH#*:}"
log "Creating $NAME..."
sshpass -p "$RESCUE_PW" ssh -o StrictHostKeyChecking=no root@$PUB_IP "cd /mnt/data && tar czf /tmp/$NAME.tar.gz --exclude='node_modules' --exclude='.git' --exclude='vendor' --exclude='cache' --exclude='.cache' --exclude='.cursor-server' $PATHS 2>/dev/null; ls -lh /tmp/$NAME.tar.gz" 2>/dev/null
log "SCP $NAME to S204..."
sshpass -p "$RESCUE_PW" scp -o StrictHostKeyChecking=no "root@$PUB_IP:/tmp/$NAME.tar.gz" "$VAULT/" 2>/dev/null && log "$NAME OK" || log "$NAME FAILED"
done
log "Archives: $(ls -lh $VAULT/)"
# 6. GitHub release + upload
log "Creating GitHub release $TAG..."
REL_ID=$(curl -s -X POST "https://api.github.com/repos/Yacineutt/weval-archive/releases" \
-H "Authorization: token $GH" -H "Content-Type: application/json" \
-d "{\"tag_name\":\"$TAG\",\"name\":\"$REL_NAME\",\"body\":\"Hetzner snapshot $SNAP_ID\"}" | python3 -c "import sys,json;print(json.load(sys.stdin).get('id',''))" 2>/dev/null)
UPLOAD="https://uploads.github.com/repos/Yacineutt/weval-archive/releases/$REL_ID/assets"
for f in $VAULT/*.tar.gz; do
FNAME=$(basename "$f")
log "Uploading $FNAME..."
curl -s -H "Authorization: token $GH" -H "Content-Type: application/gzip" --data-binary @"$f" "$UPLOAD?name=$FNAME" > /dev/null 2>&1
log "$FNAME uploaded"
done
# 7. Cleanup
log "Deleting temp server $SRV_ID..."
curl -s -X DELETE "https://api.hetzner.cloud/v1/servers/$SRV_ID" -H "Authorization: Bearer $HZ" > /dev/null
log "=== SNAPSHOT $SNAP_ID ARCHIVED → $TAG ==="