From 1642074673d1e357efa55497ede4e1631fcb2e0a Mon Sep 17 00:00:00 2001 From: Anthony Date: Mon, 6 Jan 2025 23:13:20 +0800 Subject: [PATCH] Update commands --- changelogs.md | 7 ++ manifest.jps | 8 +- scripts/imports/backup_all.sh | 21 +++- scripts/imports/check_sched.sh | 136 +++++++++++++++++++--- scripts/imports/manage_backup_schedule.sh | 77 +++++++----- 5 files changed, 199 insertions(+), 50 deletions(-) diff --git a/changelogs.md b/changelogs.md index 0e5e226..12551cd 100644 --- a/changelogs.md +++ b/changelogs.md @@ -5,6 +5,7 @@ ### Added - Implemented Restic installation using a precompiled binary to reduce memory usage. - Added logic to create the Restic password file if it doesn't exist during installation. +- Automatic installation of the cronnext tool for next-run calculation. ### Fixed - Resolved issue with missing Restic password file causing auto backup configuration to fail. @@ -15,4 +16,10 @@ ### Updated - Updated `manifest.jps` to ensure Restic password file creation and log rotation setup. + +### Improved +- Improved logging with timestamps and detailed error/warning levels. +- Enhanced fallback mechanism to manually calculate the next run time for common cron schedules. +- Implemented notifications via Slack and email for failures or issues. +- Optimized error handling to gracefully manage unsupported schedules or tool failures. \ No newline at end of file diff --git a/manifest.jps b/manifest.jps index d8aca37..7eae44f 100644 --- a/manifest.jps +++ b/manifest.jps @@ -111,7 +111,7 @@ menu: action: viewFullBackups confirmText: Are you sure you want to view full backups? successText: Full backups listed successfully. - + - caption: View Core Backups action: viewCoreBackups confirmText: Are you sure you want to view core backups? @@ -125,8 +125,8 @@ menu: - caption: View Database Backups action: viewDatabaseBackups confirmText: Are you sure you want to view database backups? - successText: Database backups listed successfully. - + successText: Database backups listed successfully. + onUninstall: - removeScript @@ -172,7 +172,7 @@ actions: backupnow: - cmd[cp]: user: root - commands: bash /home/jelastic/mb-backups/backup_all.sh "${globals.envName}" + commands: bash /home/jelastic/mb-backups/backup_all.sh "backup_now" - return: type: info message: "${response.out}" diff --git a/scripts/imports/backup_all.sh b/scripts/imports/backup_all.sh index 8965c30..2717e0b 100644 --- a/scripts/imports/backup_all.sh +++ b/scripts/imports/backup_all.sh @@ -70,11 +70,15 @@ export RESTIC_PASSWORD=$(cat "$password_file") export RESTIC_REPOSITORY="$backupPath" # Check repository +check_backup_repo() { + restic snapshots > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: Backup repository is not accessible" | tee -a "$LOG_DIR/backup_error.log" + exit 1 + fi +} + check_backup_repo -if [ $? -ne 0 ]; then - echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: Backup repository check failed" | tee -a "$LOG_DIR/backup_error.log" - exit 1 -fi # Backup functions backup_core_files() { @@ -170,5 +174,10 @@ main() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] Full backup completed in $duration seconds" | tee -a "$main_log" } -# Execute main function -main \ No newline at end of file +# Argument handling +if [ "$1" == "backup_now" ]; then + main +else + echo "Usage: $0 backup_now" + exit 1 +fi diff --git a/scripts/imports/check_sched.sh b/scripts/imports/check_sched.sh index ebbf23f..c7e509c 100644 --- a/scripts/imports/check_sched.sh +++ b/scripts/imports/check_sched.sh @@ -1,21 +1,129 @@ #!/bin/bash -# Script to check for scheduled cron jobs for /home/litespeed/mb-backups/backup_all.sh - -# Define the script path to check in cron jobs +# Global Configuration SCRIPT_PATH="/home/litespeed/mb-backups/backup_all.sh" LOG_FILE="/home/litespeed/mb-backups/logs/cron_check.log" +CRON_SCHEDULE="0 0 * * *" -# Log the start of the script check -echo "[$(date)] Checking for automated backup cron job..." | tee -a "$LOG_FILE" +# Slack Webhook URL (optional) +SLACK_WEBHOOK_URL="https://hooks.slack.com/services/your/webhook/url" -# Check if the cron job is found in the crontab -CRON_JOB=$(crontab -l | grep -F "$SCRIPT_PATH") +# Email Notification (optional) +EMAIL="your_email@example.com" -if [ -z "$CRON_JOB" ]; then - echo "[$(date)] Automated Backups are NOT enabled." | tee -a "$LOG_FILE" -else - echo "[$(date)] Automated Backups are enabled with the following schedule:" | tee -a "$LOG_FILE" - echo "$CRON_JOB" | awk '{print "Schedule: " $1, $2, $3, $4, $5}' | tee -a "$LOG_FILE" - echo "[$(date)] Note: Computing the next human-readable run time requires external tools." | tee -a "$LOG_FILE" -fi +# Helper functions +log_message() { + local level="$1" + local message="$2" + echo "[$(date)] [$level] $message" | tee -a "$LOG_FILE" +} + +send_notification() { + local message="$1" + if [ -n "$SLACK_WEBHOOK_URL" ]; then + curl -X POST -H 'Content-type: application/json' \ + --data "{\"text\":\"$message\"}" "$SLACK_WEBHOOK_URL" + log_message "INFO" "Slack notification sent." + fi + + if [ -n "$EMAIL" ]; then + echo "$message" | mail -s "Backup Script Notification" "$EMAIL" + log_message "INFO" "Email notification sent." + fi +} + +check_cron_service() { + if ! systemctl is-active --quiet crond; then + log_message "ERROR" "Cron service is not running. Attempting to restart..." + sudo systemctl start crond && log_message "INFO" "Cron service restarted successfully." || { + log_message "ERROR" "Failed to restart cron service." + exit 1 + } + fi +} + +install_cronnext() { + log_message "INFO" "Checking for 'cronnext' tool..." + if ! command -v cronnext &> /dev/null; then + log_message "WARNING" "'cronnext' tool not found. Attempting to install..." + if command -v pip &> /dev/null; then + pip install cronnext && log_message "INFO" "'cronnext' installed successfully." || { + log_message "ERROR" "Failed to install 'cronnext'. Please install it manually." + send_notification "Cronnext installation failed. Please check the server configuration." + exit 1 + } + else + log_message "ERROR" "'pip' is not installed. Unable to install 'cronnext'." + send_notification "Pip is missing; unable to install Cronnext. Please investigate." + exit 1 + fi + else + log_message "INFO" "'cronnext' is already installed." + fi +} + +check_and_repair_cron() { + log_message "INFO" "Checking for existing cron job for $SCRIPT_PATH..." + local existing_job + existing_job=$(crontab -l 2>/dev/null | grep -F "$SCRIPT_PATH") + + if [ -z "$existing_job" ]; then + log_message "WARNING" "Automated backups are NOT enabled. Attempting to re-add cron job..." + (crontab -l 2>/dev/null; echo "$CRON_SCHEDULE SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin RESTIC_PASSWORD=\"YourResticPassword\" $SCRIPT_PATH > /home/litespeed/mb-backups/logs/auto/backup.log 2>&1") | crontab - && \ + log_message "INFO" "Cron job re-added successfully." || \ + log_message "ERROR" "Failed to add cron job." + else + log_message "INFO" "Automated backups are already enabled with the following schedule:" + echo "$existing_job" | awk '{print "Schedule: " $1, $2, $3, $4, $5}' | tee -a "$LOG_FILE" + fi +} + +calculate_next_run_fallback() { + local cron_schedule="$1" + case "$cron_schedule" in + "0 * * * *") # Hourly + date -d "+1 hour" "+%Y-%m-%d %H:00:00" + ;; + "0 0 * * *") # Daily at midnight + date -d "tomorrow 00:00" "+%Y-%m-%d %H:%M:%S" + ;; + "0 0 * * 0") # Weekly at midnight on Sunday + date -d "next sunday 00:00" "+%Y-%m-%d %H:%M:%S" + ;; + "*/15 * * * *") # Every 15 minutes + date -d "15 minutes" "+%Y-%m-%d %H:%M:%S" + ;; + *) # Unsupported schedules + log_message "ERROR" "Unsupported schedule for fallback: $cron_schedule" + echo "Unsupported schedule" + ;; + esac +} + +display_next_run() { + log_message "INFO" "Calculating next run time for the cron job..." + install_cronnext + + local next_run + next_run=$(cronnext "$CRON_SCHEDULE" 2>/dev/null) + + if [ -n "$next_run" ]; then + log_message "INFO" "Next scheduled run time: $next_run" + else + log_message "WARNING" "Failed to calculate next run time using 'cronnext'. Falling back to manual calculation..." + next_run=$(calculate_next_run_fallback "$CRON_SCHEDULE") + if [ "$next_run" == "Unsupported schedule" ]; then + send_notification "Failed to calculate next run time: unsupported schedule $CRON_SCHEDULE." + else + log_message "INFO" "Next scheduled run time (fallback): $next_run" + fi + fi +} + +# Main Execution +log_message "INFO" "Starting backup schedule verification script..." +check_cron_service +check_and_repair_cron +display_next_run + +log_message "INFO" "Backup schedule verification completed successfully." diff --git a/scripts/imports/manage_backup_schedule.sh b/scripts/imports/manage_backup_schedule.sh index c2480d4..990f73d 100644 --- a/scripts/imports/manage_backup_schedule.sh +++ b/scripts/imports/manage_backup_schedule.sh @@ -14,20 +14,17 @@ log_action() { } check_and_install_cron() { - # Check if cron is installed if ! command -v crontab &> /dev/null; then echo "Cron is not installed. Installing..." - sudo dnf install -y cronie + sudo dnf install -y cronie || { echo "Failed to install cron."; exit 1; } fi - # Check if cron is running if ! systemctl is-active --quiet crond; then echo "Starting cron service..." sudo systemctl start crond sudo systemctl enable crond fi - # Verify cron is running if systemctl is-active --quiet crond; then echo "Cron service is running." else @@ -37,30 +34,55 @@ check_and_install_cron() { fi } +validate_cron_syntax() { + local schedule="$1" + if ! echo "$schedule" | grep -Eq '^(\*|[0-9]|[0-5][0-9]) (\*|[0-9]|1[0-9]|2[0-3]) (\*|[0-9]|3[0-1]) (\*|[1-9]|1[0-2]) (\*|[0-6])$'; then + echo "Invalid cron schedule format: $schedule" + log_action "Invalid cron schedule format: $schedule" + exit 1 + fi +} + add_update_cron_job() { - # Verify Restic password is provided - if [ -z "$3" ]; then + local action="$1" + local schedule="$2" + local restic_password="$3" + + validate_cron_syntax "$schedule" + + if [ -z "$restic_password" ]; then echo "Restic password is required." - log_action "Attempted to add/update a schedule without providing a Restic password." + log_action "Attempted to $action a schedule without providing a Restic password." exit 1 fi - # Prepare the cron command to include dynamic date in the backup log filename - CMD="RESTIC_PASSWORD=\"$3\" $BACKUP_SCRIPT > \"${BACKUP_LOG_PREFIX}\$(date +\\%Y-\\%m-\\%d_\\%H-\\%M-\\%S).log\" 2>&1" + local restic_path="/usr/local/bin/restic" + if [ ! -x "$restic_path" ]; then + echo "Error: restic not found at $restic_path. Please verify installation." + log_action "restic not found at $restic_path" + exit 1 + fi - # Add or update the cron job - (crontab -l | grep -v "$BACKUP_SCRIPT" 2>/dev/null; echo "$2 $CMD") | crontab - - local update_msg="Backup schedule updated to: $2" - echo "$update_msg" - log_action "$update_msg" + # Prepare the cron job command + local cmd="SHELL=/bin/bash" + cmd+=" PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + cmd+=" RESTIC_PASSWORD=\"$restic_password\"" + cmd+=" $BACKUP_SCRIPT" + cmd+=" > \"${BACKUP_LOG_PREFIX}\$(date +\\%Y-\\%m-\\%d_\\%H-\\%M-\\%S).log\" 2>&1" - # Verify if the cron job was added - if crontab -l | grep -q "$CMD"; then - echo "Cron job added successfully." - log_action "Cron job added successfully." + # Debug: Output the command to verify + echo "Adding the following cron job:" + echo "$schedule $cmd" + + # Remove any existing lines containing $BACKUP_SCRIPT, then add the new one + (crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT"; echo "$schedule $cmd") | crontab - + + if crontab -l | grep -q "$BACKUP_SCRIPT"; then + echo "Cron job $action successfully." + log_action "Cron job $action successfully: $schedule" else - echo "Failed to add cron job." - log_action "Failed to add cron job." + echo "Failed to $action cron job. Please check logs for details." + log_action "Failed to $action cron job: $schedule" exit 1 fi } @@ -68,20 +90,23 @@ add_update_cron_job() { # Main execution check_and_install_cron -# Example usage: add or update a cron job -# Usage: ./manage_backup_schedule.sh add '0 1 * * *' 'your_restic_password' case $1 in add|update) if [ "$#" -ne 3 ]; then echo "Usage for add/update: $0 {add|update} 'schedule' 'restic_password'" - echo "Example: $0 add '0 1 * * *' 'secret_password'" - log_action "Incorrect usage for add/update. Correct format not followed." + log_action "Incorrect usage for $1. Format not followed." + exit 1 else - add_update_cron_job "$@" + add_update_cron_job "$1" "$2" "$3" fi ;; remove) - # Functionality to remove cron job can be added here + tmp_cron=$(mktemp) + crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT" > "$tmp_cron" + crontab "$tmp_cron" + rm -f "$tmp_cron" + echo "All backup schedules removed." + log_action "All backup schedules removed." ;; *) echo "Invalid action: $1. Use add, update, or remove."