Update backup script

This commit is contained in:
albert 2024-12-18 14:19:13 -06:00
parent f1ddb33939
commit 39b0c57266
Signed by: albert
GPG key ID: 3895DD267CA11BA9
2 changed files with 52 additions and 31 deletions

View file

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#!/bin/bash
# Check for required argument # Check for required argument
if [ $# -ne 1 ]; then if [ $# -ne 1 ]; then
@ -10,6 +9,7 @@ fi
# Configuration # Configuration
SNAPPER_CONFIG="$1" SNAPPER_CONFIG="$1"
BACKUP_DESCRIPTION="btrfs-backup"
# Get the actual snapshot location from snapper config # Get the actual snapshot location from snapper config
SOURCE_PATH=$(sudo snapper -c "$SNAPPER_CONFIG" get-config | grep '^SUBVOLUME' | cut -d'=' -f2 | tr -d '"'| awk {'print $3'}) SOURCE_PATH=$(sudo snapper -c "$SNAPPER_CONFIG" get-config | grep '^SUBVOLUME' | cut -d'=' -f2 | tr -d '"'| awk {'print $3'})
@ -26,17 +26,22 @@ if [ ! -d "$SNAPSHOT_PATH" ]; then
exit 1 exit 1
fi fi
# Create new snapshot with backup description
NEW_SNAPSHOT=$(sudo snapper -c "$SNAPPER_CONFIG" create --description "$BACKUP_DESCRIPTION" --print-number)
if [ -z "$NEW_SNAPSHOT" ]; then
echo "ERROR: Failed to create new snapshot"
exit 1
fi
# Get latest snapshot number from snapper
LATEST_SNAPSHOT=$(sudo snapper -c "$SNAPPER_CONFIG" list | tail -n 1 | awk '{print $1}')
HOSTNME=$(hostname) HOSTNME=$(hostname)
REMOTE_HOST="root@synology" REMOTE_HOST="root@synology"
BASE_DEST_PATH="/volume1/BTRFS_Receives/`hostname`/${SNAPPER_CONFIG}" BASE_DEST_PATH="/volume1/BTRFS_Receives/`hostname`/${SNAPPER_CONFIG}"
DEST_PATH="/volume1/BTRFS_Receives/`hostname`/${SNAPPER_CONFIG}/${LATEST_SNAPSHOT}" DEST_PATH="/volume1/BTRFS_Receives/`hostname`/${SNAPPER_CONFIG}/${NEW_SNAPSHOT}"
STATE_FILE="/var/lib/snapper-backup-${SNAPPER_CONFIG}.state" STATE_FILE="/var/lib/snapper-backup-${SNAPPER_CONFIG}.state"
LOG_FILE="/var/log/snapper-backup-${SNAPPER_CONFIG}.log" LOG_FILE="/var/log/snapper-backup-${SNAPPER_CONFIG}.log"
KEEP_SNAPSHOTS=5 KEEP_SNAPSHOTS=5
# Get latest successful transfer number
# Get latest successful transfer number from snapshots with backup description
LAST_TRANSFERRED=$(cat "$STATE_FILE" 2>/dev/null || echo "") LAST_TRANSFERRED=$(cat "$STATE_FILE" 2>/dev/null || echo "")
# Ensure we exit on any error # Ensure we exit on any error
@ -73,24 +78,40 @@ verify_remote() {
# Function to get remote snapshots # Function to get remote snapshots
get_remote_snapshots() { get_remote_snapshots() {
ssh "$REMOTE_HOST" "find '$BASE_DEST_PATH' -maxdepth 2 -type d -name 'snapshot*' | sort -n" ssh "$REMOTE_HOST" "find '$BASE_DEST_PATH' -maxdepth 1 -type d -name '[0-9]*' | sort -n"
# ssh "$REMOTE_HOST" "btrfs subvolume list /volume1/ -t | grep $HOSTNAME | grep $SNAPPER_CONFIG"
} }
# Function to cleanup old remote snapshots # Function to get local backup snapshots
cleanup_remote_snapshots() { get_local_snapshots() {
local snapshots=($(get_remote_snapshots)) sudo snapper -c "$SNAPPER_CONFIG" list | grep "$BACKUP_DESCRIPTION" | awk '{print $1}' | sort -n
local count=${#snapshots[@]} }
# Function to cleanup old snapshots both locally and remotely
cleanup_snapshots() {
local local_snapshots=($(get_local_snapshots))
local remote_snapshots=($(get_remote_snapshots))
local count=${#local_snapshots[@]}
if [ $count -gt $KEEP_SNAPSHOTS ]; then if [ $count -gt $KEEP_SNAPSHOTS ]; then
local to_delete=$((count - KEEP_SNAPSHOTS)) local to_delete=$((count - KEEP_SNAPSHOTS))
log "Cleaning up $to_delete old snapshots on remote system" log "Cleaning up $to_delete old snapshots both locally and remotely"
for ((i=0; i<$to_delete; i++)); do for ((i=0; i<$to_delete; i++)); do
local snapshot="${snapshots[$i]}" local snapshot="${local_snapshots[$i]}"
# Delete remote snapshot first
if ssh "$REMOTE_HOST" "[ -d '$BASE_DEST_PATH/$snapshot' ]"; then
log "Deleting remote snapshot: $snapshot" log "Deleting remote snapshot: $snapshot"
ssh "$REMOTE_HOST" "btrfs subvolume delete '$snapshot'" || \ ssh "$REMOTE_HOST" "btrfs subvolume delete '$BASE_DEST_PATH/$snapshot/snapshot'" || \
log "WARNING: Failed to delete snapshot $snapshot" log "WARNING: Failed to delete remote snapshot $snapshot"
ssh "$REMOTE_HOST" "rm -rf '$BASE_DEST_PATH/$snapshot'" || \
log "WARNING: Failed to cleanup remote snapshot directory $snapshot"
fi
# Then delete local snapshot
log "Deleting local snapshot: $snapshot"
sudo snapper -c "$SNAPPER_CONFIG" delete "$snapshot" || \
log "WARNING: Failed to delete local snapshot $snapshot"
done done
fi fi
} }
@ -98,60 +119,60 @@ cleanup_remote_snapshots() {
# Start backup process # Start backup process
log "Starting backup for snapper config: $SNAPPER_CONFIG" log "Starting backup for snapper config: $SNAPPER_CONFIG"
log "Using snapshot path: $SNAPSHOT_PATH" log "Using snapshot path: $SNAPSHOT_PATH"
log "Created new snapshot: $NEW_SNAPSHOT"
# Verify remote connectivity first # Verify remote connectivity first
verify_remote verify_remote
# Verify snapshots exist # Verify snapshots exist
verify_snapshot "$LATEST_SNAPSHOT" || exit 1 verify_snapshot "$NEW_SNAPSHOT" || exit 1
if [ -n "$LAST_TRANSFERRED" ]; then if [ -n "$LAST_TRANSFERRED" ]; then
verify_snapshot "$LAST_TRANSFERRED" || exit 1 verify_snapshot "$LAST_TRANSFERRED" || exit 1
fi fi
# Exit if no new snapshots to transfer
if [ "$LAST_TRANSFERRED" = "$LATEST_SNAPSHOT" ]; then
log "No new snapshots to transfer"
exit 0
fi
# Create destination directory if it doesn't exist # Create destination directory if it doesn't exist
ssh "$REMOTE_HOST" "mkdir -p '$DEST_PATH'" ssh "$REMOTE_HOST" "mkdir -p '$DEST_PATH'"
# Perform the transfer # Perform the transfer
if [ -z "$LAST_TRANSFERRED" ]; then if [ -z "$LAST_TRANSFERRED" ]; then
# First time backup - full send # First time backup - full send
log "Performing full send of snapshot $LATEST_SNAPSHOT" log "Performing full send of snapshot $NEW_SNAPSHOT"
sudo btrfs send "$SNAPSHOT_PATH/$LATEST_SNAPSHOT/snapshot" | \ sudo btrfs send "$SNAPSHOT_PATH/$NEW_SNAPSHOT/snapshot" | \
pv --bytes | \ pv --bytes | \
ssh "$REMOTE_HOST" "btrfs receive '$DEST_PATH'" && { ssh "$REMOTE_HOST" "btrfs receive '$DEST_PATH'" && {
sudo echo "$LATEST_SNAPSHOT" | sudo tee "$STATE_FILE" echo "$NEW_SNAPSHOT" | sudo tee "$STATE_FILE"
log "Full send completed successfully" log "Full send completed successfully"
} || { } || {
log "ERROR: Full send failed" log "ERROR: Full send failed"
sudo snapper -c "$SNAPPER_CONFIG" delete "$NEW_SNAPSHOT"
exit 1 exit 1
} }
else else
# Incremental send # Incremental send
log "Performing incremental send from $LAST_TRANSFERRED to $LATEST_SNAPSHOT" log "Performing incremental send from $LAST_TRANSFERRED to $NEW_SNAPSHOT"
sudo btrfs send -p "$SNAPSHOT_PATH/$LAST_TRANSFERRED/snapshot" \ sudo btrfs send -p "$SNAPSHOT_PATH/$LAST_TRANSFERRED/snapshot" \
"$SNAPSHOT_PATH/$LATEST_SNAPSHOT/snapshot" | \ "$SNAPSHOT_PATH/$NEW_SNAPSHOT/snapshot" | \
pv --bytes | \ pv --bytes | \
ssh "$REMOTE_HOST" "btrfs receive '$DEST_PATH'" && { ssh "$REMOTE_HOST" "btrfs receive '$DEST_PATH'" && {
sudo echo "$LATEST_SNAPSHOT" | sudo tee "$STATE_FILE" echo "$NEW_SNAPSHOT" | sudo tee "$STATE_FILE"
log "Incremental send completed successfully" log "Incremental send completed successfully"
} || { } || {
log "ERROR: Incremental send failed" log "ERROR: Incremental send failed"
sudo snapper -c "$SNAPPER_CONFIG" delete "$NEW_SNAPSHOT"
exit 1 exit 1
} }
fi fi
# Cleanup old snapshots if transfer was successful # Cleanup old snapshots if transfer was successful
cleanup_remote_snapshots cleanup_snapshots
# Verify remote snapshots # Verify remote snapshots
log "Current remote snapshots:" log "Current remote snapshots:"
get_remote_snapshots | sudo tee -a "$LOG_FILE" get_remote_snapshots | sudo tee -a "$LOG_FILE"
log "Current local snapshots:"
get_local_snapshots | sudo tee -a "$LOG_FILE"
# Final verification # Final verification
if ! ssh "$REMOTE_HOST" "btrfs subvolume show '$DEST_PATH/snapshot'" &>/dev/null; then if ! ssh "$REMOTE_HOST" "btrfs subvolume show '$DEST_PATH/snapshot'" &>/dev/null; then
log "WARNING: Final verification failed" log "WARNING: Final verification failed"

@ -1 +1 @@
Subproject commit 8ed82c9afaac6359cf4603196f7a5bd4b399a4b5 Subproject commit 26552d8bade6fa39188ebf68e9ffa1a8dcd75108