Files
miyagi-backup/miyagi-backup.sh
T
patrick 3f9b7c5e64 miyagi-backup.sh aktualisiert
fallback without metadata
2025-06-06 00:49:18 +02:00

229 lines
6.6 KiB
Bash

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
SCRIPT_NAME=$(basename "$0")
LOGFILE="/var/log/${SCRIPT_NAME%.sh}.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOGFILE"
}
usage() {
echo "Usage:"
echo " $0 -c /path/to/config # Full backup run"
echo " $0 [function] # Run individual function"
echo " $0 help # Show available functions"
exit 1
}
# Konfigurationsdatei initialisieren (nur wenn -c übergeben)
CONFIG_FILE=""
while getopts "c:" opt; do
case "$opt" in
c) CONFIG_FILE="$OPTARG" ;;
*) usage ;;
esac
done
# Bei Einzelaufruf muss Konfiguration geladen sein
shift $((OPTIND - 1))
if [[ -n "${CONFIG_FILE:-}" ]]; then
if [[ ! -f "$CONFIG_FILE" ]]; then
log "ERROR: Configuration file not found: $CONFIG_FILE"
exit 1
fi
source "$CONFIG_FILE"
fi
# Funktionen
write_zsync_config() {
local conf_file="/etc/bashclub/$SOURCEHOST.conf"
log "Writing zsync config to $conf_file"
{
echo "target=$ZFSTRGT"
echo "source=root@$SOURCEHOST"
echo "sshport=$SSHPORT"
echo "tag=$ZPUSHTAG"
echo "snapshot_filter=$ZPUSHFILTER"
echo "min_keep=$ZPUSHMINKEEP"
echo "zfs_auto_snapshot_keep=$ZPUSHKEEP"
echo "zfs_auto_snapshot_label=$ZPUSHLABEL"
echo "zfs_auto_snapshot_engine=internal"
echo "checkzfs_disabled=0"
echo "checkzfs_local=0"
echo "checkzfs_prefix=miyagi-$SOURCEHOSTNAME-$(hostname)-$ZPUSHTAG"
echo "checkzfs_max_age=1500,2000"
echo "checkzfs_max_snapshot_count=180,200"
echo "checkzfs_spool=1"
echo "checkzfs_spool_maxage=90000"
} > "$conf_file"
}
run_zsync() {
if [[ "$ZSYNC" != "no" ]]; then
/usr/bin/bashclub-zsync -c "/etc/bashclub/$SOURCEHOST.conf"
else
log "Zsync is disabled"
fi
}
run_updates() {
log "Running updates..."
apt update && apt dist-upgrade -y
apt autopurge -y
}
run_remote_updates() {
if [[ "$UPDATES" == "yes" ]]; then
ssh "$PBSHOST" apt update && apt dist-upgrade -y
else
log "Remote updates disabled"
fi
}
send_piggyback_data() {
local fname="90000_miyagi-$SOURCEHOSTNAME-$(hostname)"
log "Sending piggyback data to $SOURCEHOST..."
echo "<<<<miyagi-$SOURCEHOSTNAME-$(hostname)>>>" > "$fname"
/usr/bin/check_mk_agent >> "$fname"
echo "<<<<>>>>" >> "$fname"
scp "$fname" "$SOURCEHOST:/var/lib/check_mk_agent/spool/"
}
run_pbs_backup() {
if [[ -z "${SOURCEHOSTNAME:-}" ]]; then
SOURCEHOSTNAME=$(ssh "$SOURCEHOST" hostname)
fi
log "Running PBS vzdump job..."
# PBS-Storage ggf. aktivieren
log "Checking if PBS storage '$BACKUPSTORE' is enabled on $SOURCEHOST..."
if ssh root@"$SOURCEHOST" "pvesm status | grep -w '$BACKUPSTORE' | grep -q 'disabled'"; then
log "PBS storage '$BACKUPSTORE' is disabled. Attempting to enable..."
ssh root@"$SOURCEHOST" "pvesm set '$BACKUPSTORE' --disable 0 && sleep 2"
else
log "PBS storage '$BACKUPSTORE' is already enabled."
fi
# Hauptversuch mit --pbs-change-detection-mode
if ssh root@"$SOURCEHOST" vzdump --pbs-change-detection-mode metadata \
--node "$SOURCEHOSTNAME" --storage "$BACKUPSTORE" \
--exclude "$BACKUPEXCLUDE" --mode snapshot --all 1 \
--notes-template '{{guestname}}'; then
log "vzdump with change-detection-mode succeeded"
else
log "Fallback: vzdump with change-detection-mode failed, trying without it..."
if ssh root@"$SOURCEHOST" vzdump \
--node "$SOURCEHOSTNAME" --storage "$BACKUPSTORE" \
--exclude "$BACKUPEXCLUDE" --mode snapshot --all 1 \
--notes-template '{{guestname}}'; then
log "Fallback vzdump succeeded"
else
log "ERROR: vzdump failed even after fallback"
fi
fi
# Monitoring-Output
if [[ $? -eq 0 ]]; then
echo "0 DailyPBS - Daily Backup" > /tmp/cmk_tmp.out
else
echo "2 DailyPBS - Daily Backup FAILED" > /tmp/cmk_tmp.out
fi
( echo "<<<local>>>" ; cat /tmp/cmk_tmp.out ) > /tmp/90000_checkpbs
scp /tmp/90000_checkpbs root@"$SOURCEHOST":/var/lib/check_mk_agent/spool || log "Fehler beim SCP des Monitoring-Outputs"
}
run_maintenance() {
if [[ "$(date +%u)" == "$MAINTDAY" ]]; then
log "Running maintenance..."
PRUNEJOB=$(ssh "$PBSHOST" proxmox-backup-manager prune-job list --output-format json-pretty | grep -m 1 "id" | cut -d'"' -f4)
ssh root@"$PBSHOST" proxmox-backup-manager prune-job run "$PRUNEJOB"
ssh root@"$PBSHOST" proxmox-backup-manager garbage-collection start "$BACKUPSTOREPBS"
ssh root@"$PBSHOST" proxmox-backup-manager verify backup
else
log "No maintenance scheduled for today."
fi
}
run_scrub_stop_src() {
ssh root@"$SOURCEHOST" 'for pool in $(zpool list -H -o name); do
echo "Stoppe Scrub auf Pool: $pool"
if zpool status "$pool" | grep -q "scrub in progress"; then
if zpool scrub -s "$pool"; then
echo "Scrub auf $pool gestoppt"
else
echo "Fehler beim Stoppen des Scrubs auf $pool"
fi
else
echo "Kein aktiver Scrub auf $pool"
fi
done'
}
run_scrub_stop_local() {
for pool in $(zpool list -H -o name); do
echo "Stoppe Scrub auf Pool: $pool"
if zpool status "$pool" | grep -q "scrub in progress"; then
if zpool scrub -s "$pool"; then
echo "Scrub auf $pool gestoppt"
else
echo "Fehler beim Stoppen des Scrubs auf $pool"
fi
else
echo "Kein aktiver Scrub auf $pool"
fi
done
}
shutdown_if_requested() {
if [[ "$SHUTDOWN" == "yes" ]]; then
send_piggyback_data
log "Shutting down now..."
shutdown now
else
log "No shutdown requested."
fi
}
main() {
log "Starting full backup routine..."
SOURCEHOSTNAME=$(ssh "$SOURCEHOST" hostname)
write_zsync_config
run_zsync
run_maintenance
run_scrub_stop_local
run_scrub_stop_src
run_pbs_backup
run_remote_updates
run_updates
shutdown_if_requested
}
# Funktionsbasierter Aufruf
if [[ "${1:-}" == "help" ]]; then
echo "Verfuegbare Funktionen:"
declare -F | awk '{print " - " $3}' | grep -v "^ - _"
exit 0
elif [[ "${1:-}" =~ ^[a-zA-Z0-9_]+$ && "$(type -t "$1")" == "function" ]]; then
FUNC="$1"
shift
"$FUNC" "$@"
exit 0
else
main
fi