mb-backup-manager/scripts/imports/manage_backup_schedule.sh

196 lines
5.3 KiB
Bash

#!/bin/bash
# Enable strict error handling
set -euo pipefail
trap 'handle_error $? $LINENO' ERR
# Configuration
BACKUP_SCRIPT="/home/litespeed/mb-backups/backup_all.sh"
LOG_DIR="/home/litespeed/mb-backups/logs/auto"
ACTION_LOG_FILE="${LOG_DIR}/schedule_actions.log"
BACKUP_LOG_PREFIX="${LOG_DIR}/backup_"
PASSWORD_FILE="/etc/restic-password"
LOCK_FILE="/tmp/backup_schedule.lock"
MAX_RETRIES=3
RETRY_DELAY=5
# Error handling function
handle_error() {
local exit_code=$1
local line_no=$2
log_action "ERROR: Command failed at line ${line_no} with exit code ${exit_code}"
cleanup_and_exit 1
}
# Cleanup function
cleanup_and_exit() {
local exit_code=$1
[ -f "$LOCK_FILE" ] && rm -f "$LOCK_FILE"
exit "${exit_code}"
}
# Ensure single instance
ensure_single_instance() {
if [ -f "$LOCK_FILE" ]; then
if kill -0 "$(cat "$LOCK_FILE")" 2>/dev/null; then
log_action "ERROR: Another instance is running"
exit 1
fi
fi
echo $$ > "$LOCK_FILE"
}
# Enhanced logging function
log_action() {
local timestamp=$(date +'%Y-%m-%d %H:%M:%S')
local log_msg="[$timestamp] $1"
echo "$log_msg" | tee -a "$ACTION_LOG_FILE"
# Log critical errors to system log
if [[ "$1" == *"ERROR"* ]]; then
logger -t "backup-schedule" "$1"
fi
}
# Validate system requirements
check_system_requirements() {
local required_space=1048576 # 1GB in KB
local available_space=$(df -k "$LOG_DIR" | awk 'NR==2 {print $4}')
if [ ! -x "$BACKUP_SCRIPT" ]; then
log_action "ERROR: Backup script not executable or not found"
return 1
fi
if [ "$available_space" -lt "$required_space" ]; then
log_action "ERROR: Insufficient disk space"
return 1
}
return 0
}
# Validate cron schedule
validate_schedule() {
local schedule="$1"
if ! [[ $schedule =~ ^[0-9,\*/-]+ [0-9,\*/-]+ [0-9,\*/-]+ [0-9,\*/-]+ [0-9,\*/-]+$ ]]; then
log_action "ERROR: Invalid cron schedule format: $schedule"
return 1
fi
return 0
}
# Get Restic password with retry mechanism
get_restic_password() {
local retry_count=0
while [ $retry_count -lt $MAX_RETRIES ]; do
if [ -f "$PASSWORD_FILE" ] && [ -s "$PASSWORD_FILE" ]; then
cat "$PASSWORD_FILE"
return 0
fi
retry_count=$((retry_count + 1))
sleep $RETRY_DELAY
done
log_action "ERROR: Failed to retrieve Restic password after $MAX_RETRIES attempts"
return 1
}
# Enhanced cron job management
add_update_cron_job() {
local action="$1"
local schedule="$2"
local restic_password="$3"
local temp_crontab="/tmp/temp_crontab.$$"
# Validate inputs
if ! validate_schedule "$schedule"; then
return 1
fi
# Prepare cron command with environment variables and error handling
local CMD="RESTIC_PASSWORD=\"$restic_password\" \
LOG_FILE=\"${BACKUP_LOG_PREFIX}\$(date +\\%Y-\\%m-\\%d_\\%H-\\%M-\\%S).log\" \
$BACKUP_SCRIPT > \"\$LOG_FILE\" 2>&1 || echo \"\$(date) Backup failed\" >> \"$ACTION_LOG_FILE\""
# Safely update crontab
crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT" > "$temp_crontab" || true
echo "$schedule $CMD" >> "$temp_crontab"
if crontab "$temp_crontab"; then
log_action "Successfully ${action}d backup schedule: $schedule"
rm -f "$temp_crontab"
return 0
else
log_action "ERROR: Failed to ${action} backup schedule"
rm -f "$temp_crontab"
return 1
fi
}
# Enhanced cron job removal
remove_cron_job() {
local temp_crontab="/tmp/temp_crontab.$$"
if crontab -l 2>/dev/null | grep -q "$BACKUP_SCRIPT"; then
crontab -l | grep -v "$BACKUP_SCRIPT" > "$temp_crontab"
if crontab "$temp_crontab"; then
log_action "Backup schedule successfully removed"
rm -f "$temp_crontab"
return 0
else
log_action "ERROR: Failed to remove backup schedule"
rm -f "$temp_crontab"
return 1
fi
else
log_action "No backup schedule found to remove"
return 0
fi
}
# Main execution
main() {
# Create log directory with proper permissions
mkdir -p "$LOG_DIR"
chmod 750 "$LOG_DIR"
# Ensure single instance
ensure_single_instance
# Check system requirements
if ! check_system_requirements; then
cleanup_and_exit 1
fi
case $1 in
add|update)
if [ "$#" -ne 3 ]; then
log_action "Usage: $0 {add|update} 'schedule' 'restic_password'"
log_action "Example: $0 add '0 1 * * *' 'secret_password'"
cleanup_and_exit 1
fi
local restic_password="${3:-$(get_restic_password)}"
if [ -z "$restic_password" ]; then
cleanup_and_exit 1
fi
add_update_cron_job "$1" "$2" "$restic_password"
;;
remove)
remove_cron_job
;;
status)
crontab -l | grep "$BACKUP_SCRIPT" || echo "No backup schedule found"
;;
*)
log_action "Invalid action: $1. Use add, update, remove, or status"
cleanup_and_exit 1
;;
esac
cleanup_and_exit 0
}
# Execute main function with all arguments
main "$@"