new version commit
This commit is contained in:
651
apps/startup-scripts/README.md
Normal file
651
apps/startup-scripts/README.md
Normal file
@@ -0,0 +1,651 @@
|
||||
# AzerothCore Startup Scripts
|
||||
|
||||
A comprehensive suite of scripts for managing AzerothCore server instances with advanced session management, automatic restart capabilities, and production-ready service management.
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Components](#components)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Configuration](#configuration)
|
||||
- [Detailed Usage](#detailed-usage)
|
||||
- [Multiple Realms Setup](#multiple-realms-setup)
|
||||
- [Service Management](#service-management)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
The AzerothCore startup scripts provide multiple approaches to running server instances:
|
||||
|
||||
1. **Development/Testing**: Simple execution for debugging and development
|
||||
2. **Production with Restarts**: Automatic restart on crashes with crash detection
|
||||
3. **Background Services**: Production-ready service management with PM2 or systemd
|
||||
4. **Session Management**: Interactive console access via tmux/screen
|
||||
|
||||
All scripts are integrated into the `acore.sh` dashboard for easy access.
|
||||
|
||||
### 📦 Automatic Deployment
|
||||
|
||||
**Important**: When you compile AzerothCore using the acore dashboard (`./acore.sh compiler build`), all startup scripts are automatically copied from `apps/startup-scripts/src/` to your `bin/` folder. This means:
|
||||
|
||||
- ✅ **Portable Deployment**: You can copy the entire `bin/` folder to different servers
|
||||
- ✅ **Self-Contained**: All restart and service management tools travel with your binaries
|
||||
- ✅ **No Additional Setup**: Scripts work immediately after deployment
|
||||
- ✅ **Production Ready**: Deploy to production servers without needing the full source code
|
||||
|
||||
This makes it easy to deploy your compiled binaries along with the management scripts to production environments where you may not have the full AzerothCore source code.
|
||||
|
||||
## 🔧 Components
|
||||
|
||||
### Core Scripts
|
||||
|
||||
- **`run-engine`**: Advanced script with session management and configuration priority
|
||||
- **`simple-restarter`**: Wrapper around starter with restart functionality (legacy compatibility)
|
||||
- **`starter`**: Basic binary execution with optional GDB support
|
||||
- **`service-manager.sh`**: Production service management with PM2/systemd
|
||||
|
||||
### Configuration
|
||||
|
||||
- **`conf.sh.dist`**: Default configuration template
|
||||
- **`conf.sh`**: User configuration (create from .dist)
|
||||
- **`gdb.conf`**: GDB debugging configuration
|
||||
|
||||
### Examples
|
||||
|
||||
- **`restarter-auth.sh`**: Auth server restart example
|
||||
- **`restarter-world.sh`**: World server restart example
|
||||
- **`starter-auth.sh`**: Auth server basic start example
|
||||
- **`starter-world.sh`**: World server basic start example
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Basic Server Start (Development)
|
||||
|
||||
```bash
|
||||
# Start authserver directly
|
||||
./starter /path/to/bin authserver
|
||||
|
||||
# Start worldserver with config
|
||||
./starter /path/to/bin worldserver "" /path/to/worldserver.conf
|
||||
```
|
||||
|
||||
### 2. Start with Auto-Restart
|
||||
|
||||
```bash
|
||||
# Using simple-restarter (legacy)
|
||||
./simple-restarter /path/to/bin authserver
|
||||
|
||||
# Using run-engine (recommended)
|
||||
./run-engine restart authserver --bin-path /path/to/bin
|
||||
```
|
||||
|
||||
### 3. Production Service Management
|
||||
|
||||
```bash
|
||||
# Create and start a service
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin
|
||||
|
||||
# List all services
|
||||
./service-manager.sh list
|
||||
|
||||
# Stop a service
|
||||
./service-manager.sh stop auth
|
||||
```
|
||||
|
||||
### 4. Using acore.sh Dashboard
|
||||
|
||||
```bash
|
||||
# Interactive dashboard
|
||||
./acore.sh
|
||||
|
||||
# Direct commands
|
||||
./acore.sh run-authserver # Start authserver with restart
|
||||
./acore.sh run-worldserver # Start worldserver with restart
|
||||
./acore.sh service-manager # Access service manager
|
||||
```
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Configuration Priority (Highest to Lowest)
|
||||
|
||||
1. **`conf.sh`** - User configuration file
|
||||
2. **Command line arguments** - Runtime parameters
|
||||
3. **Environment variables** - `RUN_ENGINE_*` variables
|
||||
4. **`conf.sh.dist`** - Default configuration
|
||||
|
||||
### Creating Configuration
|
||||
|
||||
```bash
|
||||
# Copy default configuration
|
||||
cp scripts/conf.sh.dist scripts/conf.sh
|
||||
|
||||
# Edit your configuration
|
||||
nano scripts/conf.sh
|
||||
```
|
||||
|
||||
### Key Configuration Options
|
||||
|
||||
```bash
|
||||
# Binary settings
|
||||
export BINPATH="/path/to/azerothcore/bin"
|
||||
export SERVERBIN="worldserver" # or "authserver"
|
||||
export CONFIG="/path/to/worldserver.conf"
|
||||
|
||||
# Session management
|
||||
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"
|
||||
|
||||
# Logging
|
||||
export LOGS_PATH="/path/to/logs"
|
||||
export CRASHES_PATH="/path/to/crashes"
|
||||
export LOG_PREFIX_NAME="realm1"
|
||||
```
|
||||
|
||||
## 📖 Detailed Usage
|
||||
|
||||
### 1. Run Engine
|
||||
|
||||
The `run-engine` is the most advanced script with multiple operation modes:
|
||||
|
||||
#### Basic Execution
|
||||
```bash
|
||||
# Start server once
|
||||
./run-engine start worldserver --bin-path /path/to/bin
|
||||
|
||||
# Start with configuration file
|
||||
./run-engine start worldserver --config ./conf-world.sh
|
||||
|
||||
# Start with specific server config
|
||||
./run-engine start worldserver --server-config /path/to/worldserver.conf
|
||||
```
|
||||
|
||||
#### Restart Mode
|
||||
```bash
|
||||
# Automatic restart on crash
|
||||
./run-engine restart worldserver --bin-path /path/to/bin
|
||||
|
||||
# Restart with session management
|
||||
./run-engine restart worldserver --session-manager tmux
|
||||
```
|
||||
|
||||
#### Session Management
|
||||
```bash
|
||||
# Start in tmux session
|
||||
./run-engine start worldserver --session-manager tmux
|
||||
|
||||
# Attach to existing session
|
||||
tmux attach-session -t worldserver
|
||||
|
||||
# Start in screen session
|
||||
./run-engine start worldserver --session-manager screen
|
||||
|
||||
# Attach to screen session
|
||||
screen -r worldserver
|
||||
```
|
||||
|
||||
#### Configuration Options
|
||||
```bash
|
||||
./run-engine restart worldserver \
|
||||
--bin-path /path/to/bin \
|
||||
--server-config /path/to/worldserver.conf \
|
||||
--session-manager tmux \
|
||||
--gdb-enabled 1 \
|
||||
--logs-path /path/to/logs \
|
||||
--crashes-path /path/to/crashes
|
||||
```
|
||||
|
||||
### 2. Simple Restarter
|
||||
|
||||
Legacy-compatible wrapper with restart functionality:
|
||||
|
||||
```bash
|
||||
# Basic restart
|
||||
./simple-restarter /path/to/bin worldserver
|
||||
|
||||
# With full parameters
|
||||
./simple-restarter \
|
||||
/path/to/bin \
|
||||
worldserver \
|
||||
./gdb.conf \
|
||||
/path/to/worldserver.conf \
|
||||
/path/to/system.log \
|
||||
/path/to/system.err \
|
||||
1 \
|
||||
/path/to/crashes
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
1. Binary path (required)
|
||||
2. Binary name (required)
|
||||
3. GDB configuration file (optional)
|
||||
4. Server configuration file (optional)
|
||||
5. System log file (optional)
|
||||
6. System error file (optional)
|
||||
7. GDB enabled flag (0/1, optional)
|
||||
8. Crashes directory path (optional)
|
||||
|
||||
### 3. Starter
|
||||
|
||||
Basic execution script without restart functionality:
|
||||
|
||||
```bash
|
||||
# Simple start
|
||||
./starter /path/to/bin worldserver
|
||||
|
||||
# With GDB debugging
|
||||
./starter /path/to/bin worldserver ./gdb.conf /path/to/worldserver.conf "" "" 1
|
||||
```
|
||||
|
||||
### 4. Service Manager
|
||||
|
||||
Production-ready service management:
|
||||
|
||||
#### Creating Services
|
||||
```bash
|
||||
# Auto-detect provider (PM2 or systemd)
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin
|
||||
|
||||
# Force PM2
|
||||
./service-manager.sh create world worldserver --provider pm2 --bin-path /path/to/bin
|
||||
|
||||
# Force systemd
|
||||
./service-manager.sh create world worldserver --provider systemd --bin-path /path/to/bin
|
||||
|
||||
# Create service with restart policy
|
||||
./service-manager.sh create world worldserver --bin-path /path/to/bin --restart-policy always
|
||||
```
|
||||
|
||||
#### Restart Policies
|
||||
|
||||
Services support two restart policies:
|
||||
|
||||
- **`on-failure`** (default): Restart only on crashes or errors (exit code != 0, only works with PM2 or systemd without tmux/screen)
|
||||
- **`always`**: Restart on any exit, including clean shutdown (exit code 0)
|
||||
|
||||
**Important**: When using `--restart-policy always`, the in-game command `server shutdown X` will behave like `server restart X` - the service will automatically restart after shutdown. Only the shutdown message differs from a restart message.
|
||||
|
||||
```bash
|
||||
# Service that restarts only on crashes (default behavior)
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin --restart-policy on-failure
|
||||
|
||||
# Service that always restarts (even on manual shutdown)
|
||||
./service-manager.sh create world worldserver --bin-path /path/to/bin --restart-policy always
|
||||
|
||||
# Update existing service restart policy
|
||||
./service-manager.sh update worldserver --restart-policy always
|
||||
```
|
||||
|
||||
#### Service Operations
|
||||
```bash
|
||||
# Start/stop services
|
||||
./service-manager.sh start auth
|
||||
./service-manager.sh stop world
|
||||
./service-manager.sh restart auth
|
||||
|
||||
# View logs
|
||||
./service-manager.sh logs world
|
||||
./service-manager.sh logs world --follow
|
||||
|
||||
# Attach to console (interactive)
|
||||
./service-manager.sh attach world
|
||||
|
||||
# List services
|
||||
./service-manager.sh list
|
||||
./service-manager.sh list pm2
|
||||
./service-manager.sh list systemd
|
||||
|
||||
# Delete service
|
||||
./service-manager.sh delete auth
|
||||
```
|
||||
|
||||
#### Health and Console Commands
|
||||
|
||||
Use these commands to programmatically check service health and interact with the console (used by CI workflows):
|
||||
|
||||
```bash
|
||||
# Check if service is currently running (exit 0 if running)
|
||||
./service-manager.sh is-running world
|
||||
|
||||
# Print current uptime in seconds (fails if not running)
|
||||
./service-manager.sh uptime-seconds world
|
||||
|
||||
# Wait until uptime >= 10s (optional timeout 240s)
|
||||
./service-manager.sh wait-uptime world 10 240
|
||||
|
||||
# Send a console command (uses pm2 send or tmux/screen)
|
||||
./service-manager.sh send world "server info"
|
||||
|
||||
# Show provider, configs and run-engine settings
|
||||
./service-manager.sh show-config world
|
||||
```
|
||||
|
||||
Notes:
|
||||
- For `send`, PM2 provider uses `pm2 send` with the process ID; systemd provider requires a session manager (tmux/screen). If no attachable session is configured, the command fails.
|
||||
- `wait-uptime` fails with a non-zero exit code if the service does not reach the requested uptime within the timeout window.
|
||||
|
||||
#### Service Configuration
|
||||
```bash
|
||||
# Update service settings
|
||||
./service-manager.sh update world --session-manager screen --gdb-enabled 1
|
||||
|
||||
# Edit configuration
|
||||
./service-manager.sh edit world
|
||||
|
||||
# Restore missing services from registry
|
||||
./service-manager.sh restore
|
||||
```
|
||||
|
||||
## 🌍 Multiple Realms Setup
|
||||
|
||||
### Method 1: Using Service Manager (Recommended)
|
||||
|
||||
```bash
|
||||
# Create multiple world server instances with different restart policies
|
||||
./service-manager.sh create world1 worldserver \
|
||||
--bin-path /path/to/bin \
|
||||
--server-config /path/to/worldserver-realm1.conf \
|
||||
--restart-policy on-failure
|
||||
|
||||
./service-manager.sh create world2 worldserver \
|
||||
--bin-path /path/to/bin \
|
||||
--server-config /path/to/worldserver-realm2.conf \
|
||||
--restart-policy always
|
||||
|
||||
# Single auth server for all realms (always restart for stability)
|
||||
./service-manager.sh create auth authserver \
|
||||
--bin-path /path/to/bin \
|
||||
--server-config /path/to/authserver.conf \
|
||||
--restart-policy always
|
||||
```
|
||||
|
||||
### Method 2: Using Run Engine with Different Configurations
|
||||
|
||||
Create separate configuration files for each realm:
|
||||
|
||||
**conf-realm1.sh:**
|
||||
```bash
|
||||
export BINPATH="/path/to/bin"
|
||||
export SERVERBIN="worldserver"
|
||||
export CONFIG="/path/to/worldserver-realm1.conf"
|
||||
export SESSION_NAME="ac-realm1"
|
||||
export LOG_PREFIX_NAME="realm1"
|
||||
export LOGS_PATH="/path/to/logs/realm1"
|
||||
```
|
||||
|
||||
**conf-realm2.sh:**
|
||||
```bash
|
||||
export BINPATH="/path/to/bin"
|
||||
export SERVERBIN="worldserver"
|
||||
export CONFIG="/path/to/worldserver-realm2.conf"
|
||||
export SESSION_NAME="ac-realm2"
|
||||
export LOG_PREFIX_NAME="realm2"
|
||||
export LOGS_PATH="/path/to/logs/realm2"
|
||||
```
|
||||
|
||||
Start each realm:
|
||||
```bash
|
||||
./run-engine restart worldserver --config ./conf-realm1.sh
|
||||
./run-engine restart worldserver --config ./conf-realm2.sh
|
||||
```
|
||||
|
||||
### Method 3: Using Examples with Custom Configurations
|
||||
|
||||
Copy and modify the example scripts:
|
||||
|
||||
```bash
|
||||
# Copy examples
|
||||
cp examples/restarter-world.sh restarter-realm1.sh
|
||||
cp examples/restarter-world.sh restarter-realm2.sh
|
||||
|
||||
# Edit each script to point to different configuration files
|
||||
# Then run:
|
||||
./restarter-realm1.sh
|
||||
./restarter-realm2.sh
|
||||
```
|
||||
|
||||
## 🛠️ Service Management
|
||||
|
||||
### Service Registry and Persistence
|
||||
|
||||
The service manager includes a comprehensive registry system that tracks all created services and enables automatic restoration:
|
||||
|
||||
#### Service Registry Features
|
||||
|
||||
- **Automatic Tracking**: All services are automatically registered when created
|
||||
- **Cross-Reboot Persistence**: PM2 services are configured with startup persistence
|
||||
- **Service Restoration**: Missing services can be detected and restored from registry
|
||||
- **Migration Support**: Legacy service configurations can be migrated to the new format
|
||||
|
||||
#### Using the Registry
|
||||
|
||||
```bash
|
||||
# Check for missing services and restore them
|
||||
./service-manager.sh restore
|
||||
|
||||
# List all registered services (includes status)
|
||||
./service-manager.sh list
|
||||
|
||||
# Services are automatically added to registry on creation
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin
|
||||
```
|
||||
|
||||
#### Custom Configuration Directories
|
||||
|
||||
You can customize where service configurations and PM2/systemd files are stored:
|
||||
|
||||
```bash
|
||||
# Set custom directories
|
||||
export AC_SERVICE_CONFIG_DIR="/path/to/your/project/services"
|
||||
|
||||
# Now all service operations will use these custom directories
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin
|
||||
```
|
||||
|
||||
This is particularly useful for:
|
||||
- **Version Control**: Keep service configurations in your project repository
|
||||
- **Multiple Projects**: Separate service configurations per project
|
||||
- **Team Collaboration**: Share service setups across development teams
|
||||
|
||||
#### Migration from Legacy Format
|
||||
|
||||
If you have existing services in the old format, use the migration script:
|
||||
|
||||
```bash
|
||||
# Migrate existing registry to new format
|
||||
./migrate-registry.sh
|
||||
|
||||
# The script will:
|
||||
# - Detect old format automatically
|
||||
# - Create a backup of the old registry
|
||||
# - Convert to new format with proper tracking
|
||||
# - Preserve all existing service information
|
||||
```
|
||||
|
||||
### PM2 Services
|
||||
|
||||
When using PM2 as the service provider:
|
||||
|
||||
* [PM2 CLI Documentation](https://pm2.io/docs/runtime/reference/pm2-cli/)
|
||||
|
||||
**Automatic PM2 Persistence**: The service manager automatically configures PM2 for persistence across reboots by:
|
||||
- Running `pm2 startup` to set up the startup script
|
||||
- Running `pm2 save` after each service creation/modification
|
||||
- This ensures your services automatically start when the system reboots
|
||||
|
||||
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:
|
||||
|
||||
#### Configuration Directory Variables
|
||||
|
||||
- **`AC_SERVICE_CONFIG_DIR`**: Override the default configuration directory for services registry and configurations
|
||||
- Default: `${XDG_CONFIG_HOME:-$HOME/.config}/azerothcore/services`
|
||||
- Used for storing service registry and run-engine configurations
|
||||
|
||||
#### Service Detection Variables
|
||||
|
||||
- **`AC_LAUNCHED_BY_PM2`**: Set to `1` when launched by PM2 (automatically set by service-manager)
|
||||
- Disables the use of the `unbuffer` 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:
|
||||
|
||||
```bash
|
||||
# Systemd commands
|
||||
systemctl --user status acore-auth # Check status
|
||||
systemctl --user logs acore-auth # View logs
|
||||
systemctl --user restart acore-auth # Restart
|
||||
systemctl --user enable acore-auth # Enable auto-start
|
||||
|
||||
# For system services (requires sudo)
|
||||
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:
|
||||
|
||||
```bash
|
||||
# Create service with tmux
|
||||
./service-manager.sh create world worldserver \
|
||||
--bin-path /path/to/bin \
|
||||
--session-manager tmux
|
||||
|
||||
# Attach to the session
|
||||
./service-manager.sh attach world
|
||||
# or directly:
|
||||
tmux attach-session -t worldserver
|
||||
```
|
||||
|
||||
## 🎮 Integration with acore.sh Dashboard
|
||||
|
||||
The startup scripts are fully integrated into the AzerothCore dashboard:
|
||||
|
||||
### Direct Commands
|
||||
|
||||
```bash
|
||||
# Run servers with simple restart (development/testing)
|
||||
./acore.sh run-worldserver # Option 11 or 'rw'
|
||||
./acore.sh run-authserver # Option 12 or 'ra'
|
||||
|
||||
# Access service manager (production)
|
||||
./acore.sh service-manager # Option 15 or 'sm'
|
||||
|
||||
# Examples:
|
||||
./acore.sh rw # Quick worldserver start
|
||||
./acore.sh ra # Quick authserver start
|
||||
./acore.sh sm create auth authserver --bin-path /path/to/bin
|
||||
```
|
||||
|
||||
### What Happens Behind the Scenes
|
||||
|
||||
- **run-worldserver/run-authserver**: Calls `simple-restarter` with appropriate binary
|
||||
- **service-manager**: Provides full access to the service management interface
|
||||
- Scripts automatically use the correct binary path from your build configuration
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Binary Not Found
|
||||
```bash
|
||||
Error: Binary '/path/to/bin/worldserver' not found
|
||||
```
|
||||
**Solution**: Check binary path and ensure servers are compiled
|
||||
```bash
|
||||
# Check if binary exists
|
||||
ls -la /path/to/bin/worldserver
|
||||
|
||||
# Compile if needed
|
||||
./acore.sh compiler build
|
||||
```
|
||||
|
||||
#### 2. Configuration File Issues
|
||||
```bash
|
||||
Error: Configuration file not found
|
||||
```
|
||||
**Solution**: Create configuration from template
|
||||
```bash
|
||||
cp scripts/conf.sh.dist scripts/conf.sh
|
||||
# Edit conf.sh with correct paths
|
||||
```
|
||||
|
||||
#### 3. Session Manager Not Available
|
||||
```bash
|
||||
Warning: tmux not found, falling back to direct execution
|
||||
```
|
||||
**Solution**: Install required session manager
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt install tmux screen
|
||||
|
||||
# CentOS/RHEL
|
||||
sudo yum install tmux screen
|
||||
```
|
||||
|
||||
#### 4. Permission Issues (systemd)
|
||||
```bash
|
||||
Failed to create systemd service
|
||||
```
|
||||
**Solution**: Check user permissions or use --system flag
|
||||
```bash
|
||||
# For user services (no sudo required)
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin
|
||||
|
||||
# For system services (requires sudo)
|
||||
./service-manager.sh create auth authserver --bin-path /path/to/bin --system
|
||||
```
|
||||
|
||||
#### 5. PM2 Not Found
|
||||
```bash
|
||||
Error: PM2 is not installed
|
||||
```
|
||||
**Solution**: Install PM2
|
||||
```bash
|
||||
npm install -g pm2
|
||||
# or
|
||||
sudo npm install -g pm2
|
||||
```
|
||||
|
||||
#### 7. Registry Out of Sync
|
||||
```bash
|
||||
# If the service registry shows services that don't actually exist
|
||||
```
|
||||
**Solution**: Use registry sync or restore
|
||||
```bash
|
||||
# Check and restore missing services (also cleans up orphaned entries)
|
||||
./service-manager.sh restore
|
||||
|
||||
# If you have a very old registry format, migrate it
|
||||
./migrate-registry.sh
|
||||
```
|
||||
|
||||
|
||||
1
apps/startup-scripts/src/.gitignore
vendored
Normal file
1
apps/startup-scripts/src/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
logs
|
||||
57
apps/startup-scripts/src/conf.sh.dist
Normal file
57
apps/startup-scripts/src/conf.sh.dist
Normal file
@@ -0,0 +1,57 @@
|
||||
# AzerothCore Run Engine Default Configuration
|
||||
# This file contains default values that can be overridden by environment variables
|
||||
# Priority order: conf.sh > environment variables > conf.sh.dist (this file)
|
||||
|
||||
# Enable/disable GDB execution
|
||||
export GDB_ENABLED="${RUN_ENGINE_GDB_ENABLED:-0}"
|
||||
|
||||
# [optional] GDB configuration file
|
||||
# default: gdb.conf
|
||||
export GDB="${RUN_ENGINE_GDB:-}"
|
||||
|
||||
# Directory where binaries are stored
|
||||
export BINPATH="${RUN_ENGINE_BINPATH:-}"
|
||||
|
||||
# Server binary name (e.g., worldserver, authserver)
|
||||
export SERVERBIN="${RUN_ENGINE_SERVERBIN:-}"
|
||||
|
||||
# Path to server configuration file (including the file name)
|
||||
# ex: /home/user/azerothcore/etc/worldserver.conf
|
||||
export CONFIG="${RUN_ENGINE_CONFIG:-}"
|
||||
|
||||
# Session manager to use: none|auto|tmux|screen
|
||||
# auto will detect the best available option
|
||||
export SESSION_MANAGER="${RUN_ENGINE_SESSION_MANAGER:-none}"
|
||||
|
||||
# Default session manager (fallback when SESSION_MANAGER is not set)
|
||||
export DEFAULT_SESSION_MANAGER="${RUN_ENGINE_DEFAULT_SESSION_MANAGER:-none}"
|
||||
|
||||
# Path of the crashes directory
|
||||
# If not specified, it will be created in the same directory as logs named "crashes"
|
||||
export CRASHES_PATH="${RUN_ENGINE_CRASHES_PATH:-}"
|
||||
|
||||
# Path of log files directory
|
||||
export LOGS_PATH="${RUN_ENGINE_LOGS_PATH:-}"
|
||||
|
||||
# Prefix name for log files to avoid collision with other instances
|
||||
export LOG_PREFIX_NAME="${RUN_ENGINE_LOG_PREFIX_NAME:-}"
|
||||
|
||||
# [optional] Name of session (tmux session or screen session)
|
||||
# If not specified, a default name will be generated based on server binary
|
||||
export SESSION_NAME="${RUN_ENGINE_SESSION_NAME:-}"
|
||||
|
||||
# [optional] Screen-specific options: -A -m -d -S
|
||||
# WARNING: if you are running it under a systemd service
|
||||
# please do not remove -m -d arguments from screen if you are using it,
|
||||
# or keep WITH_CONSOLE=0. Otherwise the journald-logging system will take
|
||||
# 100% of CPU slowing down the whole machine.
|
||||
export SCREEN_OPTIONS="${RUN_ENGINE_SCREEN_OPTIONS:-}"
|
||||
|
||||
# Enable/disable console output
|
||||
# If disabled, output will be redirected to logging files
|
||||
export WITH_CONSOLE="${RUN_ENGINE_WITH_CONSOLE:-0}"
|
||||
|
||||
# Restart policy (on-failure|always)
|
||||
export RESTART_POLICY="always"
|
||||
|
||||
|
||||
48
apps/startup-scripts/src/examples/restarter-auth.sh
Normal file
48
apps/startup-scripts/src/examples/restarter-auth.sh
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# AzerothCore Auth Server Restarter Example
|
||||
# This example shows how to use the run-engine with restart functionality for authserver
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
CONFIG_FILE="./conf-auth.sh"
|
||||
|
||||
# Method 1: Using configuration file (recommended)
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
echo "Starting authserver with restart loop using config file: $CONFIG_FILE"
|
||||
source "$CONFIG_FILE"
|
||||
"$PATH_RUNENGINE/run-engine" restart "$SERVERBIN" --config "$CONFIG_FILE"
|
||||
else
|
||||
echo "Error: Configuration file not found: $CONFIG_FILE"
|
||||
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
|
||||
echo "Make sure to set: export SERVERBIN=\"authserver\""
|
||||
echo ""
|
||||
echo "Alternative: Start with binary path directly"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine restart /path/to/bin/authserver"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine restart authserver # if in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Method 2: Direct binary path (full path)
|
||||
# Uncomment the line below to start with full binary path
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" restart /home/user/azerothcore/bin/authserver --server-config /path/to/authserver.conf
|
||||
|
||||
# Method 3: Binary name only (system PATH)
|
||||
# Uncomment the line below if authserver is in your system PATH
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" restart authserver --server-config /path/to/authserver.conf
|
||||
|
||||
# Method 4: With session manager (tmux/screen)
|
||||
# Uncomment the line below to use tmux session
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" restart authserver --session-manager tmux --server-config /path/to/authserver.conf
|
||||
|
||||
# Method 5: Environment variables only
|
||||
# Uncomment the lines below for environment variable configuration
|
||||
#
|
||||
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
|
||||
# export RUN_ENGINE_SERVERBIN="authserver"
|
||||
# export RUN_ENGINE_CONFIG="/path/to/authserver.conf"
|
||||
# "$PATH_RUNENGINE/run-engine" restart authserver
|
||||
|
||||
|
||||
47
apps/startup-scripts/src/examples/restarter-world.sh
Normal file
47
apps/startup-scripts/src/examples/restarter-world.sh
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# AzerothCore World Server Restarter Example
|
||||
# This example shows how to use the run-engine with restart functionality for worldserver
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
CONFIG_FILE="./conf-world.sh"
|
||||
|
||||
# Method 1: Using configuration file (recommended)
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
echo "Starting worldserver with restart loop using config file: $CONFIG_FILE"
|
||||
"$PATH_RUNENGINE/run-engine" restart "$SERVERBIN" --config "$CONFIG_FILE"
|
||||
else
|
||||
echo "Error: Configuration file not found: $CONFIG_FILE"
|
||||
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
|
||||
echo "Make sure to set: export SERVERBIN=\"worldserver\""
|
||||
echo ""
|
||||
echo "Alternative: Start with binary path directly"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine restart /path/to/bin/worldserver"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine restart worldserver # if in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Method 2: Direct binary path (full path)
|
||||
# Uncomment the line below to start with full binary path
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" restart /home/user/azerothcore/bin/worldserver --server-config /path/to/worldserver.conf
|
||||
|
||||
# Method 3: Binary name only (system PATH)
|
||||
# Uncomment the line below if worldserver is in your system PATH
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" restart worldserver --server-config /path/to/worldserver.conf
|
||||
|
||||
# Method 4: With session manager (tmux/screen)
|
||||
# Uncomment the line below to use tmux session
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" restart worldserver --session-manager tmux --server-config /path/to/worldserver.conf
|
||||
|
||||
# Method 5: Environment variables only
|
||||
# Uncomment the lines below for environment variable configuration
|
||||
#
|
||||
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
|
||||
# export RUN_ENGINE_SERVERBIN="worldserver"
|
||||
# export RUN_ENGINE_CONFIG="/path/to/worldserver.conf"
|
||||
# "$PATH_RUNENGINE/run-engine" restart worldserver
|
||||
|
||||
|
||||
46
apps/startup-scripts/src/examples/starter-auth.sh
Normal file
46
apps/startup-scripts/src/examples/starter-auth.sh
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# AzerothCore Auth Server Starter Example
|
||||
# This example shows how to use the run-engine to start authserver without restart loop
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
CONFIG_FILE="./conf-auth.sh"
|
||||
|
||||
# Method 1: Using configuration file (recommended)
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
echo "Starting authserver (single run) with config file: $CONFIG_FILE"
|
||||
"$PATH_RUNENGINE/run-engine" start "$SERVERBIN" --config "$CONFIG_FILE"
|
||||
else
|
||||
echo "Error: Configuration file not found: $CONFIG_FILE"
|
||||
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
|
||||
echo "Make sure to set: export SERVERBIN=\"authserver\""
|
||||
echo ""
|
||||
echo "Alternative: Start with binary path directly"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine start /path/to/bin/authserver"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine start authserver # if in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Method 2: Direct binary path (full path)
|
||||
# Uncomment the line below to start with full binary path
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" start /home/user/azerothcore/bin/authserver --server-config /path/to/authserver.conf
|
||||
|
||||
# Method 3: Binary name only (system PATH)
|
||||
# Uncomment the line below if authserver is in your system PATH
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" start authserver --server-config /path/to/authserver.conf
|
||||
|
||||
# Method 4: With session manager (tmux/screen)
|
||||
# Uncomment the line below to use tmux session
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" start authserver --session-manager tmux --server-config /path/to/authserver.conf
|
||||
|
||||
# Method 5: Environment variables only
|
||||
# Uncomment the lines below for environment variable configuration
|
||||
#
|
||||
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
|
||||
# export RUN_ENGINE_SERVERBIN="authserver"
|
||||
# export RUN_ENGINE_CONFIG="/path/to/authserver.conf"
|
||||
# "$PATH_RUNENGINE/run-engine" start authserver
|
||||
|
||||
47
apps/startup-scripts/src/examples/starter-world.sh
Normal file
47
apps/startup-scripts/src/examples/starter-world.sh
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# AzerothCore World Server Starter Example
|
||||
# This example shows how to use the run-engine to start worldserver without restart loop
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
CONFIG_FILE="./conf-world.sh"
|
||||
|
||||
# Method 1: Using configuration file (recommended)
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
echo "Starting worldserver (single run) with config file: $CONFIG_FILE"
|
||||
"$PATH_RUNENGINE/run-engine" start "$SERVERBIN" --config "$CONFIG_FILE"
|
||||
else
|
||||
echo "Error: Configuration file not found: $CONFIG_FILE"
|
||||
echo "Please create $CONFIG_FILE by copying and modifying conf.sh.dist"
|
||||
echo "Make sure to set: export SERVERBIN=\"worldserver\""
|
||||
echo ""
|
||||
echo "Alternative: Start with binary path directly"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine start /path/to/bin/worldserver"
|
||||
echo "Example: $PATH_RUNENGINE/run-engine start worldserver # if in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Method 2: Direct binary path (full path)
|
||||
# Uncomment the line below to start with full binary path
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" start /home/user/azerothcore/bin/worldserver --server-config /path/to/worldserver.conf
|
||||
|
||||
# Method 3: Binary name only (system PATH)
|
||||
# Uncomment the line below if worldserver is in your system PATH
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" start worldserver --server-config /path/to/worldserver.conf
|
||||
|
||||
# Method 4: With session manager (tmux/screen)
|
||||
# Uncomment the line below to use tmux session
|
||||
#
|
||||
# "$PATH_RUNENGINE/run-engine" start worldserver --session-manager tmux --server-config /path/to/worldserver.conf
|
||||
|
||||
# Method 5: Environment variables only
|
||||
# Uncomment the lines below for environment variable configuration
|
||||
#
|
||||
# export RUN_ENGINE_BINPATH="/path/to/your/bin"
|
||||
# export RUN_ENGINE_SERVERBIN="worldserver"
|
||||
# export RUN_ENGINE_CONFIG="/path/to/worldserver.conf"
|
||||
# "$PATH_RUNENGINE/run-engine" start worldserver
|
||||
|
||||
|
||||
144
apps/startup-scripts/src/migrate-registry.sh
Normal file
144
apps/startup-scripts/src/migrate-registry.sh
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# One-time migration script for service registry
|
||||
# Converts old format to new format
|
||||
|
||||
set -euo pipefail # Strict error handling
|
||||
|
||||
CONFIG_DIR="${AC_SERVICE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/azerothcore/services}"
|
||||
REGISTRY_FILE="$CONFIG_DIR/service_registry.json"
|
||||
BACKUP_FILE="$CONFIG_DIR/service_registry.json.backup"
|
||||
|
||||
# Colors
|
||||
readonly YELLOW='\033[1;33m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly RED='\033[0;31m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly NC='\033[0m'
|
||||
|
||||
echo -e "${BLUE}AzerothCore Service Registry Migration Tool${NC}"
|
||||
echo "=============================================="
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo -e "${RED}Error: jq is required but not installed. Please install jq package.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create config directory if it doesn't exist
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
|
||||
# Check if registry exists
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
echo -e "${YELLOW}No registry file found. Nothing to migrate.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate JSON format
|
||||
if ! jq empty "$REGISTRY_FILE" >/dev/null 2>&1; then
|
||||
echo -e "${RED}Error: Registry file contains invalid JSON.${NC}"
|
||||
echo "Please check the file: $REGISTRY_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if it's already new format
|
||||
if jq -e 'type == "array" and (length == 0 or .[0] | has("bin_path"))' "$REGISTRY_FILE" >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}Registry is already in new format. No migration needed.${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if it's old format
|
||||
if ! jq -e 'type == "array" and (length == 0 or .[0] | has("config"))' "$REGISTRY_FILE" >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Registry format not recognized. Manual review needed.${NC}"
|
||||
echo "Current registry content:"
|
||||
cat "$REGISTRY_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Old format detected. Starting migration...${NC}"
|
||||
|
||||
# Create backup
|
||||
if ! cp "$REGISTRY_FILE" "$BACKUP_FILE"; then
|
||||
echo -e "${RED}Error: Failed to create backup file.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${BLUE}Backup created: $BACKUP_FILE${NC}"
|
||||
|
||||
# Convert to new format
|
||||
echo "[]" > "$REGISTRY_FILE.new"
|
||||
|
||||
services_migrated=0
|
||||
while IFS= read -r service; do
|
||||
if [ -n "$service" ] && [ "$service" != "null" ]; then
|
||||
name=$(echo "$service" | jq -r '.name // ""')
|
||||
provider=$(echo "$service" | jq -r '.provider // ""')
|
||||
type=$(echo "$service" | jq -r '.type // ""')
|
||||
config=$(echo "$service" | jq -r '.config // ""')
|
||||
|
||||
# Validate required fields
|
||||
if [ -z "$name" ] || [ -z "$provider" ] || [ -z "$type" ]; then
|
||||
echo -e "${YELLOW}Skipping invalid service entry: $service${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Migrating service: $name${NC}"
|
||||
|
||||
# Create new format entry with all required fields
|
||||
new_entry=$(jq -n \
|
||||
--arg name "$name" \
|
||||
--arg provider "$provider" \
|
||||
--arg type "$type" \
|
||||
--arg bin_path "unknown" \
|
||||
--arg args "" \
|
||||
--arg created "$(date -Iseconds)" \
|
||||
--arg status "migrated" \
|
||||
--arg systemd_type "--user" \
|
||||
--arg restart_policy "always" \
|
||||
--arg session_manager "none" \
|
||||
--arg gdb_enabled "0" \
|
||||
--arg pm2_opts "" \
|
||||
--arg server_config "" \
|
||||
--arg legacy_config "$config" \
|
||||
'{
|
||||
name: $name,
|
||||
provider: $provider,
|
||||
type: $type,
|
||||
bin_path: $bin_path,
|
||||
args: $args,
|
||||
created: $created,
|
||||
status: $status,
|
||||
systemd_type: $systemd_type,
|
||||
restart_policy: $restart_policy,
|
||||
session_manager: $session_manager,
|
||||
gdb_enabled: $gdb_enabled,
|
||||
pm2_opts: $pm2_opts,
|
||||
server_config: $server_config,
|
||||
legacy_config: $legacy_config
|
||||
}')
|
||||
|
||||
# Add to new registry with error checking
|
||||
if ! jq --argjson entry "$new_entry" '. += [$entry]' "$REGISTRY_FILE.new" > "$REGISTRY_FILE.new.tmp"; then
|
||||
echo -e "${RED}Error: Failed to add service $name to new registry${NC}"
|
||||
rm -f "$REGISTRY_FILE.new" "$REGISTRY_FILE.new.tmp"
|
||||
exit 1
|
||||
fi
|
||||
mv "$REGISTRY_FILE.new.tmp" "$REGISTRY_FILE.new"
|
||||
|
||||
services_migrated=$((services_migrated + 1))
|
||||
fi
|
||||
done < <(jq -c '.[]?' "$BACKUP_FILE" 2>/dev/null || echo "")
|
||||
|
||||
# Replace old registry with new one
|
||||
if ! mv "$REGISTRY_FILE.new" "$REGISTRY_FILE"; then
|
||||
echo -e "${RED}Error: Failed to replace old registry with new one${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Migration completed successfully!${NC}"
|
||||
echo -e "${BLUE}Services migrated: $services_migrated${NC}"
|
||||
echo -e "${BLUE}Use 'service-manager.sh restore' to review and update services.${NC}"
|
||||
echo -e "${YELLOW}Note: Migrated services have bin_path='unknown' and need manual recreation.${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}To recreate services, use commands like:${NC}"
|
||||
echo " ./service-manager.sh create auth authserver --provider pm2 --bin-path /path/to/your/bin"
|
||||
echo " ./service-manager.sh create world worldserver --provider systemd --bin-path /path/to/your/bin"
|
||||
483
apps/startup-scripts/src/run-engine
Normal file
483
apps/startup-scripts/src/run-engine
Normal file
@@ -0,0 +1,483 @@
|
||||
#!/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:-$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"}"
|
||||
CRASHES_PATH="${CRASHES_PATH:-"$BINPATH/crashes"}"
|
||||
mkdir -p "$LOGS_PATH"
|
||||
mkdir -p "$CRASHES_PATH"
|
||||
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"}"
|
||||
CRASHES_PATH="${CRASHES_PATH:-"$detected_binpath/crashes"}"
|
||||
else
|
||||
# Fallback to current directory for logs
|
||||
LOGS_PATH="${LOGS_PATH:-./logs}"
|
||||
CRASHES_PATH="${CRASHES_PATH:-"$./crashes"}"
|
||||
fi
|
||||
|
||||
|
||||
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
|
||||
|
||||
# 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}"
|
||||
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
|
||||
|
||||
1979
apps/startup-scripts/src/service-manager.sh
Normal file
1979
apps/startup-scripts/src/service-manager.sh
Normal file
File diff suppressed because it is too large
Load Diff
93
apps/startup-scripts/src/simple-restarter
Normal file
93
apps/startup-scripts/src/simple-restarter
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# AzerothCore Simple Restarter
|
||||
# This script is a wrapper around the starter script that provides restart functionality
|
||||
# and maintains compatibility with the acore dashboard
|
||||
#
|
||||
# Usage: simple-restarter <binary> [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]
|
||||
#
|
||||
# Parameters (same as starter):
|
||||
# $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)
|
||||
|
||||
# Get script directory
|
||||
CURRENT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Parameters (same as starter)
|
||||
BINPATH="$1"
|
||||
BINFILE="$2"
|
||||
GDB_FILE="$3"
|
||||
CONFIG="$4"
|
||||
SYSLOG="$5"
|
||||
SYSERR="$6"
|
||||
GDB_ENABLED="${7:-0}"
|
||||
CRASHES_PATH="$8"
|
||||
|
||||
BINARY="$BINPATH/$BINFILE"
|
||||
|
||||
# Default values (same as starter)
|
||||
DEFAULT_GDB_FILE="$CURRENT_PATH/gdb.conf"
|
||||
|
||||
# Set defaults if not provided
|
||||
GDB_FILE="${GDB_FILE:-$DEFAULT_GDB_FILE}"
|
||||
|
||||
# Counters for crash detection
|
||||
_instant_crash_count=0
|
||||
_restart_count=0
|
||||
|
||||
# Check if starter script exists
|
||||
STARTER_SCRIPT="$CURRENT_PATH/starter"
|
||||
if [ ! -f "$STARTER_SCRIPT" ]; then
|
||||
echo "Error: starter script not found at $STARTER_SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Main restart loop
|
||||
while true; do
|
||||
STARTING_TIME=$(date +%s)
|
||||
|
||||
# Use starter script to launch the binary with all parameters
|
||||
"$STARTER_SCRIPT" "$BINPATH" "$BINFILE" "$GDB_FILE" "$CONFIG" "$SYSLOG" "$SYSERR" "$GDB_ENABLED" "$CRASHES_PATH"
|
||||
|
||||
_exit_code=$?
|
||||
|
||||
echo "$(basename "$BINARY") terminated with exit code: $_exit_code"
|
||||
|
||||
# Calculate runtime
|
||||
ENDING_TIME=$(date +%s)
|
||||
DIFFERENCE=$((ENDING_TIME - STARTING_TIME))
|
||||
|
||||
((_restart_count++))
|
||||
echo "$(basename "$BINARY") terminated after $DIFFERENCE seconds, restart count: $_restart_count"
|
||||
|
||||
# Crash loop detection
|
||||
if [ "$DIFFERENCE" -lt 10 ]; then
|
||||
# Increment instant crash count if runtime is lower than 10 seconds
|
||||
((_instant_crash_count++))
|
||||
echo "Warning: Quick restart detected ($DIFFERENCE seconds) - instant crash count: $_instant_crash_count"
|
||||
else
|
||||
# Reset count on successful longer run
|
||||
_instant_crash_count=0
|
||||
fi
|
||||
|
||||
# Prevent infinite crash loops
|
||||
if [ "$_instant_crash_count" -gt 5 ]; then
|
||||
echo "Error: $(basename "$BINARY") restarter exited. Infinite crash loop prevented (6 crashes in under 10 seconds each)"
|
||||
echo "Please check your system configuration and logs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Exit cleanly if shutdown was requested by command or SIGINT (exit code 0)
|
||||
if [ "$_exit_code" -eq 0 ]; then
|
||||
echo "$(basename "$BINARY") shutdown safely"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "$(basename "$BINARY") will restart in 3 seconds..."
|
||||
sleep 3
|
||||
done
|
||||
151
apps/startup-scripts/src/starter
Normal file
151
apps/startup-scripts/src/starter
Normal file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# AzerothCore Starter Script
|
||||
# This script handles the execution of AzerothCore binaries with optional GDB support
|
||||
#
|
||||
# Usage: starter <binpath> <binfile> [gdb_file] [config] [syslog] [syserr] [gdb_enabled] [crashes_path]
|
||||
#
|
||||
# Parameters:
|
||||
# $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"
|
||||
GDB_FILE="$3"
|
||||
CONFIG="$4"
|
||||
SYSLOG="$5"
|
||||
SYSERR="$6"
|
||||
GDB_ENABLED="${7:-0}"
|
||||
CRASHES_PATH="$8"
|
||||
|
||||
# Default values
|
||||
CURRENT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEFAULT_CRASHES_PATH=$(realpath "$BINPATH/crashes")
|
||||
[ -n "$CONFIG" ] && CONFIG_ABS=$(realpath "$CONFIG")
|
||||
|
||||
# Set defaults if not provided
|
||||
CRASHES_PATH="${CRASHES_PATH:-$DEFAULT_CRASHES_PATH}"
|
||||
|
||||
# Validate binary
|
||||
if [ -z "$BINPATH" ] || [ -z "$BINFILE" ]; then
|
||||
echo "Error: Binary path and file are required"
|
||||
echo "Usage: $0 <binpath> <binfile> [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
|
||||
fi
|
||||
|
||||
# Create crashes directory if it doesn't exist
|
||||
mkdir -p "$CRASHES_PATH"
|
||||
|
||||
cd "$BINPATH" || {
|
||||
echo "Error: Could not change to binary path '$BINPATH'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
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 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_ABS" ]; then
|
||||
echo "run -c $CONFIG_ABS" >> "$GDB_TEMP_FILE"
|
||||
else
|
||||
echo "run" >> "$GDB_TEMP_FILE"
|
||||
fi
|
||||
|
||||
cat >> "$GDB_TEMP_FILE" << EOF
|
||||
bt
|
||||
bt full
|
||||
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_FILE" --batch "$EXECPATH" >> "$SYSLOG" 2>> "$SYSERR"
|
||||
else
|
||||
echo "> Console enabled"
|
||||
if [ -n "$SYSLOG" ] && [ -n "$SYSERR" ]; then
|
||||
gdb -x "$GDB_FILE" --batch "$EXECPATH" > >(tee "$SYSLOG") 2> >(tee "$SYSERR" >&2)
|
||||
else
|
||||
gdb -x "$GDB_FILE" --batch "$EXECPATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
echo "Starting $BINFILE without GDB"
|
||||
# Determine if PM2 is active
|
||||
is_pm2_active="0"
|
||||
[ "$AC_LAUNCHED_BY_PM2" == "1" ] && is_pm2_active="1"
|
||||
|
||||
# Determine if interactive mode is enabled
|
||||
is_interactive_enabled="1"
|
||||
[ "$AC_DISABLE_INTERACTIVE" == "1" ] && is_interactive_enabled="0"
|
||||
|
||||
# use normal execution if we are running the binary under PM2
|
||||
# or when interactive mode is enabled
|
||||
if [[ "$is_pm2_active" == "1" || "$is_interactive_enabled" == "1" ]]; then
|
||||
echo "Running AC"
|
||||
"$EXECPATH" ${CONFIG_ABS:+-c "$CONFIG_ABS"}
|
||||
else
|
||||
# When AC_DISABLE_INTERACTIVE is set to 1 and we are not in PM2
|
||||
# This means we are using systemd without interactive mode and no session managers
|
||||
# in this case we need to run AC with unbuffer for line-buffered output
|
||||
# NOTE unbuffer doesn't fully support interactive mode
|
||||
if command -v unbuffer >/dev/null 2>&1; then
|
||||
echo "Running AC with unbuffer for line-buffered output"
|
||||
unbuffer "$EXECPATH" ${CONFIG_ABS:+-c "$CONFIG_ABS"}
|
||||
else
|
||||
echo "⚠️ unbuffer not found, the output may not be line-buffered. Try installing expect."
|
||||
exec "$EXECPATH" ${CONFIG_ABS:+-c "$CONFIG_ABS"}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
14
apps/startup-scripts/test/bats.conf
Normal file
14
apps/startup-scripts/test/bats.conf
Normal file
@@ -0,0 +1,14 @@
|
||||
# BATS Test Configuration
|
||||
|
||||
# Set test timeout (in seconds)
|
||||
export BATS_TEST_TIMEOUT=30
|
||||
|
||||
# Enable verbose output for debugging
|
||||
export BATS_VERBOSE_RUN=1
|
||||
|
||||
# Test output format
|
||||
export BATS_FORMATTER=pretty
|
||||
|
||||
# Enable colored output
|
||||
export BATS_NO_PARALLELIZE_ACROSS_FILES=1
|
||||
export BATS_NO_PARALLELIZE_WITHIN_FILE=1
|
||||
305
apps/startup-scripts/test/test_startup_scripts.bats
Normal file
305
apps/startup-scripts/test/test_startup_scripts.bats
Normal file
@@ -0,0 +1,305 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
# AzerothCore Startup Scripts Test Suite
|
||||
# This script tests the basic functionality of the startup scripts using the unified test framework
|
||||
|
||||
# Load the AzerothCore test framework
|
||||
load '../../test-framework/bats_libs/acore-support'
|
||||
load '../../test-framework/bats_libs/acore-assert'
|
||||
|
||||
# Setup that runs before each test
|
||||
setup() {
|
||||
startup_scripts_setup
|
||||
export SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/../src" && pwd)"
|
||||
}
|
||||
|
||||
# Cleanup that runs after each test
|
||||
teardown() {
|
||||
acore_test_teardown
|
||||
}
|
||||
|
||||
# ===== STARTER SCRIPT TESTS =====
|
||||
|
||||
@test "starter: should fail with missing parameters" {
|
||||
run timeout 3s "$SCRIPT_DIR/starter" '' ''
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" =~ "Error: Binary path and file are required" ]]
|
||||
}
|
||||
|
||||
@test "starter: should start with valid binary" {
|
||||
cd "$TEST_DIR"
|
||||
run timeout 5s "$SCRIPT_DIR/starter" "$TEST_DIR/bin" "test-server" "" "$TEST_DIR/test-server.conf" "" "" 0
|
||||
debug_on_failure
|
||||
# The starter might have issues with the script command, so we check for specific behavior
|
||||
# Either it should succeed or show a specific error we can work with
|
||||
[[ "$output" =~ "Test server starting" ]] || [[ "$output" =~ "script:" ]] || [[ "$status" -eq 124 ]]
|
||||
}
|
||||
|
||||
@test "starter: should validate binary path exists" {
|
||||
run "$SCRIPT_DIR/starter" "/nonexistent/path" "test-server"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$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 =====
|
||||
|
||||
@test "simple-restarter: should fail with missing parameters" {
|
||||
run timeout 3s "$SCRIPT_DIR/simple-restarter" '' ''
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" =~ "Error: Binary path and file are required" ]]
|
||||
}
|
||||
|
||||
@test "simple-restarter: should fail with missing binary" {
|
||||
run timeout 3s "$SCRIPT_DIR/simple-restarter" "$TEST_DIR/bin" 'nonexistent'
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" =~ "not found" ]] || [[ "$output" =~ "terminated with exit code" ]]
|
||||
}
|
||||
|
||||
@test "simple-restarter: should detect starter script" {
|
||||
# Test that it finds the starter script
|
||||
run timeout 1s "$SCRIPT_DIR/simple-restarter" '' ''
|
||||
# Should not fail because starter script is missing
|
||||
[[ ! "$output" =~ "starter script not found" ]]
|
||||
}
|
||||
|
||||
# ===== RUN-ENGINE TESTS =====
|
||||
|
||||
@test "run-engine: should show help" {
|
||||
run "$SCRIPT_DIR/run-engine" help
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "AzerothCore Run Engine" ]]
|
||||
}
|
||||
|
||||
@test "run-engine: should validate parameters for start command" {
|
||||
run "$SCRIPT_DIR/run-engine" start
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" =~ "Missing required arguments" ]]
|
||||
}
|
||||
|
||||
@test "run-engine: should detect binary with full path" {
|
||||
run timeout 5s "$SCRIPT_DIR/run-engine" start "$TEST_DIR/bin/test-server" --server-config "$TEST_DIR/test-server.conf"
|
||||
debug_on_failure
|
||||
[[ "$output" =~ "Starting server: test-server" ]] || [[ "$status" -eq 124 ]]
|
||||
}
|
||||
|
||||
@test "run-engine: should detect binary in current directory" {
|
||||
cd "$TEST_DIR/bin"
|
||||
run timeout 5s "$SCRIPT_DIR/run-engine" start test-server --server-config "$TEST_DIR/test-server.conf"
|
||||
debug_on_failure
|
||||
[[ "$output" =~ "Binary found in current directory" ]] || [[ "$output" =~ "Starting server: test-server" ]] || [[ "$status" -eq 124 ]]
|
||||
}
|
||||
|
||||
@test "run-engine: should support restart mode" {
|
||||
run timeout 5s "$SCRIPT_DIR/run-engine" restart "$TEST_DIR/bin/test-server" --server-config "$TEST_DIR/test-server.conf"
|
||||
debug_on_failure
|
||||
[[ "$output" =~ "Starting server: test-server" ]] || [[ "$status" -eq 124 ]]
|
||||
}
|
||||
|
||||
# ===== SERVICE MANAGER TESTS =====
|
||||
|
||||
@test "service-manager: should show help" {
|
||||
run "$SCRIPT_DIR/service-manager.sh" help
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "AzerothCore Service Setup" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: should validate create command parameters" {
|
||||
run "$SCRIPT_DIR/service-manager.sh" create
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" =~ "Missing required arguments" ]] || [[ "$output" =~ "Error:" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: should validate restart policy values" {
|
||||
run "$SCRIPT_DIR/service-manager.sh" create auth test-auth --bin-path /nonexistent --restart-policy invalid
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" =~ "Invalid restart policy" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: should accept valid restart policy values" {
|
||||
# Test on-failure (should be accepted)
|
||||
run "$SCRIPT_DIR/service-manager.sh" create auth test-auth --bin-path /nonexistent --restart-policy on-failure
|
||||
# Should fail due to missing binary, not restart policy validation
|
||||
[[ ! "$output" =~ "Invalid restart policy" ]]
|
||||
|
||||
# Test always (should be accepted)
|
||||
run "$SCRIPT_DIR/service-manager.sh" create auth test-auth2 --bin-path /nonexistent --restart-policy always
|
||||
# Should fail due to missing binary, not restart policy validation
|
||||
[[ ! "$output" =~ "Invalid restart policy" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: should include restart policy in help output" {
|
||||
run "$SCRIPT_DIR/service-manager.sh" help
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "--restart-policy" ]]
|
||||
[[ "$output" =~ "on-failure|always" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: help lists health and console commands" {
|
||||
run "$SCRIPT_DIR/service-manager.sh" help
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "is-running <service-name>" ]]
|
||||
[[ "$output" =~ "uptime-seconds <service-name>" ]]
|
||||
[[ "$output" =~ "wait-uptime <service> <sec>" ]]
|
||||
[[ "$output" =~ "send <service-name>" ]]
|
||||
[[ "$output" =~ "show-config <service-name>" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: pm2 uptime and wait-uptime work with mocked pm2" {
|
||||
command -v jq >/dev/null 2>&1 || skip "jq not installed"
|
||||
export AC_SERVICE_CONFIG_DIR="$TEST_DIR/services"
|
||||
mkdir -p "$AC_SERVICE_CONFIG_DIR"
|
||||
# Create registry with pm2 provider service
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/service_registry.json" << 'EOF'
|
||||
[
|
||||
{"name":"test-world","provider":"pm2","type":"service","bin_path":"/bin/worldserver","args":"","systemd_type":"--user","restart_policy":"always"}
|
||||
]
|
||||
EOF
|
||||
# Create minimal service config and run-engine config files required by 'send'
|
||||
echo "RUN_ENGINE_CONFIG_FILE=\"$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf\"" > "$AC_SERVICE_CONFIG_DIR/test-world.conf"
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf" << 'EOF'
|
||||
export SESSION_MANAGER="none"
|
||||
export SESSION_NAME="test-world"
|
||||
EOF
|
||||
# Mock pm2
|
||||
cat > "$TEST_DIR/bin/pm2" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
case "$1" in
|
||||
jlist)
|
||||
# Produce a JSON with uptime ~20 seconds
|
||||
if date +%s%N >/dev/null 2>&1; then
|
||||
nowms=$(( $(date +%s%N) / 1000000 ))
|
||||
else
|
||||
nowms=$(( $(date +%s) * 1000 ))
|
||||
fi
|
||||
up=$(( nowms - 20000 ))
|
||||
echo "[{\"name\":\"test-world\",\"pm2_env\":{\"status\":\"online\",\"pm_uptime\":$up}}]"
|
||||
;;
|
||||
id)
|
||||
echo "[1]"
|
||||
;;
|
||||
attach|send|list|describe|logs)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$TEST_DIR/bin/pm2"
|
||||
|
||||
run "$SCRIPT_DIR/service-manager.sh" uptime-seconds test-world
|
||||
debug_on_failure
|
||||
[ "$status" -eq 0 ]
|
||||
# Output should be a number >= 10
|
||||
[[ "$output" =~ ^[0-9]+$ ]]
|
||||
[ "$output" -ge 10 ]
|
||||
|
||||
run "$SCRIPT_DIR/service-manager.sh" wait-uptime test-world 10 5
|
||||
debug_on_failure
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "service-manager: send works under pm2 with mocked pm2" {
|
||||
command -v jq >/dev/null 2>&1 || skip "jq not installed"
|
||||
export AC_SERVICE_CONFIG_DIR="$TEST_DIR/services"
|
||||
mkdir -p "$AC_SERVICE_CONFIG_DIR"
|
||||
# Create registry and config as in previous test
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/service_registry.json" << 'EOF'
|
||||
[
|
||||
{"name":"test-world","provider":"pm2","type":"service","bin_path":"/bin/worldserver","args":"","systemd_type":"--user","restart_policy":"always"}
|
||||
]
|
||||
EOF
|
||||
echo "RUN_ENGINE_CONFIG_FILE=\"$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf\"" > "$AC_SERVICE_CONFIG_DIR/test-world.conf"
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf" << 'EOF'
|
||||
export SESSION_MANAGER="none"
|
||||
export SESSION_NAME="test-world"
|
||||
EOF
|
||||
# pm2 mock
|
||||
cat > "$TEST_DIR/bin/pm2" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
case "$1" in
|
||||
jlist)
|
||||
if date +%s%N >/dev/null 2>&1; then
|
||||
nowms=$(( $(date +%s%N) / 1000000 ))
|
||||
else
|
||||
nowms=$(( $(date +%s) * 1000 ))
|
||||
fi
|
||||
up=$(( nowms - 15000 ))
|
||||
echo "[{\"name\":\"test-world\",\"pm2_env\":{\"status\":\"online\",\"pm_uptime\":$up}}]"
|
||||
;;
|
||||
id)
|
||||
echo "[1]"
|
||||
;;
|
||||
send)
|
||||
# simulate success
|
||||
exit 0
|
||||
;;
|
||||
attach|list|describe|logs)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$TEST_DIR/bin/pm2"
|
||||
|
||||
run "$SCRIPT_DIR/service-manager.sh" send test-world "server info"
|
||||
debug_on_failure
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "service-manager: wait-uptime times out for unknown service" {
|
||||
command -v jq >/dev/null 2>&1 || skip "jq not installed"
|
||||
export AC_SERVICE_CONFIG_DIR="$TEST_DIR/services"
|
||||
mkdir -p "$AC_SERVICE_CONFIG_DIR"
|
||||
echo "[]" > "$AC_SERVICE_CONFIG_DIR/service_registry.json"
|
||||
run "$SCRIPT_DIR/service-manager.sh" wait-uptime unknown 2 1
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
# ===== EXAMPLE SCRIPTS TESTS =====
|
||||
|
||||
@test "examples: restarter-world should show configuration error" {
|
||||
run "$SCRIPT_DIR/examples/restarter-world.sh"
|
||||
[[ "$output" =~ "Configuration file not found" ]]
|
||||
}
|
||||
|
||||
@test "examples: starter-auth should show configuration error" {
|
||||
run "$SCRIPT_DIR/examples/starter-auth.sh"
|
||||
[[ "$output" =~ "Configuration file not found" ]]
|
||||
}
|
||||
|
||||
@test "examples: restarter-auth should show configuration error" {
|
||||
run "$SCRIPT_DIR/examples/restarter-auth.sh"
|
||||
[[ "$output" =~ "Configuration file not found" ]]
|
||||
}
|
||||
|
||||
@test "examples: restarter-world should show alternative suggestions" {
|
||||
run "$SCRIPT_DIR/examples/restarter-world.sh"
|
||||
[[ "$output" =~ "Alternative: Start with binary path directly" ]]
|
||||
}
|
||||
|
||||
# ===== INTEGRATION TESTS =====
|
||||
|
||||
@test "integration: starter and simple-restarter work together" {
|
||||
# Test that simple-restarter can use starter
|
||||
run timeout 5s "$SCRIPT_DIR/simple-restarter" "$TEST_DIR/bin" "test-server"
|
||||
# Should start and then restart at least once
|
||||
[[ "$output" =~ "terminated with exit code" ]] || [[ "$status" -eq 124 ]]
|
||||
}
|
||||
|
||||
@test "integration: run-engine can handle missing config gracefully" {
|
||||
run timeout 3s "$SCRIPT_DIR/run-engine" start "$TEST_DIR/bin/test-server"
|
||||
# Should either work or give a meaningful error
|
||||
[[ "$status" -eq 124 ]] || [[ "$status" -eq 0 ]] || [[ "$output" =~ "config" ]]
|
||||
}
|
||||
Reference in New Issue
Block a user