Comprehensive Script Analysis for Cloudpanel : Process Monitoring and Management System

Comprehensive Script Analysis: Process Monitoring and Management System

#!/bin/bash
# ------------------------------------------------------------
# Optimized script to check processes
# ------------------------------------------------------------
# RETURN CODES:
#    0: No processes running
#    1: One process running (CPU time < threshold)
#    2: One process running (CPU time >= threshold) 
#    3: Multiple processes running
# ------------------------------------------------------------

# Default configuration
PS_NAME="<process_name>"
CPU_MAX="000100"  # HHMMSS format
CONFIG_FILE="/etc/processcheck.conf"
VERBOSE=0
LOG_FILE="/var/log/processcheck.log"

# Process command line arguments
while getopts "vc:l:" opt; do
    case $opt in
        v) VERBOSE=1 ;;
        c) CONFIG_FILE="$OPTARG" ;;
        l) LOG_FILE="$OPTARG" ;;
        ?) echo "Usage: $0 [-v] [-c config_file] [-l log_file]" >&2; exit 1 ;;
    esac
done

# Load configuration file if it exists
if [ -f "$CONFIG_FILE" ]; then
    debug "Loading configuration from $CONFIG_FILE"
    source "$CONFIG_FILE"
fi

# Make constants readonly after config load
readonly PS_NAME CPU_MAX GREP_OPTS

# Signal handling
trap cleanup INT TERM EXIT

# Logging function
log() {
    local message="[$(date +'%Y-%m-%d %H:%M:%S')] $*"
    echo "$message" | tee -a "$LOG_FILE" >&2
}

# Debug logging function
debug() {
    if [ "$VERBOSE" -eq 1 ]; then
        log "[DEBUG] $*"
    fi
}

# Cleanup function
cleanup() {
    local exit_code=$?
    debug "Cleaning up and exiting with code $exit_code"
    # Add any cleanup tasks here
    exit "$exit_code"
}

# More efficient process counting using pgrep
get_process_count() {
    local count
    count=$(pgrep -c -f "$PS_NAME" 2>/dev/null || echo 0)
    debug "Process count: $count"
    echo "$count"
}

# Get CPU time of single process more efficiently
get_cpu_time() {
    local cpu_time
    cpu_time=$(ps -o time= -p "$(pgrep -f "$PS_NAME")" 2>/dev/null | \
        awk '{ split($1,a,":"); print a[1]*3600 + a[2]*60 + a[3] }')
    debug "CPU time: $cpu_time seconds"
    echo "$cpu_time"
}

# Convert HHMMSS to seconds for comparison
convert_hhmmss_to_seconds() {
    local time=$1
    local seconds
    seconds=$((
        10#${time:0:2} * 3600 +  # Hours
        10#${time:2:2} * 60 +    # Minutes
        10#${time:4:2}           # Seconds
    ))
    debug "Converted $time to $seconds seconds"
    echo "$seconds"
}

# Check if log directory exists and is writable
check_log_directory() {
    local log_dir
    log_dir=$(dirname "$LOG_FILE")
    if [ ! -d "$log_dir" ]; then
        mkdir -p "$log_dir" || {
            echo "Error: Cannot create log directory $log_dir" >&2
            exit 1
        }
    fi
    if [ ! -w "$log_dir" ]; then
        echo "Error: Log directory $log_dir is not writable" >&2
        exit 1
    }
}

main() {
    debug "Starting process check for $PS_NAME"
    check_log_directory

    local count
    count=$(get_process_count)

    case $count in
        0)
            log "[RET-CODE:0] processes are not running."
            exit 0
            ;;
        1)
            local cpu_time max_seconds
            cpu_time=$(get_cpu_time)
            max_seconds=$(convert_hhmmss_to_seconds "$CPU_MAX")

            debug "Comparing CPU time $cpu_time with max allowed $max_seconds"

            if [ "$cpu_time" -lt "$max_seconds" ]; then
                log "[RET-CODE:1] one process is running. (CPU time < configured value)"
                exit 1
            else
                log "[RET-CODE:2] one process is running. (CPU time >= configured value)"
                exit 2
            fi
            ;;
        *)
            log "[RET-CODE:3] more than two processes are running."
            exit 3
            ;;
    esac
}

# Example configuration file format (/etc/processcheck.conf):
# PS_NAME="myprocess"
# CPU_MAX="001500"  # 15 minutes
# LOG_FILE="/var/log/custom/processcheck.log"

# Run main function
main "$@"

Let me break down each major component and explain its purpose and functionality:

1. Script Header and Configuration Management

# Default configuration
PS_NAME="<process_name>"
CPU_MAX="000100"  # HHMMSS format
CONFIG_FILE="/etc/processcheck.conf"
VERBOSE=0
LOG_FILE="/var/log/processcheck.log"
  • Sets default values for essential parameters
  • Allows for easy configuration changes
  • Defines paths for config and log files

2. Command Line Argument Processing

while getopts "vc:l:" opt; do
    case $opt in
        v) VERBOSE=1 ;;
        c) CONFIG_FILE="$OPTARG" ;;
        l) LOG_FILE="$OPTARG" ;;
        ?) echo "Usage: $0 [-v] [-c config_file] [-l log_file]" >&2; exit 1 ;;
    esac
done
  • Processes command-line flags:
    • -v: Enables verbose mode
    • -c: Specifies custom config file
    • -l: Specifies custom log file
  • Provides usage information on invalid input

3. Configuration File Handling

if [ -f "$CONFIG_FILE" ]; then
    debug "Loading configuration from $CONFIG_FILE"
    source "$CONFIG_FILE"
fi
  • Checks for existence of config file
  • Loads custom configurations if available
  • Uses default values if no config file exists

4. Signal Management

trap cleanup INT TERM EXIT

cleanup() {
    local exit_code=$?
    debug "Cleaning up and exiting with code $exit_code"
    exit "$exit_code"
}
  • Handles script interruption gracefully
  • Captures system signals (SIGINT, SIGTERM)
  • Performs cleanup before exit
  • Preserves original exit codes

5. Logging System

log() {
    local message="[$(date +'%Y-%m-%d %H:%M:%S')] $*"
    echo "$message" | tee -a "$LOG_FILE" >&2
}

debug() {
    if [ "$VERBOSE" -eq 1 ]; then
        log "[DEBUG] $*"
    fi
}
  • Two-tier logging system:
    • Standard logging for important events
    • Debug logging for detailed information
  • Timestamps all log entries
  • Writes to both console and log file
  • Conditional debug output based on verbose mode

6. Process Management Functions

get_process_count() {
    local count
    count=$(pgrep -c -f "$PS_NAME" 2>/dev/null || echo 0)
    debug "Process count: $count"
    echo "$count"
}

get_cpu_time() {
    local cpu_time
    cpu_time=$(ps -o time= -p "$(pgrep -f "$PS_NAME")" 2>/dev/null | \
        awk '{ split($1,a,":"); print a[1]*3600 + a[2]*60 + a[3] }')
    debug "CPU time: $cpu_time seconds"
    echo "$cpu_time"
}
  • Efficient process counting using pgrep
  • Accurate CPU time calculation
  • Error handling for process operations
  • Debug logging of process information

7. Time Conversion Utility

convert_hhmmss_to_seconds() {
    local time=$1
    local seconds
    seconds=$((
        10#${time:0:2} * 3600 +  # Hours
        10#${time:2:2} * 60 +    # Minutes
        10#${time:4:2}           # Seconds
    ))
    debug "Converted $time to $seconds seconds"
    echo "$seconds"
}
  • Converts HHMMSS format to seconds
  • Handles base-10 conversion properly
  • Supports time comparison operations
  • Logs conversion for debugging

8. Log Directory Management

check_log_directory() {
    local log_dir
    log_dir=$(dirname "$LOG_FILE")
    if [ ! -d "$log_dir" ]; then
        mkdir -p "$log_dir" || {
            echo "Error: Cannot create log directory $log_dir" >&2
            exit 1
        }
    fi
    if [ ! -w "$log_dir" ]; then
        echo "Error: Log directory $log_dir is not writable" >&2
        exit 1
    }
}
  • Ensures log directory exists
  • Creates directory if missing
  • Checks write permissions
  • Fails gracefully with error messages

9. Main Process Logic

main() {
    debug "Starting process check for $PS_NAME"
    check_log_directory

    local count
    count=$(get_process_count)

    case $count in
        0) # No processes
        1) # Single process with CPU time check
        *) # Multiple processes
    esac
}
  • Orchestrates overall script execution
  • Implements core business logic
  • Handles different process scenarios
  • Provides appropriate exit codes

Usage Examples

# Basic usage
./script.sh

# Verbose mode with custom config
./script.sh -v -c /path/to/config.conf

# Custom log file
./script.sh -l /path/to/custom.log

# All options
./script.sh -v -c /path/to/config.conf -l /path/to/custom.log

Benefits of This Implementation

  1. Reliability:

    • Robust error handling
    • Graceful exit management
    • Permission checking
    • Signal handling
  2. Maintainability:

    • Modular design
    • Well-documented functions
    • Consistent coding style
    • Clear variable naming
  3. Flexibility:

    • Configurable through files
    • Command-line options
    • Customizable logging
    • Adaptable to different environments
  4. Debugging:

    • Comprehensive logging
    • Verbose mode option
    • Clear error messages
    • Debug information available