Add flexible scheduling and manual backup selection for hybrid mode

This enhancement adds two major improvements to hybrid backup mode:

1. SEPARATE SCHEDULE CONFIGURATION:
   - Block device backups now have independent scheduling from file backups
   - Options: weekly, biweekly, monthly, custom day of week/month
   - File backups run on main schedule, block device on separate schedule
   - Stored in BLOCK_DEVICE_FREQUENCY and BLOCK_DEVICE_DAY config variables
   - Backup script checks date/week to determine if block backup should run

2. MANUAL BACKUP SELECTION:
   - Interactive menu when running backup in hybrid mode
   - Three options: files only, block only, or both
   - Files only: fast (~2-3 min) for quick daily archives
   - Block only: slow (~20-30 min) for VM conversion capability
   - Both: complete backup of everything
   - Backup script accepts "files", "block", or "yes" as FORCE_FULL parameter

These features provide fine-grained control over backup execution while
maintaining the convenience of hybrid mode. Users can now optimize
backup frequency based on their needs (frequent file backups, less
frequent disk images) and selectively run specific backup types manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zaphod-black 2025-11-01 22:15:45 -05:00
parent d26ede3702
commit c51b5b03ee
2 changed files with 187 additions and 44 deletions

View file

@ -49,6 +49,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Syntax validated
- Needs functional testing
- Needs migration testing from legacy configs
- **Flexible block device scheduling in hybrid mode**
- Separate schedule configuration for block device backups vs file backups
- Block device schedule options:
- Weekly (specific day of week, default Sunday)
- Biweekly (every other week on specific day)
- Monthly (specific day of month)
- Custom day of week (1-7, Monday-Sunday)
- Custom day of month (1-31)
- File backups run on main schedule, block device on independent schedule
- Configuration stored in BLOCK_DEVICE_FREQUENCY and BLOCK_DEVICE_DAY variables
- **Manual backup selection for hybrid mode**
- Interactive menu when running backup in hybrid mode
- Three options:
- Files only (fast ~2-3 minutes) - daily file archives
- Block device only (slow ~20-30 minutes) - full disk image for VM conversion
- Both files and block device (complete backup)
- Allows selective backup execution without changing configuration
- Backup script supports three FORCE_FULL values: "files", "block", "yes"
- Intelligent reconfiguration options when PBS client is already installed
- Quick connection-only reconfiguration (server/credentials only)
- Full reconfiguration of all settings

View file

@ -872,52 +872,67 @@ run_backup_for_target() {
return 1
fi
info "Running FULL backup for target: $target_name"
# Load target config to check backup type
local config_file="$(get_target_config_path "$target_name")"
source "$config_file"
# If hybrid mode, ask what to backup
local BACKUP_MODE="yes" # Default: full backup
if [[ "$BACKUP_TYPE" == "both" ]]; then
echo
info "This target is configured for hybrid backups (files + block device)"
echo
echo "What would you like to backup?"
echo " 1) Files only (fast ~2-3 minutes)"
echo " 2) Block device only (slow ~20-30 minutes, enables VM conversion)"
echo " 3) Both files and block device (full backup)"
BACKUP_CHOICE=$(prompt "Select option [1/2/3]" "3")
case "$BACKUP_CHOICE" in
1)
BACKUP_MODE="files"
info "Running files-only backup for target: $target_name"
;;
2)
BACKUP_MODE="block"
info "Running block device backup for target: $target_name"
;;
3)
BACKUP_MODE="yes"
info "Running FULL backup (files + block device) for target: $target_name"
;;
*)
warn "Invalid choice, defaulting to full backup"
BACKUP_MODE="yes"
info "Running FULL backup for target: $target_name"
;;
esac
else
info "Running backup for target: $target_name"
fi
echo
# Show real-time progress
echo "╔════════════════════════════════════════════════════════════╗"
echo "║ Backup Progress (Live) - Target: $target_name"
echo "║ Press Ctrl+C to exit (backup continues in background) ║"
if [[ "$BACKUP_TYPE" == "both" ]]; then
echo "║ Mode: $BACKUP_MODE"
fi
echo "║ Press Ctrl+C to stop viewing (backup continues) ║"
echo "╚════════════════════════════════════════════════════════════╝"
echo
# Start the manual backup (forces full backup)
systemctl start "pbs-backup-${target_name}-manual.service" &
# Wait a brief moment for service to register
sleep 0.5
# Monitor backup in background and kill journalctl when done
(
while systemctl is-active --quiet "pbs-backup-${target_name}-manual.service"; do
sleep 2
done
# Service finished, kill the journal follow
pkill -P $$ journalctl 2>/dev/null
) &
MONITOR_PID=$!
# Follow logs in foreground from the start
journalctl -u "pbs-backup-${target_name}-manual.service" -f --since "2 seconds ago" || true
# Wait for monitor to finish
wait $MONITOR_PID 2>/dev/null
# Clear any leftover output
echo
echo "════════════════════════════════════════════════════════════"
# Check final status
if systemctl status "pbs-backup-${target_name}-manual.service" | grep -q "Active: failed"; then
# Run backup script directly with the chosen mode
if "$CONFIG_DIR/backup-${target_name}.sh" "$BACKUP_MODE"; then
echo
log "Backup completed successfully!"
else
echo
error "Backup failed!"
echo
info "Check full logs with:"
echo " sudo journalctl -u pbs-backup-${target_name}-manual.service -n 50"
else
echo
log "Backup completed successfully!"
info "Check logs above for details"
return 1
fi
}
@ -1050,7 +1065,66 @@ interactive_config() {
TIMER_SCHEDULE="custom"
;;
esac
# If hybrid mode, ask for block device schedule separately
if [[ "$BACKUP_TYPE" == "both" ]]; then
echo
info "Block Device Backup Schedule:"
echo " Block device backups are slower (20-30 min) but enable VM conversion."
echo " File backups will run on the schedule above."
echo
echo " 1) Weekly (recommended - every Sunday)"
echo " 2) Biweekly (every other Sunday)"
echo " 3) Monthly (1st of each month)"
echo " 4) Custom day of week"
echo " 5) Custom day of month"
BLOCK_SCHEDULE_TYPE=$(prompt "Select block device schedule [1/2/3/4/5]" "1")
case "$BLOCK_SCHEDULE_TYPE" in
1)
BLOCK_DEVICE_FREQUENCY="weekly"
BLOCK_DEVICE_DAY="7" # Sunday
;;
2)
BLOCK_DEVICE_FREQUENCY="biweekly"
BLOCK_DEVICE_DAY="7" # Sunday
;;
3)
BLOCK_DEVICE_FREQUENCY="monthly"
BLOCK_DEVICE_DAY="1" # 1st of month
;;
4)
BLOCK_BACKUP_DOW=$(prompt "Enter day of week for block device (Mon-Sun)" "Sun")
BLOCK_DEVICE_FREQUENCY="weekly"
# Convert day name to number (1=Mon, 7=Sun)
case "$BLOCK_BACKUP_DOW" in
Mon|mon|MON|Monday|1) BLOCK_DEVICE_DAY="1" ;;
Tue|tue|TUE|Tuesday|2) BLOCK_DEVICE_DAY="2" ;;
Wed|wed|WED|Wednesday|3) BLOCK_DEVICE_DAY="3" ;;
Thu|thu|THU|Thursday|4) BLOCK_DEVICE_DAY="4" ;;
Fri|fri|FRI|Friday|5) BLOCK_DEVICE_DAY="5" ;;
Sat|sat|SAT|Saturday|6) BLOCK_DEVICE_DAY="6" ;;
Sun|sun|SUN|Sunday|7) BLOCK_DEVICE_DAY="7" ;;
*) BLOCK_DEVICE_DAY="7" ;;
esac
;;
5)
BLOCK_BACKUP_DOM=$(prompt "Enter day of month (1-31)" "1")
BLOCK_DEVICE_FREQUENCY="monthly"
BLOCK_DEVICE_DAY="$BLOCK_BACKUP_DOM"
;;
*)
warn "Invalid choice, defaulting to weekly (Sunday)"
BLOCK_DEVICE_FREQUENCY="weekly"
BLOCK_DEVICE_DAY="7"
;;
esac
else
# Not hybrid mode, set defaults (won't be used)
BLOCK_DEVICE_FREQUENCY="weekly"
BLOCK_DEVICE_DAY="7"
fi
echo
# Retention policy
info "Retention Policy:"
@ -1437,6 +1511,8 @@ BACKUP_TYPE="${BACKUP_TYPE}"
BACKUP_PATHS="${BACKUP_PATHS}"
EXCLUDE_PATTERNS="${EXCLUDE_PATTERNS}"
BLOCK_DEVICE="${BLOCK_DEVICE}"
BLOCK_DEVICE_FREQUENCY="${BLOCK_DEVICE_FREQUENCY}"
BLOCK_DEVICE_DAY="${BLOCK_DEVICE_DAY}"
TIMER_SCHEDULE="${TIMER_SCHEDULE}"
TIMER_ONCALENDAR="${TIMER_ONCALENDAR}"
KEEP_LAST=${KEEP_LAST}
@ -1553,18 +1629,67 @@ case "\$BACKUP_TYPE" in
backup_block_device || BACKUP_SUCCESS=false
;;
both)
# Do file backup first (faster, more frequent)
backup_files || BACKUP_SUCCESS=false
# Determine what to backup
SHOULD_RUN_FILES=true
SHOULD_RUN_BLOCK=false
# Do block device backup on Sunday OR if manually forced
if [ "\$FORCE_FULL" = "yes" ]; then
log "Manual full backup - including block device"
backup_block_device || BACKUP_SUCCESS=false
elif [ "\$(date +%u)" -eq 7 ]; then
log "Weekly block device backup day (Sunday)"
log "Manual full backup - running both files and block device"
SHOULD_RUN_FILES=true
SHOULD_RUN_BLOCK=true
elif [ "\$FORCE_FULL" = "files" ]; then
log "Manual files-only backup"
SHOULD_RUN_FILES=true
SHOULD_RUN_BLOCK=false
elif [ "\$FORCE_FULL" = "block" ]; then
log "Manual block-only backup"
SHOULD_RUN_FILES=false
SHOULD_RUN_BLOCK=true
else
# Scheduled backup - check if it's time based on frequency
CURRENT_DOW=\$(date +%u) # 1=Mon, 7=Sun
CURRENT_DOM=\$(date +%d | sed 's/^0//') # Remove leading zero
case "\$BLOCK_DEVICE_FREQUENCY" in
weekly)
if [ "\$CURRENT_DOW" -eq "\$BLOCK_DEVICE_DAY" ]; then
log "Weekly block device backup day (day \$BLOCK_DEVICE_DAY)"
SHOULD_RUN_BLOCK=true
fi
;;
biweekly)
WEEK_OF_YEAR=\$(date +%V)
if [ "\$CURRENT_DOW" -eq "\$BLOCK_DEVICE_DAY" ] && [ \$((WEEK_OF_YEAR % 2)) -eq 0 ]; then
log "Biweekly block device backup day (even week, day \$BLOCK_DEVICE_DAY)"
SHOULD_RUN_BLOCK=true
fi
;;
monthly)
if [ "\$CURRENT_DOM" -eq "\$BLOCK_DEVICE_DAY" ]; then
log "Monthly block device backup day (\$BLOCK_DEVICE_DAY of month)"
SHOULD_RUN_BLOCK=true
fi
;;
*)
log "Unknown BLOCK_DEVICE_FREQUENCY: \$BLOCK_DEVICE_FREQUENCY, defaulting to weekly Sunday"
if [ "\$CURRENT_DOW" -eq 7 ]; then
SHOULD_RUN_BLOCK=true
fi
;;
esac
fi
# Execute backups based on decisions
if [ "\$SHOULD_RUN_FILES" = true ]; then
backup_files || BACKUP_SUCCESS=false
else
log "Skipping file backup (block-only mode)"
fi
if [ "\$SHOULD_RUN_BLOCK" = true ]; then
backup_block_device || BACKUP_SUCCESS=false
else
log "Skipping block device backup (runs weekly on Sunday, or use 'Run backup now' for immediate full backup)"
log "Skipping block device backup (next: \${BLOCK_DEVICE_FREQUENCY} on day \${BLOCK_DEVICE_DAY})"
fi
;;
*)