feat: Enhance backup script with upload-only mode and improved error logging

This commit is contained in:
Peter Wood
2025-12-16 17:25:15 -05:00
parent ebe9644701
commit 5b31d616f6

View File

@@ -53,13 +53,13 @@ cleanup() {
trap cleanup EXIT SIGINT SIGTERM
# Load environment variables from the .env file
ENV_FILE="$(dirname "$0")/../.env"
ENV_FILE="${SCRIPT_DIR}/../.env"
if [ -f "$ENV_FILE" ]; then
echo "Loading environment variables from $ENV_FILE"
# shellcheck source=/dev/null
source "$ENV_FILE"
else
echo "Error: .env file not found in $(dirname "$0")/.."
echo "Error: .env file not found in ${SCRIPT_DIR}/.."
exit 1
fi
@@ -109,6 +109,7 @@ EXAMPLES:
$(basename "$0") --help # Show this help
$(basename "$0") --dry-run # Preview backup without executing
$(basename "$0") --no-upload # Backup locally only (skip B2)
$(basename "$0") --upload-only # Only upload the latest existing backup to B2
RESTORE INSTRUCTIONS:
https://immich.app/docs/administration/backup-and-restore/
@@ -119,6 +120,7 @@ EOF
# Parse command line arguments
DRY_RUN=false
NO_UPLOAD=false
UPLOAD_ONLY=false
VERBOSE=false
while [[ $# -gt 0 ]]; do
@@ -135,6 +137,10 @@ while [[ $# -gt 0 ]]; do
NO_UPLOAD=true
shift
;;
--upload-only)
UPLOAD_ONLY=true
shift
;;
--verbose)
VERBOSE=true
shift
@@ -148,12 +154,12 @@ while [[ $# -gt 0 ]]; do
done
# B2 CLI tool path
if [ -f "$(dirname "$0")/b2-linux" ]; then
B2_CLI="$(dirname "$0")/b2-linux"
if [ -f "${SCRIPT_DIR}/b2-linux" ]; then
B2_CLI="${SCRIPT_DIR}/b2-linux"
elif command -v b2 &> /dev/null; then
B2_CLI=$(command -v b2)
else
B2_CLI="$(dirname "$0")/b2-linux"
B2_CLI="${SCRIPT_DIR}/b2-linux"
fi
# Notification function
@@ -204,17 +210,40 @@ upload_to_b2() {
log_message "Uploading $filename to B2 bucket: $B2_BUCKET_NAME"
# Authorize B2 account
if ! "$B2_CLI" authorize-account "$B2_APPLICATION_KEY_ID" "$B2_APPLICATION_KEY" 2>/dev/null; then
local auth_output
if ! auth_output=$("$B2_CLI" authorize-account "$B2_APPLICATION_KEY_ID" "$B2_APPLICATION_KEY" 2>&1); then
log_message "Error: Failed to authorize B2 account"
log_message "B2 Output: $auth_output"
return 1
fi
# Upload file to B2
if "$B2_CLI" upload-file "$B2_BUCKET_NAME" "$file_path" "immich-backups/$filename" 2>/dev/null; then
local temp_log
temp_log=$(mktemp)
# Enable pipefail to catch b2 exit code through tee
set -o pipefail
# Use --threads 4 to avoid "More than one concurrent upload using auth token" error
# which can happen with default thread count on large files
if "$B2_CLI" file upload --threads 4 "$B2_BUCKET_NAME" "$file_path" "immich-backups/$filename" 2>&1 | tee "$temp_log"; then
set +o pipefail
rm "$temp_log"
log_message "✅ Successfully uploaded $filename to B2"
return 0
else
local exit_code=$?
set +o pipefail
log_message "❌ Failed to upload $filename to B2"
# Log the last few lines of output to capture the error message
# avoiding the progress bar spam
local error_msg
error_msg=$(tail -n 20 "$temp_log")
log_message "B2 Output (last 20 lines):"
log_message "$error_msg"
rm "$temp_log"
return 1
fi
}
@@ -223,7 +252,7 @@ upload_to_b2() {
IMMICH_SERVER_RUNNING=true
# Set up logging to central logs directory
LOG_DIR="$(dirname "$0")/../logs"
LOG_DIR="${SCRIPT_DIR}/../logs"
mkdir -p "$LOG_DIR"
LOG_FILE="${LOG_DIR}/immich-backup.log"
@@ -243,10 +272,35 @@ mkdir -p "$BACKUP_DIR"
# Shared backup directory (can be overridden in .env)
SHARED_BACKUP_DIR="${SHARED_BACKUP_DIR:-/mnt/share/media/backups/immich}"
# Generate timestamp for the backup filename
# Handle upload-only mode
if [ "$UPLOAD_ONLY" = true ]; then
log_message "=== UPLOAD ONLY MODE ==="
log_message "Skipping backup creation, looking for latest backups in $SHARED_BACKUP_DIR"
# Find latest database backup
LATEST_DB=$(ls -t "$SHARED_BACKUP_DIR"/immich_db_backup_*.sql.gz 2>/dev/null | head -n1)
if [ -f "$LATEST_DB" ]; then
log_message "Found latest database backup: $LATEST_DB"
upload_to_b2 "$LATEST_DB"
else
log_message "Warning: No database backup found in $SHARED_BACKUP_DIR"
fi
# Find latest uploads backup
LATEST_UPLOADS=$(ls -t "$SHARED_BACKUP_DIR"/immich_uploads_*.tar.gz 2>/dev/null | head -n1)
if [ -f "$LATEST_UPLOADS" ]; then
log_message "Found latest uploads backup: $LATEST_UPLOADS"
upload_to_b2 "$LATEST_UPLOADS"
else
log_message "Warning: No uploads backup found in $SHARED_BACKUP_DIR"
fi
log_message "Upload only mode completed."
exit 0
fi
# Create backup directory if it doesn't exist
BACKUP_DIR="$(dirname "$0")/../immich_backups"
BACKUP_DIR="${SCRIPT_DIR}/../immich_backups"
mkdir -p "$BACKUP_DIR"
# Generate timestamp for the backup filename
@@ -446,8 +500,9 @@ log_message "Creating compressed archive of upload directory..."
log_message "This may take a while depending on the size of your media library..."
# Use tar with progress indication and exclude any existing backup files in the upload location
if ! tar --exclude="${UPLOAD_LOCATION}/backups/*.tar.gz" \
--exclude="${UPLOAD_LOCATION}/backups/*.sql.gz" \
# Note: Exclude patterns must match the relative path structure used by -C
if ! tar --exclude="$(basename "${UPLOAD_LOCATION}")/backups/*.tar.gz" \
--exclude="$(basename "${UPLOAD_LOCATION}")/backups/*.sql.gz" \
-czf "${UPLOAD_BACKUP_PATH}" \
-C "$(dirname "${UPLOAD_LOCATION}")" \
"$(basename "${UPLOAD_LOCATION}")"; then