#!/bin/bash # Desk-Moloni v3.0 Cron Job Setup Script # # Sets up automated cron jobs for queue processing and maintenance tasks. # Handles different environments and user permissions. set -euo pipefail # Script configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MODULE_DIR="$(dirname "$SCRIPT_DIR")" CLI_DIR="$MODULE_DIR/cli" LOG_DIR="$MODULE_DIR/logs" LOCK_DIR="$MODULE_DIR/locks" # Default configuration DEFAULT_QUEUE_INTERVAL="*/1" # Every minute DEFAULT_MAINTENANCE_HOUR="2" # 2 AM DEFAULT_LOG_RETENTION_DAYS="30" DEFAULT_USER="" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # Help function show_help() { cat << EOF Desk-Moloni v3.0 Cron Setup Script Usage: $0 [OPTIONS] Options: -h, --help Show this help message -u, --user USER User to run cron jobs as (default: current user) -i, --interval INTERVAL Queue processor interval (default: */1 for every minute) -m, --maintenance HOUR Maintenance hour (default: 2 for 2 AM) -r, --retention DAYS Log retention days (default: 30) -d, --dry-run Show what would be done without making changes -v, --verbose Verbose output --uninstall Remove all cron jobs --status Show current cron job status Examples: $0 # Setup with defaults $0 -u www-data -i "*/5" # Run as www-data every 5 minutes $0 --dry-run # Preview changes $0 --uninstall # Remove all cron jobs $0 --status # Show current status Cron Jobs Created: 1. Queue Processor: Processes synchronization queue 2. Daily Maintenance: Cleanup logs, update mappings 3. Health Check: Monitor system health 4. Token Refresh: Refresh OAuth tokens EOF } # Parse command line arguments QUEUE_INTERVAL="$DEFAULT_QUEUE_INTERVAL" MAINTENANCE_HOUR="$DEFAULT_MAINTENANCE_HOUR" LOG_RETENTION_DAYS="$DEFAULT_LOG_RETENTION_DAYS" CRON_USER="$DEFAULT_USER" DRY_RUN=false VERBOSE=false UNINSTALL=false SHOW_STATUS=false while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_help exit 0 ;; -u|--user) CRON_USER="$2" shift 2 ;; -i|--interval) QUEUE_INTERVAL="$2" shift 2 ;; -m|--maintenance) MAINTENANCE_HOUR="$2" shift 2 ;; -r|--retention) LOG_RETENTION_DAYS="$2" shift 2 ;; -d|--dry-run) DRY_RUN=true shift ;; -v|--verbose) VERBOSE=true shift ;; --uninstall) UNINSTALL=true shift ;; --status) SHOW_STATUS=true shift ;; *) log_error "Unknown option: $1" show_help exit 1 ;; esac done # Set default user to current user if not specified if [[ -z "$CRON_USER" ]]; then CRON_USER=$(whoami) fi # Validate user exists if ! id "$CRON_USER" &>/dev/null; then log_error "User '$CRON_USER' does not exist" exit 1 fi # Check if running as root or target user CURRENT_USER=$(whoami) if [[ "$CURRENT_USER" != "root" && "$CURRENT_USER" != "$CRON_USER" ]]; then log_error "Must run as root or target user ($CRON_USER)" exit 1 fi # Validate maintenance hour if [[ ! "$MAINTENANCE_HOUR" =~ ^[0-9]+$ ]] || [[ "$MAINTENANCE_HOUR" -lt 0 ]] || [[ "$MAINTENANCE_HOUR" -gt 23 ]]; then log_error "Invalid maintenance hour: $MAINTENANCE_HOUR (must be 0-23)" exit 1 fi # Create required directories create_directories() { local dirs=("$LOG_DIR" "$LOCK_DIR") for dir in "${dirs[@]}"; do if [[ ! -d "$dir" ]]; then if [[ "$DRY_RUN" == true ]]; then log_info "Would create directory: $dir" else mkdir -p "$dir" chown "$CRON_USER:$CRON_USER" "$dir" 2>/dev/null || true log_success "Created directory: $dir" fi fi done } # Generate cron job entries generate_cron_jobs() { cat << EOF # Desk-Moloni v3.0 Cron Jobs # Generated on $(date) # User: $CRON_USER # Queue Processor - Process synchronization queue $QUEUE_INTERVAL * * * * /usr/bin/flock -n $LOCK_DIR/queue_processor.lock php $CLI_DIR/queue_processor.php >> $LOG_DIR/queue_processor.log 2>&1 # Daily Maintenance - Cleanup and optimization 0 $MAINTENANCE_HOUR * * * /usr/bin/flock -n $LOCK_DIR/maintenance.lock $SCRIPT_DIR/maintenance.sh >> $LOG_DIR/maintenance.log 2>&1 # Health Check - System monitoring */15 * * * * /usr/bin/flock -n $LOCK_DIR/health_check.lock php $CLI_DIR/sync_commands.php health >> $LOG_DIR/health_check.log 2>&1 # Token Refresh - OAuth token maintenance 0 */6 * * * /usr/bin/flock -n $LOCK_DIR/token_refresh.lock $SCRIPT_DIR/token_refresh.sh >> $LOG_DIR/token_refresh.log 2>&1 # Log Rotation - Cleanup old logs 0 1 * * 0 /usr/bin/find $LOG_DIR -name "*.log" -mtime +$LOG_RETENTION_DAYS -delete EOF } # Get current cron jobs for the user get_current_crontab() { if [[ "$CURRENT_USER" == "root" ]]; then crontab -u "$CRON_USER" -l 2>/dev/null || true else crontab -l 2>/dev/null || true fi } # Remove existing Desk-Moloni cron jobs remove_existing_jobs() { local current_crontab current_crontab=$(get_current_crontab) if [[ -n "$current_crontab" ]]; then # Remove lines between Desk-Moloni markers local new_crontab new_crontab=$(echo "$current_crontab" | sed '/# Desk-Moloni v3.0 Cron Jobs/,/^$/d') if [[ "$DRY_RUN" == true ]]; then log_info "Would remove existing Desk-Moloni cron jobs" else if [[ "$CURRENT_USER" == "root" ]]; then echo "$new_crontab" | crontab -u "$CRON_USER" - else echo "$new_crontab" | crontab - fi log_success "Removed existing Desk-Moloni cron jobs" fi return 0 fi return 1 } # Install cron jobs install_cron_jobs() { local current_crontab new_crontab cron_jobs current_crontab=$(get_current_crontab) cron_jobs=$(generate_cron_jobs) # Combine existing crontab with new jobs if [[ -n "$current_crontab" ]]; then new_crontab="$current_crontab"$'\n'"$cron_jobs" else new_crontab="$cron_jobs" fi if [[ "$DRY_RUN" == true ]]; then log_info "Would install the following cron jobs:" echo "$cron_jobs" else if [[ "$CURRENT_USER" == "root" ]]; then echo "$new_crontab" | crontab -u "$CRON_USER" - else echo "$new_crontab" | crontab - fi log_success "Installed Desk-Moloni cron jobs for user: $CRON_USER" fi } # Show current status show_status() { log_info "Desk-Moloni Cron Job Status" echo "================================" local current_crontab current_crontab=$(get_current_crontab) if [[ -n "$current_crontab" ]]; then local desk_moloni_jobs desk_moloni_jobs=$(echo "$current_crontab" | sed -n '/# Desk-Moloni v3.0 Cron Jobs/,/^$/p') if [[ -n "$desk_moloni_jobs" ]]; then log_success "Desk-Moloni cron jobs are installed for user: $CRON_USER" echo "$desk_moloni_jobs" else log_warning "No Desk-Moloni cron jobs found for user: $CRON_USER" fi else log_warning "No crontab found for user: $CRON_USER" fi # Check if cron daemon is running if systemctl is-active --quiet cron 2>/dev/null || systemctl is-active --quiet crond 2>/dev/null; then log_success "Cron daemon is running" else log_warning "Cron daemon may not be running" fi # Check log files echo -e "\nLog Files Status:" for log_file in "queue_processor.log" "maintenance.log" "health_check.log" "token_refresh.log"; do local log_path="$LOG_DIR/$log_file" if [[ -f "$log_path" ]]; then local size=$(du -h "$log_path" | cut -f1) local modified=$(stat -c %y "$log_path" 2>/dev/null | cut -d' ' -f1,2 | cut -d'.' -f1) log_info "$log_file: $size (modified: $modified)" else log_warning "$log_file: Not found" fi done # Check lock files echo -e "\nActive Processes:" for lock_file in "$LOCK_DIR"/*.lock; do if [[ -f "$lock_file" ]]; then local lock_name=$(basename "$lock_file" .lock) log_warning "$lock_name: Process may be running (lock file exists)" fi done } # Validate PHP and dependencies validate_dependencies() { log_info "Validating dependencies..." # Check PHP if ! command -v php &> /dev/null; then log_error "PHP is not installed or not in PATH" exit 1 fi local php_version php_version=$(php -r "echo PHP_VERSION;" 2>/dev/null) log_success "PHP version: $php_version" # Check flock if ! command -v flock &> /dev/null; then log_error "flock is not installed (required for preventing concurrent execution)" exit 1 fi # Check CLI files exist local cli_files=("$CLI_DIR/queue_processor.php" "$CLI_DIR/sync_commands.php") for cli_file in "${cli_files[@]}"; do if [[ ! -f "$cli_file" ]]; then log_error "CLI file not found: $cli_file" exit 1 fi done log_success "All dependencies validated" } # Test cron job syntax test_cron_syntax() { log_info "Testing cron job syntax..." local cron_jobs cron_jobs=$(generate_cron_jobs) # Basic validation of cron expressions while IFS= read -r line; do if [[ "$line" =~ ^[^#].* ]]; then local cron_expr cron_expr=$(echo "$line" | cut -d' ' -f1-5) # Very basic validation - just check field count local field_count field_count=$(echo "$cron_expr" | wc -w) if [[ "$field_count" -ne 5 ]]; then log_error "Invalid cron expression: $cron_expr" exit 1 fi fi done <<< "$cron_jobs" log_success "Cron job syntax validated" } # Main execution main() { log_info "Desk-Moloni v3.0 Cron Setup" log_info "User: $CRON_USER" log_info "Queue Interval: $QUEUE_INTERVAL" log_info "Maintenance Hour: $MAINTENANCE_HOUR" if [[ "$DRY_RUN" == true ]]; then log_warning "DRY RUN MODE - No changes will be made" fi if [[ "$SHOW_STATUS" == true ]]; then show_status exit 0 fi if [[ "$UNINSTALL" == true ]]; then log_info "Uninstalling Desk-Moloni cron jobs..." if remove_existing_jobs; then log_success "Cron jobs removed successfully" else log_warning "No existing cron jobs found" fi exit 0 fi # Installation process validate_dependencies test_cron_syntax create_directories # Remove existing jobs first remove_existing_jobs || true # Install new jobs install_cron_jobs if [[ "$DRY_RUN" == false ]]; then log_info "" log_success "Cron jobs have been installed successfully!" log_info "Monitor logs in: $LOG_DIR" log_info "Check status with: $0 --status" log_info "" log_info "Next steps:" log_info "1. Verify cron daemon is running: systemctl status cron" log_info "2. Monitor queue processor: tail -f $LOG_DIR/queue_processor.log" log_info "3. Check health status: php $CLI_DIR/sync_commands.php health" fi } # Run main function main "$@"