feat: Implement comprehensive restore functionality for Immich

- Added `restore-immich.sh` script to handle complete restoration from backups.
- Implemented database restoration with integrity checks and error handling.
- Added uploads restoration with proper ownership and permissions setup.
- Introduced validation script `validate-immich-backups.sh` for backup integrity checks.
- Created test suite `test-immich-restore.sh` to validate restoration functionality with mock data.
- Enhanced logging and notification features for restoration processes.
- Updated README.md with detailed usage instructions for backup and restore workflows.
This commit is contained in:
Peter Wood
2025-06-03 14:38:55 -04:00
parent 48e51fa094
commit c1479a8b0c
5 changed files with 1188 additions and 46 deletions

View File

@@ -3,8 +3,7 @@
# Immich Backup Validation Script
# This script validates Immich backup files for integrity and completeness
# Set up error handling
set -e
# Note: We don't use set -e here to ensure all validations are performed
# Colors for output
RED='\033[0;31m'
@@ -65,17 +64,17 @@ if [ -z "$DB_BACKUPS" ]; then
else
for backup in $DB_BACKUPS; do
echo "Validating: $(basename "$backup")"
# Check file size
SIZE=$(stat -c%s "$backup" 2>/dev/null || echo "0")
if [ "$SIZE" -lt 1024 ]; then
if [ "$SIZE" -lt 100 ]; then
echo -e " ${RED}✗ File is too small (${SIZE} bytes)${NC}"
log_validation "Error: File is too small (${SIZE} bytes) - $(basename "$backup")"
((TOTAL_ERRORS++))
else
echo -e " ${GREEN}✓ File size OK ($(du -h "$backup" | cut -f1))${NC}"
fi
# Check if it's a valid gzip file
if gzip -t "$backup" 2>/dev/null; then
echo -e " ${GREEN}✓ Gzip file integrity OK${NC}"
@@ -84,14 +83,14 @@ else
log_validation "Error: Gzip file corruption detected - $(basename "$backup")"
((TOTAL_ERRORS++))
fi
# Check if SQL content looks valid (basic check)
if zcat "$backup" 2>/dev/null | head -n 10 | grep -q "PostgreSQL database dump"; then
echo -e " ${GREEN}✓ SQL content appears valid${NC}"
else
echo -e " ${YELLOW}? Cannot verify SQL content format${NC}"
fi
echo ""
done
fi
@@ -104,21 +103,21 @@ if [ -z "$UPLOAD_BACKUPS" ]; then
else
for backup in $UPLOAD_BACKUPS; do
echo "Validating: $(basename "$backup")"
# Check file size
SIZE=$(stat -c%s "$backup" 2>/dev/null || echo "0")
if [ "$SIZE" -lt 1024 ]; then
if [ "$SIZE" -lt 100 ]; then
echo -e " ${RED}✗ File is too small (${SIZE} bytes)${NC}"
log_validation "Error: File is too small (${SIZE} bytes) - $(basename "$backup")"
((TOTAL_ERRORS++))
else
echo -e " ${GREEN}✓ File size OK ($(du -h "$backup" | cut -f1))${NC}"
fi
# Check if it's a valid tar.gz file
if tar -tzf "$backup" >/dev/null 2>&1; then
echo -e " ${GREEN}✓ Tar.gz file integrity OK${NC}"
# Count files in archive
FILE_COUNT=$(tar -tzf "$backup" 2>/dev/null | wc -l)
echo -e " ${GREEN}✓ Archive contains ${FILE_COUNT} files/directories${NC}"
@@ -127,7 +126,7 @@ else
log_validation "Error: Tar.gz file corruption detected - $(basename "$backup")"
((TOTAL_ERRORS++))
fi
echo ""
done
fi
@@ -159,11 +158,50 @@ for upload_ts in $UPLOAD_TIMESTAMPS; do
fi
done
# Find most recent complete backup set
LATEST_COMPLETE=""
for db_ts in $DB_TIMESTAMPS; do
if echo "$UPLOAD_TIMESTAMPS" | grep -q "^${db_ts}$"; then
LATEST_COMPLETE="$db_ts"
break # First one is most recent due to sort -r
fi
done
echo ""
echo "=== VALIDATION SUMMARY ==="
echo "Complete backup pairs: $MATCHED_PAIRS"
echo "Total validation errors: $TOTAL_ERRORS"
if [ -n "$LATEST_COMPLETE" ]; then
echo -e "${GREEN}Most recent complete backup: $LATEST_COMPLETE${NC}"
echo ""
echo "=== RESTORATION COMMANDS ==="
echo "To restore the most recent complete backup:"
echo ""
echo "# Dry run (recommended first):"
echo "./restore-immich.sh \\"
echo " --db-backup \"$BACKUP_DIR/immich_db_backup_${LATEST_COMPLETE}.sql.gz\" \\"
echo " --uploads-backup \"$BACKUP_DIR/immich_uploads_${LATEST_COMPLETE}.tar.gz\" \\"
echo " --dry-run"
echo ""
echo "# Actual restoration:"
echo "./restore-immich.sh \\"
echo " --db-backup \"$BACKUP_DIR/immich_db_backup_${LATEST_COMPLETE}.sql.gz\" \\"
echo " --uploads-backup \"$BACKUP_DIR/immich_uploads_${LATEST_COMPLETE}.tar.gz\""
echo ""
echo "# Restore database only:"
echo "./restore-immich.sh \\"
echo " --db-backup \"$BACKUP_DIR/immich_db_backup_${LATEST_COMPLETE}.sql.gz\" \\"
echo " --uploads-backup \"$BACKUP_DIR/immich_uploads_${LATEST_COMPLETE}.tar.gz\" \\"
echo " --skip-uploads"
echo ""
echo "# Restore uploads only:"
echo "./restore-immich.sh \\"
echo " --db-backup \"$BACKUP_DIR/immich_db_backup_${LATEST_COMPLETE}.sql.gz\" \\"
echo " --uploads-backup \"$BACKUP_DIR/immich_uploads_${LATEST_COMPLETE}.tar.gz\" \\"
echo " --skip-db"
fi
log_validation "Validation summary: $MATCHED_PAIRS complete backup pairs, $TOTAL_ERRORS errors"
if [ "$TOTAL_ERRORS" -eq 0 ]; then