feat(failover): add VM 201 manual failover + recovery scripts, watchdog alert
VM 201 (Windows critical) stays out of HA by design. Added: - failover-vm201.sh: interactive failover pvemini -> pveelite with ZFS replication state - recover-vm201-to-pvemini.sh: interactive reverse migration with uptime + split-brain checks - pvemini-down-alert.sh: cron watchdog on pveelite, emails full runbook after 2min DOWN Replication RPO tightened: CT 108 + VM 201 to 5min, CT 171 to 15min. CT 171 added to HA (ha-group-main) for continuous Claude Code access. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
105
proxmox/cluster/failover/README.md
Normal file
105
proxmox/cluster/failover/README.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# Failover & High Availability
|
||||||
|
|
||||||
|
Strategia HA pe cluster, separată pe nivele de criticitate.
|
||||||
|
|
||||||
|
## Rezumat resurse critice
|
||||||
|
|
||||||
|
| Resursă | Criticitate | HA automat | Replicare | RPO |
|
||||||
|
|---------|-------------|------------|-----------|-----|
|
||||||
|
| CT 108 Oracle central | Nivel 0 | Da | pveelite `*/5` min, pve1 `*/5` min | 5 min |
|
||||||
|
| VM 201 Windows roacentral | Nivel 0 | **NU** (failover manual) | pveelite `*/5` min, pve1 `*/5` min | 5 min |
|
||||||
|
| CT 171 claude-agent | Nivel 1 | Da | pveelite `*/15` min, pve1 `*/15` min | 15 min |
|
||||||
|
| CT 104 flowise | Nivel 2 | Da | zilnic 21:15 | 24h |
|
||||||
|
| CT 106 gitea | Nivel 2 | Da | `*/2` ore | 2h |
|
||||||
|
| CT 100 portainer | Nivel 2 | Da | zilnic | 24h |
|
||||||
|
|
||||||
|
## VM 201 — failover manual
|
||||||
|
|
||||||
|
VM 201 (Windows production) **nu este în HA deliberat**. Incident anterior: când pvemini a fost scos temporar din HA pentru mentenanță, VM 201 a migrat automat — comportament nedorit pentru Windows production care cere fereastră de mentenanță controlată.
|
||||||
|
|
||||||
|
### Declanșator alertă
|
||||||
|
|
||||||
|
Cron pe pveelite verifică pvemini la fiecare minut:
|
||||||
|
- Script: `/opt/scripts/pvemini-down-alert.sh`
|
||||||
|
- După 2 minute DOWN consecutive → mail `mmarius28@gmail.com` cu comanda failover ready-to-run
|
||||||
|
|
||||||
|
### Execuție failover
|
||||||
|
|
||||||
|
Din orice sesiune SSH:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@10.0.20.202 /opt/scripts/failover-vm201.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Scriptul:
|
||||||
|
1. Verifică pvemini efectiv DOWN (ping + ssh); abort dacă răspunde
|
||||||
|
2. Verifică VM 201 nu rulează deja pe pveelite
|
||||||
|
3. Afișează ultima replicare ZFS disponibilă local
|
||||||
|
4. Cere confirmare interactivă (tastezi `DA`)
|
||||||
|
5. `qm start 201` pe pveelite
|
||||||
|
6. Trimite mail confirmare cu pași post-failover
|
||||||
|
|
||||||
|
Pentru automatizare (fără prompt):
|
||||||
|
```bash
|
||||||
|
ssh root@10.0.20.202 /opt/scripts/failover-vm201.sh --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### După revenire pvemini — script interactiv
|
||||||
|
|
||||||
|
**NU porni automat VM 201 pe pvemini.** Date posibil divergente.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@10.0.20.202 /opt/scripts/recover-vm201-to-pvemini.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Scriptul verifică:
|
||||||
|
- pvemini uptime min. 30 min + erori recente
|
||||||
|
- pvemini reachable ssh + VM 201 nu rulează deja acolo (anti split-brain)
|
||||||
|
- VM 201 running local pe pveelite
|
||||||
|
|
||||||
|
Pași executați automat (cu confirmare):
|
||||||
|
1. `qm shutdown 201` pe pveelite
|
||||||
|
2. `pvesr create-local-job 201-2 pvemini --source pveelite` + run forțat
|
||||||
|
3. `qm migrate 201 pvemini` offline
|
||||||
|
4. Cleanup job replicare inversă
|
||||||
|
5. `qm start 201` pe pvemini
|
||||||
|
|
||||||
|
Non-interactiv: adaugă `--yes`.
|
||||||
|
|
||||||
|
## CT 108 Oracle — HA automat
|
||||||
|
|
||||||
|
- Group `ha-group-main` (pvemini:100, pveelite:50, pve1:33)
|
||||||
|
- `max_restart 3, max_relocate 2`
|
||||||
|
- Replicare 5 min → failover automat cu RPO 5 min
|
||||||
|
- **Constrângere RAM pveelite 16 GB**: dacă pvemini cade, pveelite trebuie să aibă spațiu pentru CT 108 (8 GB) + CT 101 existent + eventual alte CT-uri HA
|
||||||
|
|
||||||
|
## CT 171 claude-agent — HA automat
|
||||||
|
|
||||||
|
- Adăugat în HA pentru acces Claude Code continuu
|
||||||
|
- Dacă pvemini cade, CT 171 pornește pe pveelite cu ultima replicare (max 15 min în urmă)
|
||||||
|
- State = workspace files din `/workspace/` — replicate ZFS
|
||||||
|
|
||||||
|
## Fișiere relevante
|
||||||
|
|
||||||
|
| Fișier | Locație | Scop |
|
||||||
|
|--------|---------|------|
|
||||||
|
| `failover-vm201.sh` | `/opt/scripts/` pe pveelite | Failover manual VM 201 pvemini → pveelite |
|
||||||
|
| `recover-vm201-to-pvemini.sh` | `/opt/scripts/` pe pveelite | Recovery interactiv VM 201 pveelite → pvemini |
|
||||||
|
| `pvemini-down-alert.sh` | `/opt/scripts/` pe pveelite | Watchdog 1 min, mail dacă pvemini DOWN 2 min |
|
||||||
|
| `oom-alert.sh` | `/opt/scripts/` pe toate nodurile | Alertă OOM kills |
|
||||||
|
|
||||||
|
## Comenzi utile
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stare replicare
|
||||||
|
ssh root@10.0.20.201 "pvesr status"
|
||||||
|
|
||||||
|
# Stare HA
|
||||||
|
ssh root@10.0.20.201 "ha-manager status"
|
||||||
|
|
||||||
|
# Forțează replicare acum (util înainte de mentenanță)
|
||||||
|
ssh root@10.0.20.201 "pvesr run --id 108-1; pvesr run --id 201-1; pvesr run --id 171-1"
|
||||||
|
|
||||||
|
# Test script failover (dry — fără confirmare)
|
||||||
|
ssh root@10.0.20.202 "/opt/scripts/failover-vm201.sh" # va abort dacă pvemini răspunde
|
||||||
|
```
|
||||||
79
proxmox/cluster/failover/failover-vm201.sh
Executable file
79
proxmox/cluster/failover/failover-vm201.sh
Executable file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Manual failover VM 201 (roacentral Windows) către pveelite
|
||||||
|
# Deployed la /opt/scripts/failover-vm201.sh pe pveelite
|
||||||
|
# Folosește ultima replicare ZFS locală
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VMID=201
|
||||||
|
PRIMARY=pvemini
|
||||||
|
PRIMARY_IP=10.0.20.201
|
||||||
|
SECONDARY=$(hostname)
|
||||||
|
LOG=/var/log/failover-vm201.log
|
||||||
|
MAIL_TO=mmarius28@gmail.com
|
||||||
|
|
||||||
|
log() { echo "[$(date '+%F %T')] $*" | tee -a "$LOG"; }
|
||||||
|
die() { log "ABORT: $*"; exit 1; }
|
||||||
|
|
||||||
|
[[ "$SECONDARY" == "pveelite" ]] || die "Rulează pe pveelite, nu pe $SECONDARY"
|
||||||
|
[[ $EUID -eq 0 ]] || die "Trebuie root"
|
||||||
|
|
||||||
|
FORCE=${1:-}
|
||||||
|
|
||||||
|
log "=== Failover VM $VMID pornit ==="
|
||||||
|
|
||||||
|
# Check 1: pvemini efectiv down
|
||||||
|
log "Verific $PRIMARY..."
|
||||||
|
if ping -c 2 -W 2 "$PRIMARY_IP" &>/dev/null; then
|
||||||
|
if ssh -o ConnectTimeout=5 -o BatchMode=yes "root@$PRIMARY_IP" 'pvecm status' &>/dev/null; then
|
||||||
|
die "$PRIMARY răspunde la ping + ssh. NU fac failover. Oprește manual VM 201 pe $PRIMARY înainte."
|
||||||
|
fi
|
||||||
|
log "$PRIMARY ping OK dar ssh fail — posibil degradat"
|
||||||
|
fi
|
||||||
|
log "$PRIMARY confirmat DOWN"
|
||||||
|
|
||||||
|
# Check 2: VM nu rulează deja local
|
||||||
|
if qm status "$VMID" 2>/dev/null | grep -q running; then
|
||||||
|
die "VM $VMID deja running pe $SECONDARY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check 3: discul există local (ultima replicare)
|
||||||
|
if ! zfs list "rpool/data/vm-$VMID-disk-3" &>/dev/null; then
|
||||||
|
die "Disc vm-$VMID-disk-3 lipsește local. Replicare nefuncțională?"
|
||||||
|
fi
|
||||||
|
LAST_SNAP=$(zfs list -t snapshot -o name,creation -s creation "rpool/data/vm-$VMID-disk-3" 2>/dev/null | tail -1)
|
||||||
|
log "Ultima replicare: $LAST_SNAP"
|
||||||
|
|
||||||
|
# Confirmare interactivă
|
||||||
|
if [[ "$FORCE" != "--yes" ]]; then
|
||||||
|
echo
|
||||||
|
echo "========================================"
|
||||||
|
echo "ATENȚIE: VM $VMID va porni pe $SECONDARY"
|
||||||
|
echo "folosind ultima replicare ZFS."
|
||||||
|
echo "Date pierdute = ce s-a scris după $LAST_SNAP"
|
||||||
|
echo "========================================"
|
||||||
|
read -p "Continui? (tastează 'DA' pentru confirmare): " CONFIRM
|
||||||
|
[[ "$CONFIRM" == "DA" ]] || die "Anulat de utilizator"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start
|
||||||
|
log "Pornesc VM $VMID pe $SECONDARY..."
|
||||||
|
qm start "$VMID"
|
||||||
|
sleep 5
|
||||||
|
STATUS=$(qm status "$VMID" | awk '{print $2}')
|
||||||
|
log "Status: $STATUS"
|
||||||
|
|
||||||
|
# Mail
|
||||||
|
{
|
||||||
|
echo "Failover VM $VMID executat pe $SECONDARY la $(date)"
|
||||||
|
echo
|
||||||
|
echo "Primary $PRIMARY era DOWN."
|
||||||
|
echo "Ultima replicare folosită: $LAST_SNAP"
|
||||||
|
echo "Status VM: $STATUS"
|
||||||
|
echo
|
||||||
|
echo "Pași următori:"
|
||||||
|
echo "1. Verifică aplicația Windows pe 10.0.20.201 (IIS, etc)"
|
||||||
|
echo "2. Când $PRIMARY revine, NU porni VM $VMID pe $PRIMARY"
|
||||||
|
echo "3. După stabilizare, migrare înapoi: qm migrate $VMID $PRIMARY --online 0"
|
||||||
|
} | mail -r 'ups@romfast.ro' -s "[CRITIC] Failover VM $VMID pornit pe $SECONDARY" "$MAIL_TO"
|
||||||
|
|
||||||
|
log "=== Failover complet ==="
|
||||||
83
proxmox/cluster/failover/pvemini-down-alert.sh
Executable file
83
proxmox/cluster/failover/pvemini-down-alert.sh
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Alertă când pvemini e unreachable — rulează pe pveelite din cron 1 min
|
||||||
|
# Deployed la /opt/scripts/pvemini-down-alert.sh pe pveelite
|
||||||
|
# Stateful: alertează o dată după 2 minute consecutive DOWN, reset la UP
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PRIMARY_IP=10.0.20.201
|
||||||
|
STATE=/var/run/pvemini-down-alert.state
|
||||||
|
MAIL_TO=mmarius28@gmail.com
|
||||||
|
THRESHOLD=2 # min consecutive
|
||||||
|
|
||||||
|
COUNT=0
|
||||||
|
[[ -f "$STATE" ]] && COUNT=$(cat "$STATE")
|
||||||
|
|
||||||
|
if ping -c 2 -W 2 "$PRIMARY_IP" &>/dev/null; then
|
||||||
|
if [[ "$COUNT" -ge "$THRESHOLD" ]]; then
|
||||||
|
# Recovery
|
||||||
|
echo "pvemini revenit online la $(date)" | \
|
||||||
|
mail -r 'ups@romfast.ro' -s "[OK] pvemini UP" "$MAIL_TO"
|
||||||
|
fi
|
||||||
|
echo 0 > "$STATE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
COUNT=$((COUNT + 1))
|
||||||
|
echo "$COUNT" > "$STATE"
|
||||||
|
|
||||||
|
# Alertează o singură dată când atingem threshold
|
||||||
|
if [[ "$COUNT" -eq "$THRESHOLD" ]]; then
|
||||||
|
{
|
||||||
|
echo "pvemini (10.0.20.201) NU răspunde la ping de $THRESHOLD minute"
|
||||||
|
echo "Timp: $(date)"
|
||||||
|
echo
|
||||||
|
echo "Stare cluster:"
|
||||||
|
pvecm status 2>&1 | head -20 || true
|
||||||
|
echo
|
||||||
|
echo "HA status:"
|
||||||
|
ha-manager status 2>&1 || true
|
||||||
|
echo
|
||||||
|
echo "=========================================="
|
||||||
|
echo "CT-uri HA (104, 106, 108, 171): migrare AUTOMATĂ"
|
||||||
|
echo "pe pveelite în ~2 min dacă pveelite are RAM."
|
||||||
|
echo "=========================================="
|
||||||
|
echo
|
||||||
|
echo "### FAILOVER MANUAL VM 201 (Windows) ###"
|
||||||
|
echo
|
||||||
|
echo "Dacă pvemini rămâne DOWN, pentru a porni VM 201 pe pveelite:"
|
||||||
|
echo
|
||||||
|
echo " ssh root@10.0.20.202 /opt/scripts/failover-vm201.sh"
|
||||||
|
echo
|
||||||
|
echo "(tastezi 'DA' la prompt; scriptul folosește ultima replicare"
|
||||||
|
echo " ZFS — max 5 min în urmă. Verifică ping + ssh înainte)"
|
||||||
|
echo
|
||||||
|
echo "Variantă non-interactivă:"
|
||||||
|
echo " ssh root@10.0.20.202 /opt/scripts/failover-vm201.sh --yes"
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo "### REVENIRE PE PVEMINI (după ce pvemini e stabil) ###"
|
||||||
|
echo
|
||||||
|
echo "IMPORTANT: NU porni VM 201 pe pvemini automat — date divergente."
|
||||||
|
echo "Folosește scriptul interactiv care face toți pașii în siguranță:"
|
||||||
|
echo
|
||||||
|
echo " ssh root@10.0.20.202 /opt/scripts/recover-vm201-to-pvemini.sh"
|
||||||
|
echo
|
||||||
|
echo "Scriptul verifică:"
|
||||||
|
echo " - pvemini uptime min. 30 min + erori recente"
|
||||||
|
echo " - pvemini reachable ssh + VM 201 NU rulează deja acolo"
|
||||||
|
echo " - VM 201 running local pe pveelite"
|
||||||
|
echo
|
||||||
|
echo "Execuția face automat (cu confirmări la fiecare pas):"
|
||||||
|
echo " 1. qm shutdown 201 pe pveelite"
|
||||||
|
echo " 2. pvesr replicare inversă pveelite → pvemini + run forțat"
|
||||||
|
echo " 3. qm migrate 201 pvemini (offline)"
|
||||||
|
echo " 4. cleanup job replicare inversă"
|
||||||
|
echo " 5. qm start 201 pe pvemini"
|
||||||
|
echo
|
||||||
|
echo "Variantă non-interactivă: adaugă '--yes' la final."
|
||||||
|
echo
|
||||||
|
echo "CT-urile HA (104, 106, 108, 171) revin automat pe pvemini"
|
||||||
|
echo "conform priorității ha-group-main."
|
||||||
|
echo "=========================================="
|
||||||
|
} | mail -r 'ups@romfast.ro' -s "[CRITIC] pvemini DOWN $THRESHOLD min" "$MAIL_TO"
|
||||||
|
fi
|
||||||
139
proxmox/cluster/failover/recover-vm201-to-pvemini.sh
Executable file
139
proxmox/cluster/failover/recover-vm201-to-pvemini.sh
Executable file
@@ -0,0 +1,139 @@
|
|||||||
|
#!/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 ==="
|
||||||
Reference in New Issue
Block a user