#!/bin/bash # # Nightly mirror of Oracle backups + cluster config to pve1's backup-ssd. # # Why two redundant copies are not enough: # * ZFS replica pveelite -> pvemini covers pveelite hardware failure. # * If both pveelite AND pvemini are down (rare but possible — common # storage controller, network rack, electrical fault), pve1 is the # last copy. Keeping it on a different physical disk type (SATA # ext4) further insulates against ZFS-on-NVMe-specific failures. # * /etc/pve is in pmxcfs (in-RAM, replicated cluster-wide). If # quorum is lost on multiple nodes simultaneously the config is # unrecoverable without a backup. # # Schedule (cron on pveelite): 0 4 * * * set -euo pipefail export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" PVE1_HOST="10.0.20.200" PVE1_BACKUP_DIR="/mnt/pve/backup-ssd" ORACLE_SRC="/mnt/pve/oracle-backups/" ORACLE_DST="${PVE1_BACKUP_DIR}/oracle-backups-mirror/" PVE_CFG_DST="${PVE1_BACKUP_DIR}/pve-config-backups" LOG="/var/log/oracle-dr/nightly-mirror.log" SSH_OPTS="-o UserKnownHostsFile=/etc/pve/priv/known_hosts -o StrictHostKeyChecking=no -o BatchMode=yes" KEEP_PVE_CONFIGS=14 # 2 weeks of nightly /etc/pve archives mkdir -p "$(dirname "$LOG")" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >>"$LOG"; } log "=== Starting nightly mirror ===" # 1. Rsync Oracle backups to pve1 log "Rsync ${ORACLE_SRC} -> ${PVE1_HOST}:${ORACLE_DST}" if rsync -aHX --delete -e "ssh ${SSH_OPTS}" \ "${ORACLE_SRC}" "root@${PVE1_HOST}:${ORACLE_DST}" 2>>"$LOG"; then log "Oracle backups rsync OK" else log "ERROR: Oracle backups rsync failed" fi # 2. Tar /etc/pve and ship to pve1 TS=$(date +%Y%m%d_%H%M%S) ARCHIVE="pve-config-${TS}.tar.gz" log "Tar /etc/pve -> ${PVE1_HOST}:${PVE_CFG_DST}/${ARCHIVE}" if tar czf - -C / etc/pve 2>/dev/null | \ ssh ${SSH_OPTS} "root@${PVE1_HOST}" \ "cat > '${PVE_CFG_DST}/${ARCHIVE}'" 2>>"$LOG"; then log "pve-config tar OK ($(ssh ${SSH_OPTS} root@${PVE1_HOST} \ "stat -c %s '${PVE_CFG_DST}/${ARCHIVE}'") bytes)" else log "ERROR: pve-config tar failed" fi # 3. Prune old pve-config archives on pve1 (keep last KEEP_PVE_CONFIGS) ssh ${SSH_OPTS} "root@${PVE1_HOST}" " cd '${PVE_CFG_DST}' && \ ls -1t pve-config-*.tar.gz 2>/dev/null | tail -n +$((KEEP_PVE_CONFIGS + 1)) | xargs -r rm -v " >>"$LOG" 2>&1 || true log "=== Nightly mirror completed ==="