From 9a837ee1f7b06ad00655d570d2fe54419303a43e Mon Sep 17 00:00:00 2001 From: Yehonal Date: Sat, 5 Jul 2025 23:02:04 +0200 Subject: fix(bash): Improve session management and GDB handling in service scripts (#22418) This pull request introduces several enhancements and fixes to the startup scripts for AzerothCore, focusing on improving service management, interactive mode handling, and script execution. The most important changes include adding support for non-interactive mode, enhancing systemd integration, and refactoring the starter script to handle binary paths and files more robustly. ### Enhancements to Service Management: * **Non-Interactive Mode:** Added `AC_DISABLE_INTERACTIVE` environment variable to disable interactive prompts for services running without session managers (e.g., systemd/pm2). This prevents hanging during non-interactive execution. (`apps/startup-scripts/src/run-engine`, `apps/startup-scripts/src/service-manager.sh`) [[1]](diffhunk://#diff-1792abab64da981c71221890876ce832aab405f670f320f75b73b8788b1a4174R336-R349) [[2]](diffhunk://#diff-31edfed7f73d0647a5fc96ce74c249e025e884cd1fe06621cb78eb4a381464f9R724-R727) * **Enhanced Systemd Integration:** Services using session managers like tmux/screen are automatically configured with `Type=forking` and appropriate `ExecStop` commands to terminate sessions gracefully. (`apps/startup-scripts/src/service-manager.sh`) [[1]](diffhunk://#diff-31edfed7f73d0647a5fc96ce74c249e025e884cd1fe06621cb78eb4a381464f9R401-R425) [[2]](diffhunk://#diff-31edfed7f73d0647a5fc96ce74c249e025e884cd1fe06621cb78eb4a381464f9R567-R578) ### Improvements to Script Execution: * **Starter Script Refactor:** Updated the starter script to require both binary path and file name as parameters, improving clarity and error handling. (`apps/startup-scripts/src/starter`) [[1]](diffhunk://#diff-e92f132163ec1e49dc625eac9107c6841ae14e416aa35adec787dca5031dc631L6-R16) [[2]](diffhunk://#diff-e92f132163ec1e49dc625eac9107c6841ae14e416aa35adec787dca5031dc631L26-R44) * **Temporary GDB File Management:** Enhanced handling of temporary GDB configuration files, ensuring proper cleanup after execution. (`apps/startup-scripts/src/starter`) [[1]](diffhunk://#diff-e92f132163ec1e49dc625eac9107c6841ae14e416aa35adec787dca5031dc631R68-R70) [[2]](diffhunk://#diff-e92f132163ec1e49dc625eac9107c6841ae14e416aa35adec787dca5031dc631R92-R141) ### Updates to Tests: * **Test Adjustments:** Modified test cases to reflect the updated starter script parameter requirements and error messages. (`apps/startup-scripts/test/test_startup_scripts.bats`) [[1]](diffhunk://#diff-febbaeb294e50bdba0511ecad5d44b0c3f11ae92c79dd19dbd5f61d41a654278L26-R26) [[2]](diffhunk://#diff-febbaeb294e50bdba0511ecad5d44b0c3f11ae92c79dd19dbd5f61d41a654278L41-R49) --- apps/startup-scripts/README.md | 31 ++++ apps/startup-scripts/src/gdb.conf | 7 - apps/startup-scripts/src/run-engine | 16 +- apps/startup-scripts/src/service-manager.sh | 188 +++++++++++++++++---- apps/startup-scripts/src/starter | 87 ++++++---- .../startup-scripts/test/test_startup_scripts.bats | 15 +- 6 files changed, 265 insertions(+), 79 deletions(-) delete mode 100644 apps/startup-scripts/src/gdb.conf (limited to 'apps') diff --git a/apps/startup-scripts/README.md b/apps/startup-scripts/README.md index 9a408dd6c0..1463395d44 100644 --- a/apps/startup-scripts/README.md +++ b/apps/startup-scripts/README.md @@ -135,6 +135,9 @@ export CONFIG="/path/to/worldserver.conf" export SESSION_MANAGER="tmux" # none|auto|tmux|screen export SESSION_NAME="ac-world" +# Interactive mode control +export AC_DISABLE_INTERACTIVE="0" # Set to 1 to disable interactive prompts (useful for non-interactive services) + # Debugging export GDB_ENABLED="1" # 0 or 1 export GDB="/path/to/gdb.conf" @@ -372,6 +375,29 @@ pm2 save pm2 startup # Auto-start on boot ``` +NOTE: pm2 cannot run tmux/screen sessions, but you can always use the `attach` command to connect to the service console because pm2 supports interactive mode. + +### Environment Variables + +The startup scripts recognize several environment variables for configuration and runtime behavior: + +#### Service Detection Variables + +- **`AC_LAUNCHED_BY_PM2`**: Set to `1` when launched by PM2 (automatically set by service-manager) + - Disables the use of the `script` command for output capture + - Enables non-interactive mode to prevent prompts + - More robust than relying on PM2's internal variables + +- **`AC_DISABLE_INTERACTIVE`**: Controls interactive mode (0=enabled, 1=disabled) + - Automatically set based on execution context + - Prevents AzerothCore from showing interactive prompts in service environments + +#### Configuration Variables + +- **`RUN_ENGINE_*`**: See [Configuration](#configuration) section for complete list +- **`SERVICE_MODE`**: Set to `true` to enable service-specific behavior +- **`SESSION_MANAGER`**: Override session manager choice (tmux, screen, none, auto) + ### Systemd Services When using systemd as the service provider: @@ -388,6 +414,11 @@ sudo systemctl status acore-auth sudo systemctl enable acore-auth ``` +**Enhanced systemd Integration:** +- **Automatic Service Type**: When using session managers (tmux/screen), services are automatically configured with `Type=forking` for proper daemon behavior +- **Smart ExecStop**: Services with session managers get automatic `ExecStop` commands to properly terminate tmux/screen sessions when stopping the service +- **Non-Interactive Mode**: Services without session managers automatically set `AC_DISABLE_INTERACTIVE=1` to prevent hanging on prompts + ### Session Management in Services Services can be configured with session managers for interactive access: diff --git a/apps/startup-scripts/src/gdb.conf b/apps/startup-scripts/src/gdb.conf deleted file mode 100644 index d6802a56b6..0000000000 --- a/apps/startup-scripts/src/gdb.conf +++ /dev/null @@ -1,7 +0,0 @@ -set logging enabled on -set debug timestamp -run -bt -bt full -info thread -thread apply all backtrace full diff --git a/apps/startup-scripts/src/run-engine b/apps/startup-scripts/src/run-engine index 2860339a5e..57ed33e3f1 100755 --- a/apps/startup-scripts/src/run-engine +++ b/apps/startup-scripts/src/run-engine @@ -254,7 +254,7 @@ function start_service() { # Use environment/config values if not set from command line BINPATH="${BINPATH:-$RUN_ENGINE_BINPATH}" SERVERBIN="${SERVERBIN:-$RUN_ENGINE_SERVERBIN}" - CONFIG="${serverconfig:-$RUN_ENGINE_CONFIG}" + CONFIG="${serverconfig:-$CONFIG}" echo "SERVERBIN: $SERVERBIN" @@ -333,6 +333,20 @@ function start_service() { echo "Server config: default (not specified)" fi + # Set AC_DISABLE_INTERACTIVE when running as a service without interactive session manager + # This prevents AzerothCore from showing interactive prompts when running under systemd/pm2 + if [[ "${SERVICE_MODE:-false}" == "true" && "$session_manager" == "none" ]]; then + export AC_DISABLE_INTERACTIVE=1 + echo "Service mode: Non-interactive mode enabled (AC_DISABLE_INTERACTIVE=1)" + else + export AC_DISABLE_INTERACTIVE=0 + if [[ "${SERVICE_MODE:-false}" == "true" ]]; then + echo "Service mode: Interactive mode enabled (session manager: $session_manager)" + else + echo "Direct execution: Interactive mode enabled" + fi + fi + if [ "$use_restarter" = "true" ]; then # Use simple-restarter for restart functionality local gdb_enabled="${GDB_ENABLED:-0}" diff --git a/apps/startup-scripts/src/service-manager.sh b/apps/startup-scripts/src/service-manager.sh index 1c44c9c247..470582bd1e 100755 --- a/apps/startup-scripts/src/service-manager.sh +++ b/apps/startup-scripts/src/service-manager.sh @@ -100,6 +100,7 @@ function print_help() { echo " --bin-path - Path to the server binary directory (required)" echo " --server-config - Path to the server configuration file" echo " --session-manager - Session manager (none|tmux|screen, default: none)" + echo " Note: PM2 doesn't support tmux/screen, always uses 'none'" echo " --gdb-enabled <0|1> - Enable GDB debugging (default: 0)" echo " --system - Create as system service (systemd only, requires sudo)" echo " --user - Create as user service (systemd only, default)" @@ -137,6 +138,7 @@ function print_help() { echo " - Use --server-config for the actual server configuration file" echo " - Services use run-engine in 'start' mode for single-shot execution" echo " - Restart on crash is handled by PM2 or systemd, not by run-engine" + echo " - PM2 services always use session-manager 'none' and have built-in attach functionality" echo " - attach command automatically detects the configured session manager and connects appropriately" echo " - attach always provides interactive access to the server console" echo " - Use 'logs' command to view service logs without interaction" @@ -166,9 +168,11 @@ function validate_service_exists() { local provider="$2" if [ "$provider" = "pm2" ]; then - # Check if service exists in PM2 - if ! pm2 id "$service_name" > /dev/null 2>&1; then - return 1 # Service not found + # Check if service exists in PM2 using pm2 describe (most reliable) + if pm2 describe "$service_name" >/dev/null 2>&1; then + return 0 # Service exists + else + return 1 # Service doesn't exist fi elif [ "$provider" = "systemd" ]; then # Check if service exists in systemd @@ -275,8 +279,8 @@ function pm2_create_service() { esac done - # Build PM2 start command - local pm2_cmd="pm2 start '$command$additional_args' --name '$service_name'" + # Build PM2 start command with AzerothCore environment variable + local pm2_cmd="AC_LAUNCHED_BY_PM2=1 pm2 start '$command$additional_args' --name '$service_name'" # Add memory limit if specified if [ -n "$max_memory" ]; then @@ -301,6 +305,7 @@ function pm2_create_service() { fi } + function pm2_remove_service() { local service_name="$1" @@ -309,12 +314,24 @@ function pm2_remove_service() { echo -e "${YELLOW}Stopping and removing PM2 service: $service_name${NC}" # Stop the service if it's running - if pm2 id "$service_name" > /dev/null 2>&1; then + if pm2 describe "$service_name" >/dev/null 2>&1; then pm2 stop "$service_name" 2>/dev/null || true - pm2 delete "$service_name" 2>/dev/null + pm2 delete "$service_name" 2>/dev/null + # Wait for PM2 to process the stop/delete command with timeout + local timeout=10 + local elapsed=0 + while pm2 describe "$service_name" >/dev/null 2>&1; do + if [ "$elapsed" -ge "$timeout" ]; then + echo -e "${RED}Timeout reached while waiting for PM2 service '$service_name' to stop${NC}" + return 1 + fi + sleep 0.5 + elapsed=$((elapsed + 1)) + done + # Verify the service was removed - if pm2 id "$service_name" > /dev/null 2>&1; then + if pm2 describe "$service_name" >/dev/null 2>&1; then echo -e "${RED}Failed to remove PM2 service '$service_name'${NC}" return 1 fi @@ -398,6 +415,31 @@ function systemd_create_service() { mkdir -p "$systemd_dir" fi + # Determine service type and ExecStop for systemd + local service_type="simple" + local exec_stop="" + + # Load the run-engine config to check the session manager + local run_engine_config_path="$CONFIG_DIR/$service_name-run-engine.conf" + local session_manager="none" + local session_name="$service_name" + + if [ -f "$run_engine_config_path" ]; then + # Read the session manager and name from the config file without sourcing it + session_manager=$(grep -oP 'SESSION_MANAGER="\K[^"]+' "$run_engine_config_path" || echo "none") + session_name=$(grep -oP 'SESSION_NAME="\K[^"]+' "$run_engine_config_path" || echo "$service_name") + fi + + if [ "$session_manager" = "tmux" ]; then + service_type="forking" + # Provide a direct and absolute path for the ExecStop command + exec_stop="ExecStop=/usr/bin/tmux kill-session -t $session_name" + elif [ "$session_manager" = "screen" ]; then + service_type="forking" + # Provide a direct and absolute path for the ExecStop command + exec_stop="ExecStop=/usr/bin/screen -S $session_name -X quit" + fi + # Create service file echo -e "${YELLOW}Creating systemd service: $service_name${NC}" @@ -409,8 +451,9 @@ Description=AzerothCore $service_name After=network.target [Service] -Type=forking +Type=${service_type} ExecStart=$command +${exec_stop} Restart=always RestartSec=3 User=$(whoami) @@ -430,8 +473,9 @@ Description=AzerothCore $service_name After=network.target [Service] -Type=forking +Type=${service_type} ExecStart=$command +${exec_stop} Restart=always RestartSec=3 WorkingDirectory=$(realpath "$bin_path") @@ -536,7 +580,19 @@ function systemd_service_action() { fi echo -e "${YELLOW}${action^} systemd service: $service_name${NC}" - + + # stop tmux or screen session if applicable && action is stop or restart + if [[ "$action" == "stop" || "$action" == "restart" ]]; then + local session_manager=$(grep -oP 'SESSION_MANAGER="\K[^"]+' "$CONFIG_DIR/$service_name-run-engine.conf" || echo "none") + if [ "$session_manager" = "tmux" ]; then + echo -e "${YELLOW}Stopping tmux session for service: $service_name${NC}" + tmux kill-session -t "$service_name" + elif [ "$session_manager" = "screen" ]; then + echo -e "${YELLOW}Stopping screen session for service: $service_name${NC}" + screen -S "$service_name" -X quit + fi + fi + if [ "$systemd_type" = "--system" ]; then systemctl "$action" "$service_name.service" else @@ -659,9 +715,20 @@ function create_service() { return 1 fi + # PM2 specific validation and adjustments + if [ "$provider" = "pm2" ]; then + # PM2 doesn't support session managers (tmux/screen), force to none + if [ "$session_manager" != "none" ]; then + echo -e "${YELLOW}Warning: PM2 doesn't support session managers. Setting session-manager to 'none'${NC}" + echo -e "${BLUE}PM2 has built-in attach functionality via: $0 attach $service_name${NC}" + session_manager="none" + fi + fi + # Determine server binary based on service type local server_bin="${service_type}server" local server_binary_path=$(realpath "$bin_path/$server_bin") + local real_config_path=$(realpath "$server_config") # Check if binary exists if [ ! -f "$server_binary_path" ]; then @@ -681,6 +748,10 @@ export GDB_ENABLED=$gdb_enabled # Session manager (none|auto|tmux|screen) export SESSION_MANAGER="$session_manager" +# Service mode - indicates this is running under a service manager (systemd/pm2) +# When true, AC_DISABLE_INTERACTIVE will be set if no interactive session manager is used +export SERVICE_MODE="true" + # Session name for tmux/screen (optional) export SESSION_NAME="${service_name}" @@ -691,7 +762,7 @@ export BINPATH="$bin_path" export SERVERBIN="$server_bin" # Server configuration file path -export CONFIG="$server_config" +export CONFIG="$real_config_path" # Show console output for easier debugging export WITH_CONSOLE=1 @@ -830,6 +901,14 @@ function update_service() { esac done + # PM2 specific validation for session manager + if [ "$provider" = "pm2" ] && [ -n "$SESSION_MANAGER" ] && [ "$SESSION_MANAGER" != "none" ]; then + echo -e "${YELLOW}Warning: PM2 doesn't support session managers. Setting session-manager to 'none'${NC}" + echo -e "${BLUE}PM2 has built-in attach functionality via: $0 attach $service_name${NC}" + export SESSION_MANAGER="none" + config_updated=true + fi + if [ "$config_updated" = "true" ]; then # Update run-engine configuration file cat > "$RUN_ENGINE_CONFIG_FILE" << EOF @@ -842,6 +921,9 @@ export GDB_ENABLED=${GDB_ENABLED:-0} # Session manager (none|auto|tmux|screen) export SESSION_MANAGER="${SESSION_MANAGER:-none}" +# Service mode - indicates this is running under a service manager (systemd/pm2) +export SERVICE_MODE="true" + # Session name for tmux/screen export SESSION_NAME="${service_name}" @@ -940,15 +1022,6 @@ function list_services() { return fi - # Show PM2 services - if [ -z "$provider_filter" ] || [ "$provider_filter" = "pm2" ]; then - local pm2_services=$(jq -r '.[] | select(.provider == "pm2") | .name' "$REGISTRY_FILE" 2>/dev/null) - if [ -n "$pm2_services" ] && command -v pm2 >/dev/null 2>&1; then - echo -e "\n${YELLOW}PM2 Services:${NC}" - pm2 list - fi - fi - # Show systemd services if [ -z "$provider_filter" ] || [ "$provider_filter" = "systemd" ]; then local systemd_services=$(jq -r '.[] | select(.provider == "systemd") | .name' "$REGISTRY_FILE" 2>/dev/null) @@ -978,6 +1051,15 @@ function list_services() { fi fi fi + + # Show PM2 services + if [ -z "$provider_filter" ] || [ "$provider_filter" = "pm2" ]; then + local pm2_services=$(jq -r '.[] | select(.provider == "pm2") | .name' "$REGISTRY_FILE" 2>/dev/null) + if [ -n "$pm2_services" ] && command -v pm2 >/dev/null 2>&1; then + echo -e "\n${YELLOW}PM2 Services:${NC}" + pm2 list + fi + fi } function service_action() { @@ -1079,33 +1161,67 @@ function attach_to_service() { source "$RUN_ENGINE_CONFIG_FILE" # Auto-detect session manager and attach accordingly - case "$SESSION_MANAGER" in - "tmux") - attach_tmux_session "$service_name" "$provider" - ;; - "screen") - attach_screen_session "$service_name" "$provider" - ;; - "none"|"auto"|*) - # No session manager - launch interactive shell directly - attach_interactive_shell "$service_name" "$provider" - ;; - esac + if [ "$provider" = "pm2" ]; then + # PM2 has built-in attach functionality + attach_pm2_process "$service_name" + else + # For systemd, check session manager + case "$SESSION_MANAGER" in + "tmux") + attach_tmux_session "$service_name" "$provider" + ;; + "screen") + attach_screen_session "$service_name" "$provider" + ;; + "none"|"auto"|*) + # No session manager - show helpful message for systemd + attach_interactive_shell "$service_name" "$provider" + ;; + esac + fi +} + +function attach_pm2_process() { + local service_name="$1" + + + # First check if the service exists and get its ID + local pm2_id=$(pm2 id "$service_name" 2>/dev/null) + if [ -z "$pm2_id" ] || [ "$pm2_id" = "[]" ]; then + echo -e "${RED}Error: PM2 process '$service_name' not found${NC}" + return 1 + fi + + # Extract the numeric ID from the JSON response + local numeric_id=$(echo "$pm2_id" | jq -r '.[0] // empty') + if [ -z "$numeric_id" ]; then + echo -e "${RED}Error: Could not determine PM2 process ID for '$service_name'${NC}" + return 1 + fi + + echo -e "${YELLOW}Attaching to PM2 process: $service_name (ID: $numeric_id)${NC}" + pm2 attach "$numeric_id" } function attach_interactive_shell() { local service_name="$1" local provider="$2" - # Get service info again to access configuration + # For PM2, use PM2's attach functionality + if [ "$provider" = "pm2" ]; then + attach_pm2_process "$service_name" + return $? + fi + + # For systemd without session manager, show helpful message local service_info=$(get_service_info "$service_name") local config_file=$(echo "$service_info" | jq -r '.config') source "$config_file" source "$RUN_ENGINE_CONFIG_FILE" - echo -e "${RED}Error: Cannot attach to service '$service_name'${NC} [for now]" - echo -e "${YELLOW}Interactive attachment requires a session manager (tmux or screen).${NC}" + echo -e "${RED}Error: Cannot attach to systemd service '$service_name'${NC}" + echo -e "${YELLOW}Interactive attachment for systemd requires a session manager (tmux or screen).${NC}" echo "" echo -e "${BLUE}Current session manager: $SESSION_MANAGER${NC}" echo "" diff --git a/apps/startup-scripts/src/starter b/apps/startup-scripts/src/starter index 967146efad..0fa4b45f61 100755 --- a/apps/startup-scripts/src/starter +++ b/apps/startup-scripts/src/starter @@ -3,16 +3,17 @@ # AzerothCore Starter Script # This script handles the execution of AzerothCore binaries with optional GDB support # -# Usage: starter [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path] +# Usage: starter [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path] # # Parameters: -# $1 - Binary to execute (required) -# $2 - GDB configuration file (optional) -# $3 - Configuration file path (optional) -# $4 - System log file (optional) -# $5 - System error file (optional) -# $6 - GDB enabled flag (0/1, optional) -# $7 - Crashes directory path (optional) +# $1 - Binary path (required) +# $2 - Binary file name (required) +# $3 - GDB configuration file (optional) +# $4 - Configuration file path (optional) +# $5 - System log file (optional) +# $6 - System error file (optional) +# $7 - GDB enabled flag (0/1, optional) +# $8 - Crashes directory path (optional) BINPATH="$1" BINFILE="$2" @@ -23,25 +24,22 @@ SYSERR="$6" GDB_ENABLED="${7:-0}" CRASHES_PATH="$8" -BINARY=$(realpath "$BINPATH/$BINFILE") - # Default values CURRENT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DEFAULT_CRASHES_PATH="$CURRENT_PATH/logs/crashes" -DEFAULT_GDB_FILE="$CURRENT_PATH/gdb.conf" +[ -n "$CONFIG" ] && CONFIG_ABS=$(realpath "$CONFIG") # Set defaults if not provided -CONFIG="${CONFIG:-""}" CRASHES_PATH="${CRASHES_PATH:-$DEFAULT_CRASHES_PATH}" -GDB_FILE="${GDB_FILE:-$DEFAULT_GDB_FILE}" # Validate binary -if [ -z "$BINARY" ]; then - echo "Error: Binary parameter is required" - echo "Usage: $0 [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]" +if [ -z "$BINPATH" ] || [ -z "$BINFILE" ]; then + echo "Error: Binary path and file are required" + echo "Usage: $0 [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]" exit 1 fi +BINARY="$BINPATH/$BINFILE" if [ ! -f "$BINARY" ]; then echo "Error: Binary '$BINARY' not found" exit 1 @@ -50,7 +48,7 @@ fi # Create crashes directory if it doesn't exist mkdir -p "$CRASHES_PATH" -cd $BINPATH || { +cd "$BINPATH" || { echo "Error: Could not change to binary path '$BINPATH'" exit 1 } @@ -59,22 +57,25 @@ EXECPATH=$(realpath "$BINFILE") if [ "$GDB_ENABLED" -eq 1 ]; then echo "Starting $EXECPATH with GDB enabled" - + # Generate GDB configuration on the fly TIMESTAMP=$(date +%Y-%m-%d-%H-%M-%S) GDB_TEMP_FILE="$CRASHES_PATH/gdb-$TIMESTAMP.conf" GDB_OUTPUT_FILE="$CRASHES_PATH/gdb-$TIMESTAMP.txt" - - # Create GDB configuration - cat > "$GDB_TEMP_FILE" << EOF + + # Create GDB configuration file if it is not defined + if [ -z "$GDB_FILE" ]; then + + # Create GDB configuration + cat > "$GDB_TEMP_FILE" << EOF set logging file $GDB_OUTPUT_FILE set logging enabled on set debug timestamp EOF # Add run command with config if specified - if [ -n "$CONFIG" ]; then - echo "run -c $CONFIG" >> "$GDB_TEMP_FILE" + if [ -n "$CONFIG_ABS" ]; then + echo "run -c $CONFIG_ABS" >> "$GDB_TEMP_FILE" else echo "run" >> "$GDB_TEMP_FILE" fi @@ -86,32 +87,54 @@ info thread thread apply all backtrace full EOF + + GDB_FILE="$GDB_TEMP_FILE" + fi + + + # Create log files if specified if [ -n "$SYSLOG" ]; then [ ! -f "$SYSLOG" ] && touch "$SYSLOG" fi + if [ -n "$SYSERR" ]; then [ ! -f "$SYSERR" ] && touch "$SYSERR" fi # Execute with GDB if [ "${WITH_CONSOLE:-0}" -eq 0 ] && [ -n "$SYSLOG" ] && [ -n "$SYSERR" ]; then - gdb -x "$GDB_TEMP_FILE" --batch "$EXECPATH" >> "$SYSLOG" 2>> "$SYSERR" + gdb -x "$GDB_FILE" --batch "$EXECPATH" >> "$SYSLOG" 2>> "$SYSERR" else echo "> Console enabled" if [ -n "$SYSLOG" ] && [ -n "$SYSERR" ]; then - gdb -x "$GDB_TEMP_FILE" --batch "$EXECPATH" > >(tee "$SYSLOG") 2> >(tee "$SYSERR" >&2) + gdb -x "$GDB_FILE" --batch "$EXECPATH" > >(tee "$SYSLOG") 2> >(tee "$SYSERR" >&2) else - gdb -x "$GDB_TEMP_FILE" --batch "$EXECPATH" + gdb -x "$GDB_FILE" --batch "$EXECPATH" fi fi - - # Cleanup temporary GDB file - rm -f "$GDB_TEMP_FILE" + + + # clean up temporary GDB file if it exists + if [ -n "$GDB_TEMP_FILE" ]; then + # Clean up temporary GDB file + rm -f "$GDB_TEMP_FILE" + fi else - if [ -n "$CONFIG" ]; then - script -q -e -c "$EXECPATH -c \"$CONFIG\"" + # check if it's running under PM2 or `script` command does not exist + # Note: script is used to capture output in non-interactive sessions such as systemd (without tmux/screen) + # We use AC_LAUNCHED_BY_PM2 environment variable set by service-manager for robust PM2 detection + if [[ "$AC_LAUNCHED_BY_PM2" == "1" || ! -x "$(command -v script)" ]]; then + if [ -n "$CONFIG_ABS" ]; then + "$EXECPATH" -c "$CONFIG_ABS" + else + "$EXECPATH" + fi else - script -q -e -c "$EXECPATH" + if [ -n "$CONFIG_ABS" ]; then + script -q -e -c "$EXECPATH -c \"$CONFIG_ABS\"" + else + script -q -e -c "$EXECPATH" + fi fi fi diff --git a/apps/startup-scripts/test/test_startup_scripts.bats b/apps/startup-scripts/test/test_startup_scripts.bats index aaf95d1e1e..eed377ca87 100644 --- a/apps/startup-scripts/test/test_startup_scripts.bats +++ b/apps/startup-scripts/test/test_startup_scripts.bats @@ -23,7 +23,7 @@ teardown() { @test "starter: should fail with missing parameters" { run timeout 3s "$SCRIPT_DIR/starter" '' '' [ "$status" -ne 0 ] - [[ "$output" =~ "Error: Binary '/' not found" ]] + [[ "$output" =~ "Error: Binary path and file are required" ]] } @test "starter: should start with valid binary" { @@ -38,7 +38,16 @@ teardown() { @test "starter: should validate binary path exists" { run "$SCRIPT_DIR/starter" "/nonexistent/path" "test-server" [ "$status" -ne 0 ] - [[ "$output" =~ "Binary parameter is required" ]] || [[ "$output" =~ "No such file or directory" ]] + [[ "$output" =~ "Binary '/nonexistent/path/test-server' not found" ]] +} + +@test "starter: should detect PM2 environment properly" { + cd "$TEST_DIR" + # Test with AC_LAUNCHED_BY_PM2=1 (should not use script command) + AC_LAUNCHED_BY_PM2=1 run timeout 5s "$SCRIPT_DIR/starter" "$TEST_DIR/bin" "test-server" "" "$TEST_DIR/test-server.conf" "" "" 0 + debug_on_failure + # Should start without using script command + [[ "$output" =~ "Test server starting" ]] } # ===== SIMPLE RESTARTER TESTS ===== @@ -46,7 +55,7 @@ teardown() { @test "simple-restarter: should fail with missing parameters" { run timeout 3s "$SCRIPT_DIR/simple-restarter" '' '' [ "$status" -ne 0 ] - [[ "$output" =~ "Error: Binary '/' not found" ]] + [[ "$output" =~ "Error: Binary path and file are required" ]] } @test "simple-restarter: should fail with missing binary" { -- cgit v1.2.3