feat(bash): startup-scripts reworked + bash scripts workflow integration (#22401)

This commit is contained in:
Yehonal
2025-07-01 15:35:54 +02:00
committed by GitHub
parent d3130f0d39
commit e1b2689c3a
40 changed files with 4125 additions and 384 deletions

View File

@@ -0,0 +1,467 @@
#!/usr/bin/env bash
# AzerothCore Run Engine
# Advanced script for running AzerothCore services with session management and restart capabilities
#
# This script can be sourced to provide functions or executed directly with parameters
#
# Configuration Priority Order (highest to lowest):
# 1. conf.sh - User configuration file (highest priority)
# 2. Command line arguments (--config, --server-config, etc.)
# 3. Environment variables (RUN_ENGINE_*)
# 4. conf.sh.dist - Default configuration (lowest priority)
#
# Environment Variables:
# RUN_ENGINE_CONFIG_FILE - Path to temporary configuration file (optional)
# RUN_ENGINE_SESSION_MANAGER - Session manager (none|auto|tmux|screen, default: auto)
# RUN_ENGINE_BINPATH - Binary directory path
# RUN_ENGINE_SERVERBIN - Server binary name (worldserver|authserver)
# RUN_ENGINE_CONFIG - Server configuration file path
# RUN_ENGINE_LOGS_PATH - Directory for log files
# RUN_ENGINE_CRASHES_PATH - Directory for crash dumps
# RUN_ENGINE_SESSION_NAME - Session name for tmux/screen
export RUN_ENGINE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Configuration priority order:
# 1. conf.sh (highest priority - user overrides)
# 2. Environment variables (RUN_ENGINE_*)
# 3. conf.sh.dist (lowest priority - defaults)
# Load default configuration first (sets defaults from environment variables)
if [ -e "$RUN_ENGINE_PATH/conf.sh.dist" ]; then
source "$RUN_ENGINE_PATH/conf.sh.dist"
fi
# Load user configuration if exists (this takes priority over everything)
if [ -e "$RUN_ENGINE_PATH/conf.sh" ]; then
source "$RUN_ENGINE_PATH/conf.sh"
fi
# Load configuration
function load_config() {
local config_file="$1"
# If a specific config file is provided via command line, load it
# This allows temporary overrides for specific runs
if [ -n "$config_file" ] && [ -e "$config_file" ]; then
echo "Loading configuration from: $config_file"
source "$config_file"
elif [ -n "$RUN_ENGINE_CONFIG_FILE" ] && [ -e "$RUN_ENGINE_CONFIG_FILE" ]; then
echo "Loading configuration from environment: $RUN_ENGINE_CONFIG_FILE"
source "$RUN_ENGINE_CONFIG_FILE"
fi
# Final override with any remaining environment variables
# This ensures that even after loading config files, environment variables take precedence
BINPATH="${RUN_ENGINE_BINPATH:-$BINPATH}"
SERVERBIN="${RUN_ENGINE_SERVERBIN:-$SERVERBIN}"
CONFIG="${RUN_ENGINE_CONFIG:-$CONFIG}"
SESSION_MANAGER="${RUN_ENGINE_SESSION_MANAGER:-$SESSION_MANAGER}"
LOGS_PATH="${RUN_ENGINE_LOGS_PATH:-$LOGS_PATH}"
CRASHES_PATH="${RUN_ENGINE_CRASHES_PATH:-$CRASHES_PATH}"
}
# Detect available session manager
function detect_session_manager() {
if command -v tmux >/dev/null 2>&1; then
echo "tmux"
elif command -v screen >/dev/null 2>&1; then
echo "screen"
else
echo "none"
fi
}
# Determine which session manager to use
function get_session_manager() {
local requested="$1"
case "$requested" in
"none")
echo "none"
;;
"auto")
detect_session_manager
;;
"tmux")
if command -v tmux >/dev/null 2>&1; then
echo "tmux"
else
echo "error"
fi
;;
"screen")
if command -v screen >/dev/null 2>&1; then
echo "screen"
else
echo "error"
fi
;;
*)
echo "none"
;;
esac
}
# Configure log files
function configure_files() {
TRACE_BEGIN_STRING="SIGSEGV"
TRACE_FILE="$LOGS_PATH/${LOG_PREFIX_NAME}_trace.log"
ERR_FILE="$LOGS_PATH/${LOG_PREFIX_NAME}_error.log"
SYSLOG="$LOGS_PATH/${LOG_PREFIX_NAME}_system.log"
SYSERR="$LOGS_PATH/${LOG_PREFIX_NAME}_system.err"
LINKS_FILE="$LOGS_PATH/${LOG_PREFIX_NAME}_crash_links.link"
}
# Check if service is running
function check_status() {
local session_name="$1"
local ret=1
# Check for GDB process
local gdbres=$(pgrep -f "gdb.*--batch.*$SERVERBIN")
if [[ "$GDB_ENABLED" -eq 1 && -n "$gdbres" ]]; then
return 1
fi
# Check for binary process
local binres=$(pgrep -f "$SERVERBIN -c $CONFIG")
if [ -n "$binres" ]; then
return 1
fi
# Check session manager
if [ -n "$session_name" ]; then
case "$(get_session_manager "${SESSION_MANAGER:-auto}")" in
"tmux")
tmux has-session -t "$session_name" 2>/dev/null && return 1
;;
"screen")
screen -ls "$session_name" 2>/dev/null | grep -q "$session_name" && return 1
;;
esac
fi
return 0
}
# Run with session manager
function run_with_session() {
local session_manager="$1"
local session_name="$2"
local wrapper="$3"
shift 3
local args=("$@")
if [ "$wrapper" = "simple-restarter" ]; then
script_path="$RUN_ENGINE_PATH/simple-restarter"
else
script_path="$RUN_ENGINE_PATH/starter"
fi
case "$session_manager" in
"tmux")
echo "> Starting with tmux session: $session_name - attach with 'tmux attach -t $session_name'"
tmux new-session -d -s "$session_name" -- "$script_path" "${args[@]}"
;;
"screen")
local OPTIONS="-A -m -d -S"
if [ -n "$SCREEN_OPTIONS" ]; then
OPTIONS="$SCREEN_OPTIONS"
fi
echo "> Starting with screen session: $session_name (options: $OPTIONS) - attach with 'screen -r $session_name'"
echo "screen $OPTIONS \"$session_name\" -- \"$script_path\" ${args[*]}"
screen $OPTIONS "$session_name" -- "$script_path" "${args[@]}"
;;
"none"|*)
echo "> Starting without session manager"
"$script_path" "${args[@]}"
;;
esac
}
# Parse command line arguments
function parse_arguments() {
local mode="$1"
local serverbin="$2"
shift 2
local config_file=""
local serverconfig=""
local session_manager=""
# Parse named arguments
while [[ $# -gt 0 ]]; do
case $1 in
--config)
config_file="$2"
shift 2
;;
--server-config)
serverconfig="$2"
shift 2
;;
--session-manager)
session_manager="$2"
shift 2
;;
*)
echo "Unknown argument: $1"
return 1
;;
esac
done
# Export parsed values for use by start_service
export PARSED_MODE="$mode"
export PARSED_SERVERBIN="$serverbin"
export PARSED_CONFIG_FILE="$config_file"
export PARSED_SERVERCONFIG="$serverconfig"
export PARSED_SESSION_MANAGER="$session_manager"
}
# Start service (single run or with simple-restarter)
function start_service() {
local config_file="$1"
local serverbin_path="$2"
local serverconfig="$3"
local use_restarter="${4:-false}"
local session_manager_choice="$5"
# Load configuration first
load_config "$config_file"
# if no session manager is specified, get it from config
if [ -z "$session_manager_choice" ]; then
session_manager_choice="$SESSION_MANAGER"
fi
# Parse serverbin_path to extract BINPATH and SERVERBIN
if [ -n "$serverbin_path" ]; then
# If it's a full path, extract directory and binary name
if [[ "$serverbin_path" == */* ]]; then
BINPATH="$(dirname "$serverbin_path")"
SERVERBIN="$(basename "$serverbin_path")"
else
# If it's just a binary name, use it as-is (system PATH)
SERVERBIN="$serverbin_path"
BINPATH="${BINPATH:-""}" # Empty means use current directory or system PATH
fi
fi
# 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}"
echo "SERVERBIN: $SERVERBIN"
# Validate required parameters
if [ -z "$SERVERBIN" ]; then
echo "Error: SERVERBIN is required"
echo "Could not determine server binary from: $serverbin_path"
echo "Provide it as:"
echo " - Full path: $0 <mode> /path/to/bin/worldserver"
echo " - Binary name: $0 <mode> worldserver"
echo " - Environment variables: RUN_ENGINE_SERVERBIN"
echo " - Configuration file with SERVERBIN variable"
return 1
fi
# If BINPATH is set, validate binary exists and create log paths
if [ -n "$BINPATH" ]; then
if [ ! -d "$BINPATH" ]; then
echo "Error: BINPATH not found: $BINPATH"
return 1
fi
# Set up directories and logging relative to BINPATH
LOGS_PATH="${LOGS_PATH:-"$BINPATH/logs"}"
mkdir -p "$LOGS_PATH"
mkdir -p "$LOGS_PATH/crashes"
else
# For system binaries, try to detect binary location and create logs accordingly
local detected_binpath=""
# Try to find binary in system PATH
local binary_location=$(which "$SERVERBIN" 2>/dev/null)
if [ -n "$binary_location" ]; then
detected_binpath="$(dirname "$binary_location")"
echo "Binary found in system PATH: $binary_location"
# Set BINPATH to the detected location so starter script can find the binary
BINPATH="$detected_binpath"
fi
# Set up log paths based on detected or fallback location
if [ -n "$detected_binpath" ]; then
LOGS_PATH="${LOGS_PATH:-"$detected_binpath/logs"}"
else
# Fallback to current directory for logs
LOGS_PATH="${LOGS_PATH:-./logs}"
fi
CRASHES_PATH="${CRASHES_PATH:-"$LOGS_PATH/crashes"}"
mkdir -p "$LOGS_PATH"
mkdir -p "$CRASHES_PATH"
fi
# Set up logging names
LOG_PREFIX_NAME="${LOG_PREFIX_NAME:-${SERVERBIN%server}}"
# Set up session name (with backward compatibility for SCREEN_NAME)
SESSION_NAME="${SESSION_NAME:-$SCREEN_NAME}"
SESSION_NAME="${SESSION_NAME:-AC-${SERVERBIN%server}}"
configure_files
local session_manager=$(get_session_manager "$session_manager_choice")
if [ "$session_manager" = "error" ]; then
echo "Error: Invalid session manager specified: $session_manager_choice, is it installed?"
exit 1
fi
echo "Using session manager: $session_manager"
echo "Starting server: $SERVERBIN"
if [ -n "$CONFIG" ]; then
echo "Server config: $CONFIG"
else
echo "Server config: default (not specified)"
fi
if [ "$use_restarter" = "true" ]; then
# Use simple-restarter for restart functionality
local gdb_enabled="${GDB_ENABLED:-0}"
run_with_session "$session_manager" "$SESSION_NAME" "simple-restarter" "$BINPATH" "$SERVERBIN" "$GDB" "$CONFIG" "$SYSLOG" "$SYSERR" "$gdb_enabled" "$CRASHES_PATH"
else
# Single run using starter
local gdb_enabled="${GDB_ENABLED:-0}"
run_with_session "$session_manager" "$SESSION_NAME" "starter" "$BINPATH" "$SERVERBIN" "$GDB" "$CONFIG" "$SYSLOG" "$SYSERR" "$gdb_enabled" "$CRASHES_PATH"
fi
}
# Cleanup function
function finish() {
local session_manager=$(get_session_manager "${SESSION_MANAGER:-auto}")
if [ -n "$SESSION_NAME" ]; then
case "$session_manager" in
"tmux")
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
;;
"screen")
screen -X -S "$SESSION_NAME" quit 2>/dev/null || true
;;
esac
fi
}
# Legacy compatibility functions for old examples
function restarter() {
echo "Legacy function 'restarter' called - redirecting to new API"
start_service "" "" "" "true" "${SESSION_MANAGER:-auto}"
}
function starter() {
echo "Legacy function 'starter' called - redirecting to new API"
start_service "" "" "" "false" "${SESSION_MANAGER:-auto}"
}
# Set trap for cleanup (currently disabled to avoid interfering with systemd)
# trap finish EXIT
# Main execution when script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
case "${1:-help}" in
"start"|"restart")
if [ $# -lt 2 ]; then
echo "Error: Missing required arguments"
echo "Usage: $0 <mode> <serverbin> [options]"
echo "Example: $0 start worldserver --config ./conf-world.sh --server-config worldserver.conf"
exit 1
fi
# Parse arguments
if ! parse_arguments "$@"; then
exit 1
fi
# Determine restart mode
use_restarter="false"
if [ "$PARSED_MODE" = "restart" ]; then
use_restarter="true"
fi
# Start service with parsed arguments
start_service "$PARSED_CONFIG_FILE" "$PARSED_SERVERBIN" "$PARSED_SERVERCONFIG" "$use_restarter" "$PARSED_SESSION_MANAGER"
;;
"help"|*)
echo "AzerothCore Run Engine"
echo ""
echo "Usage: $0 <mode> <serverbin> [options]"
echo ""
echo "Modes:"
echo " start - Start service once (no restart on crash)"
echo " restart - Start service with restart on crash (uses simple-restarter)"
echo ""
echo "Required Parameters:"
echo " serverbin - Server binary (full path or binary name)"
echo " Full path: /path/to/bin/worldserver"
echo " Binary name: worldserver (uses system PATH)"
echo ""
echo "Options:"
echo " --config <file> - Path to configuration file"
echo " --server-config <file> - Server configuration file (sets -c parameter)"
echo " --session-manager <type> - Session manager: none|auto|tmux|screen (default: auto)"
echo ""
echo "Configuration Priority (highest to lowest):"
echo " 1. conf.sh - User configuration file"
echo " 2. Command line arguments (--config, --server-config, etc.)"
echo " 3. Environment variables (RUN_ENGINE_*)"
echo " 4. conf.sh.dist - Default configuration"
echo ""
echo "Environment Variables:"
echo " RUN_ENGINE_CONFIG_FILE - Config file path"
echo " RUN_ENGINE_SESSION_MANAGER - Session manager (default: auto)"
echo " RUN_ENGINE_BINPATH - Binary directory path"
echo " RUN_ENGINE_SERVERBIN - Server binary name"
echo " RUN_ENGINE_CONFIG - Server configuration file"
echo " RUN_ENGINE_LOGS_PATH - Directory for log files"
echo " RUN_ENGINE_CRASHES_PATH - Directory for crash dumps"
echo " RUN_ENGINE_SESSION_NAME - Session name for tmux/screen"
echo ""
echo "Examples:"
echo ""
echo " # Using full path to binary"
echo " $0 start /home/user/ac/bin/worldserver"
echo ""
echo " # Using binary name (system PATH)"
echo " $0 start worldserver"
echo ""
echo " # With configuration file"
echo " $0 start worldserver --config ./conf-world.sh"
echo ""
echo " # With server configuration (sets -c parameter)"
echo " $0 start /path/to/bin/worldserver --server-config /etc/worldserver.conf"
echo ""
echo " # With session manager"
echo " $0 restart worldserver --session-manager tmux"
echo ""
echo " # Complete example"
echo " $0 restart /home/user/ac/bin/worldserver --config ./conf-world.sh --server-config worldserver.conf --session-manager screen"
echo ""
echo "Binary Resolution:"
echo " - Full path (contains /): Extracts directory and binary name"
echo " - Binary name only: Uses system PATH to find executable"
echo " Auto-detection will check current directory first, then system PATH"
echo ""
echo "Server Config:"
echo " If --server-config is specified, it's passed as -c parameter to the server."
echo " If not specified, the server will use its default configuration."
;;
esac
fi