Files
ROMFASTSQL/proxmox/cluster/failover/arhiva/recover-vm201-to-pvemini.sh
Claude Agent 0104c255a5 feat(cluster): cluster-shutdown/startup --allow-on-node pentru rulare pe pvemini
Rulare detasata din dashboard/Discord: nssh local fara ssh la sine, CT 171
ramane pornit si moare odata cu pvemini (HA freeze il reporneste), email cu
instructiunile de pornire, pauza si pentru testul DR si fereastra de patch.
Garda CT 171 nu mai depinde de /proc/1/environ (era sarita fara root).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KddsXCqEbKMhdFJDYbAsx8
2026-09-13 10:18:12 +00:00

140 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
# Revenire VM 201 pe pvemini după failover manual
# Deployed la /opt/scripts/recover-vm201-to-pvemini.sh pe pveelite
# Rulează DUPĂ ce pvemini e stabil din nou
set -euo pipefail
VMID=201
PRIMARY=pvemini
PRIMARY_IP=10.0.20.201
SECONDARY=$(hostname)
LOG=/var/log/recover-vm201.log
MAIL_TO=mmarius28@gmail.com
MIN_UPTIME_MIN=30 # pvemini trebuie să fie UP min. 30 min
log() { echo "[$(date '+%F %T')] $*" | tee -a "$LOG"; }
die() { log "ABORT: $*"; exit 1; }
confirm() {
local msg="$1"
if [[ "${FORCE:-}" == "--yes" ]]; then
log "$msg → auto-confirmat (--yes)"
return 0
fi
echo
read -p "$msg (tastează 'DA'): " ANS
[[ "$ANS" == "DA" ]] || die "Anulat la pasul: $msg"
}
[[ "$SECONDARY" == "pveelite" ]] || die "Rulează pe pveelite, nu pe $SECONDARY"
[[ $EUID -eq 0 ]] || die "Trebuie root"
FORCE=${1:-}
log "=== Recovery VM $VMID → $PRIMARY pornit ==="
# === CHECK-URI PRE-RECOVERY ===
# Check 1: VM rulează pe pveelite
if ! qm status "$VMID" 2>/dev/null | grep -q running; then
die "VM $VMID NU rulează pe $SECONDARY. Nu e nimic de recuperat."
fi
log "VM $VMID running pe $SECONDARY ✓"
# Check 2: pvemini reachable + ssh OK
if ! ping -c 3 -W 2 "$PRIMARY_IP" &>/dev/null; then
die "$PRIMARY nu răspunde la ping. Abort."
fi
if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "root@$PRIMARY_IP" 'pvecm status' &>/dev/null; then
die "$PRIMARY nu răspunde la ssh sau nu e în cluster. Abort."
fi
log "$PRIMARY reachable ✓"
# Check 3: uptime pvemini > threshold
UPTIME_SEC=$(ssh "root@$PRIMARY_IP" "cat /proc/uptime | awk '{print int(\$1)}'")
UPTIME_MIN=$((UPTIME_SEC / 60))
log "$PRIMARY uptime: ${UPTIME_MIN} min"
if [[ "$UPTIME_MIN" -lt "$MIN_UPTIME_MIN" ]]; then
die "$PRIMARY uptime doar ${UPTIME_MIN} min (< ${MIN_UPTIME_MIN} min). Așteaptă stabilizare."
fi
# Check 4: errors recente pe pvemini
ERR_COUNT=$(ssh "root@$PRIMARY_IP" "journalctl -p err -b --since '30 min ago' 2>/dev/null | grep -v '^-- ' | wc -l" || echo 0)
log "$PRIMARY erori în ultimele 30 min: $ERR_COUNT"
if [[ "$ERR_COUNT" -gt 50 ]]; then
log "ATENȚIE: $ERR_COUNT erori pe $PRIMARY"
confirm "Continui oricum?"
fi
# Check 5: VM 201 NU există ca running pe pvemini
if ssh "root@$PRIMARY_IP" "qm status $VMID 2>/dev/null | grep -q running"; then
die "VM $VMID rulează deja pe $PRIMARY (split brain!). Oprește manual întâi."
fi
# === EXECUȚIE ===
echo
echo "========================================"
echo "Plan recovery VM $VMID către $PRIMARY:"
echo " 1. Shutdown VM $VMID pe $SECONDARY"
echo " 2. Replicare inversă $SECONDARY → $PRIMARY"
echo " 3. Migrare offline $VMID către $PRIMARY"
echo " 4. Restore replicări normale"
echo " 5. Start VM $VMID pe $PRIMARY"
echo "========================================"
confirm "Pornesc recovery?"
# Pas 1: Shutdown VM 201 pe pveelite
log "Pas 1/5: Shutdown VM $VMID pe $SECONDARY..."
qm shutdown "$VMID" --timeout 120 || die "Shutdown VM eșuat"
sleep 5
qm status "$VMID" | grep -q stopped || die "VM $VMID nu s-a oprit"
log "VM $VMID stopped ✓"
# Pas 2: Job replicare inversă pveelite → pvemini
log "Pas 2/5: Creez replicare inversă $SECONDARY → $PRIMARY..."
if pvesr status | grep -q "^${VMID}-2 "; then
log "Job ${VMID}-2 deja există, îl șterg"
pvesr delete "${VMID}-2" --force 1 || true
sleep 2
fi
pvesr create-local-job "${VMID}-2" "$PRIMARY" --schedule '*/5' --source "$SECONDARY" \
--comment "recovery reverse"
log "Rulez replicare inversă acum (poate dura, depinde de delta)..."
pvesr run --id "${VMID}-2" || die "Replicare inversă eșuată"
log "Replicare inversă OK ✓"
# Pas 3: Migrare offline VM către pvemini
log "Pas 3/5: Migrare offline VM $VMID → $PRIMARY..."
qm migrate "$VMID" "$PRIMARY" || die "Migrare eșuată"
log "Migrare completă ✓"
# Pas 4: Șterge job reverse + verifică replicările normale
log "Pas 4/5: Curăț jobul de replicare inversă..."
pvesr delete "${VMID}-2" --force 1 || true
sleep 2
log "Replicări active:"
pvesr status | grep "^${VMID}-" | tee -a "$LOG"
# Pas 5: Start VM pe pvemini
log "Pas 5/5: Start VM $VMID pe $PRIMARY..."
ssh "root@$PRIMARY_IP" "qm start $VMID" || die "Start pe $PRIMARY eșuat"
sleep 10
PRIMARY_STATUS=$(ssh "root@$PRIMARY_IP" "qm status $VMID" | awk '{print $2}')
log "VM $VMID pe $PRIMARY: $PRIMARY_STATUS"
# Mail confirmare
{
echo "Recovery VM $VMID complet la $(date)"
echo
echo "$SECONDARY → $PRIMARY migrare reușită."
echo "Status VM pe $PRIMARY: $PRIMARY_STATUS"
echo
echo "Replicări active:"
pvesr status | grep "^${VMID}-"
echo
echo "Verifică aplicația Windows pe 10.0.20.201 (IIS etc)."
} | mail -r 'ups@romfast.ro' -s "[OK] Recovery VM $VMID pe $PRIMARY" "$MAIL_TO"
log "=== Recovery complet ==="