#!/bin/bash
# ==============================================================================
# SCRIPT: 01_backup_remote.sh (V3 - Robust-Edition)
# ZWECK: ZFS Snapshots + System-Konfig + Sicherheits-Checks + Push
# ==============================================================================
# --- 1. INITIALISIERUNG & KONFIGURATION ---
source /usr/local/sbin/01_backup/001_global_config.sh
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
ALERT=0
START_TIME=$(date +%s)
TIMESTAMP=$(date '+%Y-%m-%d_%H-%M-%S')
SYS_REMOTE_PATH="${BACKUPPOOL}/sysdata-${MY_IP##*.}"
clear
echo -e "${BLUE}================================================================${NC}"
echo -e " Start ZFS & System Remote-Backup: $(date '+%d.%m.%Y %H:%M')"
echo -e "️ Quelle: ${YELLOW}$HOST ($MY_IP)${NC} | Ziel: ${YELLOW}$REMOTE_HOST${NC}"
echo -e "${BLUE}================================================================${NC}\n"
# --- 2. PRE-FLIGHT CHECKS (Sicherheits-Prüfungen) ---
echo -e "${BLUE}▶ Starte Sicherheits-Checks...${NC}"
# A) Ist der Quell-Pool gesund?
POOL_HEALTH=$(zpool status "$MASTERPOOL" | grep "state:" | awk '{print $2}')
if [ "$POOL_HEALTH" != "ONLINE" ]; then
msg=" ABBRUCH: Quell-Pool $MASTERPOOL ist $POOL_HEALTH! Backup riskant."
echo -e "${RED}$msg${NC}"
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$msg" warn
exit 1
fi
# B) Ist der Ziel-Server per Ping erreichbar?
if ! ping -c 1 -W 2 "$REMOTE_HOST" >/dev/null 2>&1; then
msg=" ABBRUCH: Ziel-Server $REMOTE_HOST ist nicht erreichbar (Ping failed)!"
echo -e "${RED}$msg${NC}"
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$msg" warn
exit 1
fi
# C) Speicherplatz auf dem Ziel-Pool prüfen (Abbruch bei > 95%)
REMOTE_USAGE=$(ssh root@$REMOTE_HOST "zfs list -H -o capacity $BACKUPPOOL" 2>/dev/null | cut -d'%' -f1)
if [ -n "$REMOTE_USAGE" ] && [ "$REMOTE_USAGE" -gt 95 ]; then
msg=" ABBRUCH: Ziel-Pool $BACKUPPOOL ist zu $REMOTE_USAGE% voll!"
echo -e "${RED}$msg${NC}"
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$msg" warn
exit 1
fi
echo -e " ✅ Sicherheits-Checks bestanden (Pool OK, Ping OK, Platz: ${REMOTE_USAGE:-0}%).\n"
# --- 3. SYSTEM-KONFIGURATION SICHERN (/etc & Paketliste) ---
echo -e "${BLUE}▶ Sichere System-Konfiguration...${NC}"
ssh root@$REMOTE_HOST "mkdir -p /${SYS_REMOTE_PATH}/etc" 2>/dev/null
dpkg --get-selections > /tmp/packages.txt
rsync -az /tmp/packages.txt root@$REMOTE_HOST:/${SYS_REMOTE_PATH}/ 2>/dev/null
rm -f /tmp/packages.txt
if rsync -avz --delete /etc/ root@$REMOTE_HOST:/${SYS_REMOTE_PATH}/etc/ >/dev/null 2>&1; then
echo -e " ✅ /etc & Paketliste nach ${YELLOW}${SYS_REMOTE_PATH}${NC} gesichert.\n"
else
msg=" SYSTEM-BACKUP FEHLER: /etc auf $HOST konnte nicht übertragen werden."
echo -e " ❌ ${RED}$msg${NC}\n"
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$msg" warn
ALERT=1
fi
# --- 4. ZFS BACKUP-SCHLEIFE ---
for DS in "${DATASETS[@]}"; do
MASTER_DS="${MASTERPOOL}/${DS}"
TARGET_DS="${BACKUPPOOL}/pve_${MY_IP}/${DS}"
NEWSNAP="${MASTER_DS}@${PREFIX}-${TIMESTAMP}"
echo -e "${BLUE}▶ ZFS Dataset:${NC} ${YELLOW}$DS${NC}"
# Snapshot erstellen
if zfs snapshot "$NEWSNAP" 2>/dev/null; then
echo -e " ✅ Snapshot: ${PREFIX}-${TIMESTAMP}"
else
msg=" SNAPSHOT FEHLER: $DS auf $HOST fehlgeschlagen!"
echo -e " ❌ ${RED}$msg${NC}"
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$msg" warn
ALERT=1; continue
fi
# Remote-Check & Transfer
LAST_REMOTE_SNAP=$(ssh root@$REMOTE_HOST "zfs list -H -t snapshot -o name -s creation $TARGET_DS" 2>/dev/null | grep "@${PREFIX}-" | tail -1 | cut -d@ -f2)
if [ -z "$LAST_REMOTE_SNAP" ]; then
echo -e " ${YELLOW}Modus: FULL-TRANSFER${NC}"
zfs send -cL "$NEWSNAP" | pv -N "Full: $DS" | mbuffer -m 256M | ssh root@$REMOTE_HOST "zfs recv -Fp $TARGET_DS"
else
echo -e " ${YELLOW}Modus: INKREMENTELL (ab $LAST_REMOTE_SNAP)$NC"
zfs send -cL -i "${MASTER_DS}@${LAST_REMOTE_SNAP}" "$NEWSNAP" | pv -N "Incr: $DS" | mbuffer -m 256M | ssh root@$REMOTE_HOST "zfs recv -Fu $TARGET_DS"
fi
if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo -e " ✨ ${GREEN}ZFS Transfer erfolgreich.${NC}\n"
else
msg=" ZFS TRANSFER FEHLER: $DS konnte nicht an $REMOTE_HOST gesendet werden!"
echo -e " ${RED}$msg${NC}\n"
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$msg" warn
ALERT=1
fi
# Retention (Aufräumen)
zfs list -H -t snapshot -o name -s creation "$MASTER_DS" | grep "@${PREFIX}-" | head -n -"$KEEPOLD_MASTER" | xargs -n 1 zfs destroy -r 2>/dev/null
ssh root@$REMOTE_HOST "zfs list -H -t snapshot -o name -s creation $TARGET_DS | grep '@${PREFIX}-' | head -n -"$KEEPOLD_BACKUP" | xargs -n 1 zfs destroy -r 2>/dev/null"
done
# --- 5. ABSCHLUSS & PUSH ---
DURATION=$(( $(date +%s) - START_TIME ))
if [ $ALERT -eq 0 ]; then
PUSH_TEXT="✅ Backup OK: $HOST -> $REMOTE_HOST (${DURATION}s). /etc & Datasets synchron."
[ -f "$SEND_PUSH" ] && "$SEND_PUSH" "$PUSH_TEXT" success
echo -e "${GREEN} Alles erledigt. Erfolgs-Push gesendet.${NC}"
else
echo -e "${RED} Backup mit Fehlern beendet. Warnungen wurden gesendet.${NC}"
fi
echo -e "${BLUE}================================================================${NC}"