#!/bin/bash # Configuration backupPath='/mnt/backups' password_file="/etc/restic-password" LOG_DIR="$HOME/mb-backups/logs" LOG_FILE="${LOG_DIR}/backup_sessions.log" ERROR_LOG_FILE="${LOG_DIR}/backup_sessions_error.log" # Ensure log directory exists mkdir -p "$LOG_DIR" # Logging function log_message() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } # Error logging function log_error() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1" | tee -a "$ERROR_LOG_FILE" } # Function: Display usage display_usage() { echo "Usage: $0 [options]" echo "" echo "Options:" echo " sessions - Show all complete backup sessions" echo " incomplete - Show incomplete backup sessions" echo " all - Show all snapshots grouped by session" echo " validate - Validate a specific backup session" echo "" echo "Examples:" echo " $0 sessions" echo " $0 validate manual-backup-2024-01-15_10-30-45" exit 1 } # Function: Validate repository access validate_repository() { log_message "Validating repository access..." if [ ! -d "$backupPath" ]; then log_error "Backup path '$backupPath' does not exist or is not accessible." echo "Restic repository path not found. Please verify that the path exists and is mounted." exit 1 fi if ! RESTIC_PASSWORD=$(cat "$password_file") restic -r "$backupPath" snapshots &>/dev/null; then log_message "Attempting to fix permissions for '$backupPath'..." sudo chown -R "$(whoami)":"$(whoami)" "$backupPath" 2>/dev/null || true sudo chmod -R u+rwX "$backupPath" 2>/dev/null || true if ! RESTIC_PASSWORD=$(cat "$password_file") restic -r "$backupPath" snapshots &>/dev/null; then log_error "Unable to access Restic repository at '$backupPath'." echo "Restic repository is inaccessible. Please check the path, permissions, or mount status." exit 1 fi fi log_message "Repository access validated successfully." } # Function: Get all snapshots with session analysis get_all_snapshots() { log_message "Retrieving all snapshots for session analysis..." local snapshots_json snapshots_json=$(RESTIC_PASSWORD=$(cat "$password_file") restic -r "$backupPath" snapshots --json 2>/dev/null) if [ $? -ne 0 ] || [ -z "$snapshots_json" ]; then log_error "Failed to retrieve snapshots from repository." return 1 fi echo "$snapshots_json" return 0 } # Function: Extract backup session tags extract_session_tags() { local snapshots_json="$1" # Extract all session tags (manual-backup-* and automated-backup-*) echo "$snapshots_json" | jq -r '.[].tags[]' | grep -E '^(manual|automated)-backup-[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}$' | sort | uniq } # Function: Analyze backup session completeness analyze_session_completeness() { local snapshots_json="$1" local session_tag="$2" # Get all snapshots for this session local session_snapshots session_snapshots=$(echo "$snapshots_json" | jq -r ".[] | select(.tags[] | contains(\"$session_tag\"))") # Count snapshots in session local snapshot_count snapshot_count=$(echo "$session_snapshots" | jq -s '. | length') # Extract component tags local has_core=false local has_media=false local has_db=false if echo "$session_snapshots" | jq -r '.tags[]' | grep -q "^core_files$"; then has_core=true fi if echo "$session_snapshots" | jq -r '.tags[]' | grep -q "^media_themes$"; then has_media=true fi if echo "$session_snapshots" | jq -r '.tags[]' | grep -q "^wordpress_db$"; then has_db=true fi # Determine session status local status="INCOMPLETE" local missing_components=() if [ "$has_core" = true ] && [ "$has_media" = true ] && [ "$has_db" = true ] && [ "$snapshot_count" -eq 3 ]; then status="COMPLETE" else if [ "$has_core" = false ]; then missing_components+=("core_files") fi if [ "$has_media" = false ]; then missing_components+=("media_themes") fi if [ "$has_db" = false ]; then missing_components+=("wordpress_db") fi fi # Get session timestamp local session_time session_time=$(echo "$session_snapshots" | jq -r '.time' | head -n1) # Output session info echo "$session_tag|$status|$snapshot_count|$session_time|$(IFS=,; echo "${missing_components[*]}")" } # Function: Display complete backup sessions display_complete_sessions() { log_message "Displaying complete backup sessions..." local snapshots_json snapshots_json=$(get_all_snapshots) if [ $? -ne 0 ]; then echo "Failed to retrieve snapshots." return 1 fi local session_tags session_tags=$(extract_session_tags "$snapshots_json") if [ -z "$session_tags" ]; then echo "No backup sessions found." return 0 fi echo "=== COMPLETE BACKUP SESSIONS ===" echo "Format: [Session Tag] [Date/Time] [Status]" echo "========================================" local complete_sessions=0 while IFS= read -r session_tag; do if [ -n "$session_tag" ]; then local session_info session_info=$(analyze_session_completeness "$snapshots_json" "$session_tag") local status status=$(echo "$session_info" | cut -d'|' -f2) if [ "$status" = "COMPLETE" ]; then local session_time session_time=$(echo "$session_info" | cut -d'|' -f4) printf "%-45s %s [%s]\n" "$session_tag" "$session_time" "$status" ((complete_sessions++)) fi fi done <<< "$session_tags" echo "========================================" echo "Total complete backup sessions: $complete_sessions" echo "" echo "To restore a complete session, use:" echo " ./restore_full_backup_session.sh " } # Function: Display incomplete backup sessions display_incomplete_sessions() { log_message "Displaying incomplete backup sessions..." local snapshots_json snapshots_json=$(get_all_snapshots) if [ $? -ne 0 ]; then echo "Failed to retrieve snapshots." return 1 fi local session_tags session_tags=$(extract_session_tags "$snapshots_json") if [ -z "$session_tags" ]; then echo "No backup sessions found." return 0 fi echo "=== INCOMPLETE BACKUP SESSIONS ===" echo "Format: [Session Tag] [Date/Time] [Status] [Missing Components]" echo "=================================================================" local incomplete_sessions=0 while IFS= read -r session_tag; do if [ -n "$session_tag" ]; then local session_info session_info=$(analyze_session_completeness "$snapshots_json" "$session_tag") local status status=$(echo "$session_info" | cut -d'|' -f2) if [ "$status" = "INCOMPLETE" ]; then local session_time missing_components session_time=$(echo "$session_info" | cut -d'|' -f4) missing_components=$(echo "$session_info" | cut -d'|' -f5) printf "%-45s %s [%s] Missing: %s\n" "$session_tag" "$session_time" "$status" "$missing_components" ((incomplete_sessions++)) fi fi done <<< "$session_tags" echo "=================================================================" echo "Total incomplete backup sessions: $incomplete_sessions" echo "" echo "WARNING: Incomplete sessions cannot be used for full restoration." } # Function: Display all sessions with details display_all_sessions() { log_message "Displaying all backup sessions with details..." local snapshots_json snapshots_json=$(get_all_snapshots) if [ $? -ne 0 ]; then echo "Failed to retrieve snapshots." return 1 fi local session_tags session_tags=$(extract_session_tags "$snapshots_json") if [ -z "$session_tags" ]; then echo "No backup sessions found." return 0 fi echo "=== ALL BACKUP SESSIONS ===" echo "Format: [Session Tag] [Date/Time] [Status] [Snapshot Count] [Missing Components]" echo "=============================================================================" local total_sessions=0 local complete_sessions=0 while IFS= read -r session_tag; do if [ -n "$session_tag" ]; then local session_info session_info=$(analyze_session_completeness "$snapshots_json" "$session_tag") local status session_time snapshot_count missing_components status=$(echo "$session_info" | cut -d'|' -f2) snapshot_count=$(echo "$session_info" | cut -d'|' -f3) session_time=$(echo "$session_info" | cut -d'|' -f4) missing_components=$(echo "$session_info" | cut -d'|' -f5) if [ "$status" = "COMPLETE" ]; then printf "%-45s %s [%s] (%d snapshots)\n" "$session_tag" "$session_time" "$status" "$snapshot_count" ((complete_sessions++)) else printf "%-45s %s [%s] (%d snapshots) Missing: %s\n" "$session_tag" "$session_time" "$status" "$snapshot_count" "$missing_components" fi ((total_sessions++)) fi done <<< "$session_tags" echo "=============================================================================" echo "Total sessions: $total_sessions (Complete: $complete_sessions, Incomplete: $((total_sessions - complete_sessions)))" } # Function: Validate specific backup session validate_backup_session() { local session_tag="$1" log_message "Validating backup session: $session_tag" # Validate session tag format if [[ ! "$session_tag" =~ ^(manual|automated)-backup-[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}$ ]]; then echo "ERROR: Invalid backup session tag format." echo "Expected format: manual-backup-YYYY-MM-DD_HH-MM-SS or automated-backup-YYYY-MM-DD_HH-MM-SS" return 1 fi local snapshots_json snapshots_json=$(get_all_snapshots) if [ $? -ne 0 ]; then echo "Failed to retrieve snapshots." return 1 fi # Check if session exists local session_snapshots session_snapshots=$(echo "$snapshots_json" | jq -r ".[] | select(.tags[] | contains(\"$session_tag\"))") if [ -z "$session_snapshots" ]; then echo "ERROR: No snapshots found for session tag '$session_tag'." return 1 fi # Analyze session local session_info session_info=$(analyze_session_completeness "$snapshots_json" "$session_tag") local status snapshot_count session_time missing_components status=$(echo "$session_info" | cut -d'|' -f2) snapshot_count=$(echo "$session_info" | cut -d'|' -f3) session_time=$(echo "$session_info" | cut -d'|' -f4) missing_components=$(echo "$session_info" | cut -d'|' -f5) echo "=== BACKUP SESSION VALIDATION ===" echo "Session Tag: $session_tag" echo "Session Time: $session_time" echo "Status: $status" echo "Snapshot Count: $snapshot_count" if [ "$status" = "COMPLETE" ]; then echo "✓ All required components present:" echo " ✓ Core Files (core_files)" echo " ✓ Media Files (media_themes)" echo " ✓ Database (wordpress_db)" echo "" echo "This session is ready for full restoration using:" echo " ./restore_full_backup_session.sh $session_tag" else echo "✗ Session is incomplete. Missing components:" IFS=',' read -ra MISSING <<< "$missing_components" for component in "${MISSING[@]}"; do echo " ✗ $component" done echo "" echo "WARNING: This session cannot be used for full restoration." fi echo "=================================" # Show individual snapshots in session echo "" echo "Individual snapshots in this session:" echo "$session_snapshots" | jq -r '" " + .short_id + " - " + .time + " - Tags: " + (.tags | join(", "))' } # Function: Validate environment validate_environment() { if [ ! -f "$password_file" ]; then log_error "Password file not found at $password_file" exit 1 fi validate_repository } # Main script logic main() { local action="${1:-sessions}" case "$action" in "sessions") validate_environment display_complete_sessions ;; "incomplete") validate_environment display_incomplete_sessions ;; "all") validate_environment display_all_sessions ;; "validate") if [ -z "$2" ]; then echo "ERROR: Session tag required for validation." echo "Usage: $0 validate " exit 1 fi validate_environment validate_backup_session "$2" ;; *) display_usage ;; esac } # Run main function main "$@"