Merge pull request #7 from azerothcore/master

Merge
This commit is contained in:
kadeshar
2025-08-27 21:04:10 +02:00
committed by GitHub
79 changed files with 2648 additions and 291 deletions

View File

@@ -100,7 +100,8 @@ git clone --depth=1 --branch=main https://github.com/azerothcore/mod-system-vi
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-tic-tac-toe modules/mod-tic-tac-toe
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-top-arena modules/mod-top-arena
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-transmog modules/mod-transmog
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-war-effort modules/mod-war-effort
# archived / outdated
#git clone --depth=1 --branch=master https://github.com/azerothcore/mod-war-effort modules/mod-war-effort
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-weekend-xp modules/mod-weekend-xp
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-who-logged modules/mod-who-logged
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-zone-difficulty modules/mod-zone-difficulty

View File

@@ -312,6 +312,9 @@ Services support two restart policies:
# Edit configuration
./service-manager.sh edit world
# Restore missing services from registry
./service-manager.sh restore
```
## 🌍 Multiple Realms Setup
@@ -384,22 +387,72 @@ cp examples/restarter-world.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:
```bash
# PM2-specific commands
pm2 list # List all PM2 processes
pm2 logs auth # View logs
pm2 monit # Real-time monitoring
pm2 restart auth # Restart service
pm2 delete auth # Remove service
* [PM2 CLI Documentation](https://pm2.io/docs/runtime/reference/pm2-cli/)
# Save PM2 configuration
pm2 save
pm2 startup # Auto-start on boot
```
**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.
@@ -407,6 +460,12 @@ NOTE: pm2 cannot run tmux/screen sessions, but you can always use the `attach` c
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)
@@ -551,4 +610,18 @@ npm install -g pm2
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
```

View 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"

View File

@@ -4,6 +4,8 @@
# A unified interface for managing AzerothCore services with PM2 or systemd
# This script provides commands to create, update, delete, and manage server instances
set -euo pipefail # Strict error handling
# Script location
CURRENT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -11,16 +13,16 @@ SCRIPT_DIR="$CURRENT_PATH"
ROOT_DIR="$(cd "$CURRENT_PATH/../../.." && pwd)"
# Configuration directory
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/azerothcore/services"
# Configuration directory (can be overridden with AC_SERVICE_CONFIG_DIR)
CONFIG_DIR="${AC_SERVICE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/azerothcore/services}"
REGISTRY_FILE="$CONFIG_DIR/service_registry.json"
# Colors for output
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
readonly YELLOW='\033[1;33m'
readonly GREEN='\033[0;32m'
readonly RED='\033[0;31m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m' # No Color
# Create config directory if it doesn't exist
mkdir -p "$CONFIG_DIR"
@@ -38,6 +40,198 @@ check_dependencies() {
}
}
# Registry management functions
function add_service_to_registry() {
local service_name="$1"
local provider="$2"
local service_type="$3"
local bin_path="$4"
local args="$5"
local systemd_type="$6"
local restart_policy="$7"
local session_manager="$8"
local gdb_enabled="$9"
local pm2_opts="${10}"
local server_config="${11}"
# Remove any existing entry with the same service name to avoid duplicates
local tmp_file
tmp_file=$(mktemp)
jq --arg name "$service_name" 'map(select(.name != $name))' "$REGISTRY_FILE" > "$tmp_file" && mv "$tmp_file" "$REGISTRY_FILE"
# Add the new entry to the registry
tmp_file=$(mktemp)
jq --arg name "$service_name" \
--arg provider "$provider" \
--arg type "$service_type" \
--arg bin_path "$bin_path" \
--arg args "$args" \
--arg created "$(date -Iseconds)" \
--arg systemd_type "$systemd_type" \
--arg restart_policy "$restart_policy" \
--arg session_manager "$session_manager" \
--arg gdb_enabled "$gdb_enabled" \
--arg pm2_opts "$pm2_opts" \
--arg server_config "$server_config" \
'. += [{"name": $name, "provider": $provider, "type": $type, "bin_path": $bin_path, "args": $args, "created": $created, "status": "active", "systemd_type": $systemd_type, "restart_policy": $restart_policy, "session_manager": $session_manager, "gdb_enabled": $gdb_enabled, "pm2_opts": $pm2_opts, "server_config": $server_config}]' \
"$REGISTRY_FILE" > "$tmp_file" && mv "$tmp_file" "$REGISTRY_FILE"
echo -e "${GREEN}Service '$service_name' added to registry${NC}"
}
function remove_service_from_registry() {
local service_name="$1"
if [ -f "$REGISTRY_FILE" ]; then
local tmp_file
tmp_file=$(mktemp)
jq --arg name "$service_name" \
'map(select(.name != $name))' \
"$REGISTRY_FILE" > "$tmp_file" && mv "$tmp_file" "$REGISTRY_FILE"
echo -e "${GREEN}Service '$service_name' removed from registry${NC}"
fi
}
function restore_missing_services() {
echo -e "${BLUE}Checking for missing services...${NC}"
if [ ! -f "$REGISTRY_FILE" ] || [ ! -s "$REGISTRY_FILE" ]; then
echo -e "${YELLOW}No services registry found or empty${NC}"
return 0
fi
local missing_services=()
local services_count
services_count=$(jq length "$REGISTRY_FILE")
if [ "$services_count" -eq 0 ]; then
echo -e "${YELLOW}No services registered${NC}"
return 0
fi
echo -e "${BLUE}Found $services_count registered services. Checking status...${NC}"
# Check each service
for i in $(seq 0 $((services_count-1))); do
local service=$(jq -r ".[$i]" "$REGISTRY_FILE")
local name=$(echo "$service" | jq -r '.name')
local provider=$(echo "$service" | jq -r '.provider')
local service_type=$(echo "$service" | jq -r '.type')
local bin_path=$(echo "$service" | jq -r '.bin_path // "unknown"')
local args=$(echo "$service" | jq -r '.args // ""')
local status=$(echo "$service" | jq -r '.status // "active"')
local systemd_type=$(echo "$service" | jq -r '.systemd_type // "--user"')
local restart_policy=$(echo "$service" | jq -r '.restart_policy // "always"')
local session_manager=$(echo "$service" | jq -r '.session_manager // "none"')
local gdb_enabled=$(echo "$service" | jq -r '.gdb_enabled // "0"')
local pm2_opts=$(echo "$service" | jq -r '.pm2_opts // ""')
local server_config=$(echo "$service" | jq -r '.server_config // ""')
local service_exists=false
if [ "$provider" = "pm2" ]; then
if pm2 describe "$name" >/dev/null 2>&1; then
service_exists=true
fi
elif [ "$provider" = "systemd" ]; then
local user_unit="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/$name.service"
local system_unit="/etc/systemd/system/$name.service"
if [ -f "$user_unit" ] || [ -f "$system_unit" ]; then
# Unit file present, you can also check if it is active
service_exists=true
else
# Unit file missing: service needs to be recreated!
service_exists=false
fi
fi
if [ "$service_exists" = false ]; then
missing_services+=("$i")
echo -e "${YELLOW}Missing service: $name ($provider)${NC}"
else
echo -e "${GREEN}✓ Service $name ($provider) exists${NC}"
fi
done
# Handle missing services
if [ ${#missing_services[@]} -eq 0 ]; then
echo -e "${GREEN}All registered services are present${NC}"
return 0
fi
echo -e "${YELLOW}Found ${#missing_services[@]} missing services${NC}"
for index in "${missing_services[@]}"; do
local service=$(jq -r ".[$index]" "$REGISTRY_FILE")
local name=$(echo "$service" | jq -r '.name')
local provider=$(echo "$service" | jq -r '.provider')
local service_type=$(echo "$service" | jq -r '.type')
local bin_path=$(echo "$service" | jq -r '.bin_path')
local args=$(echo "$service" | jq -r '.args')
local systemd_type=$(echo "$service" | jq -r '.systemd_type // "--user"')
local restart_policy=$(echo "$service" | jq -r '.restart_policy // "always"')
local session_manager=$(echo "$service" | jq -r '.session_manager // "none"')
local gdb_enabled=$(echo "$service" | jq -r '.gdb_enabled // "0"')
local pm2_opts=$(echo "$service" | jq -r '.pm2_opts // ""')
local server_config=$(echo "$service" | jq -r '.server_config // ""')
echo ""
echo -e "${YELLOW}Service '$name' ($provider) is missing${NC}"
echo " Type: $service_type"
echo " Status: $status"
if [ "$bin_path" = "unknown" ] || [ "$bin_path" = "null" ] || [ "$status" = "migrated" ]; then
echo " Binary: <needs manual configuration>"
echo " Args: <needs manual configuration>"
echo ""
echo -e "${YELLOW}This service needs to be recreated manually:${NC}"
echo " $0 create $service_type $name --provider $provider --bin-path /path/to/your/bin"
else
echo " Binary: $bin_path"
echo " Args: $args"
fi
echo ""
read -p "Do you want to (r)ecreate, (d)elete from registry, or (s)kip? [r/d/s]: " choice
case "$choice" in
r|R|recreate)
if [ "$bin_path" = "unknown" ] || [ "$status" = "migrated" ]; then
echo -e "${YELLOW}Please recreate manually with full create command${NC}"
read -p "Remove this entry from registry? [y/n]: " remove_entry
if [[ "$remove_entry" =~ ^[Yy]$ ]]; then
remove_service_from_registry "$name"
fi
else
echo -e "${BLUE}Recreating service '$name'...${NC}"
if [ "$provider" = "pm2" ]; then
if [ "$args" != "null" ] && [ -n "$args" ]; then
pm2_create_service "$name" "$bin_path $args" "$restart_policy" $pm2_opts
else
pm2_create_service "$name" "$bin_path" "$restart_policy" $pm2_opts
fi
elif [ "$provider" = "systemd" ]; then
echo -e "${BLUE}Attempting to recreate systemd service '$name' automatically...${NC}"
if systemd_create_service "$name" "$bin_path $args" "$restart_policy" "$systemd_type" "$session_manager" "$gdb_enabled" "$server_config"; then
echo -e "${GREEN}Systemd service '$name' recreated successfully${NC}"
else
echo -e "${RED}Failed to recreate systemd service '$name'. Please recreate manually.${NC}"
echo " $0 create $name $service_type --provider systemd --bin-path $bin_path"
fi
fi
fi
;;
d|D|delete)
echo -e "${BLUE}Removing '$name' from registry...${NC}"
remove_service_from_registry "$name"
;;
s|S|skip|*)
echo -e "${BLUE}Skipping '$name'${NC}"
;;
esac
done
}
# Check if PM2 is installed
check_pm2() {
if ! command -v pm2 >/dev/null 2>&1; then
@@ -81,6 +275,7 @@ function print_help() {
echo " $base_name update <service-name> [options]"
echo " $base_name delete <service-name>"
echo " $base_name list [provider]"
echo " $base_name restore"
echo " $base_name start|stop|restart|status <service-name>"
echo " $base_name logs <service-name> [--follow]"
echo " $base_name attach <service-name>"
@@ -139,6 +334,9 @@ function print_help() {
echo " $base_name attach worldserver-realm1"
echo " $base_name list pm2"
echo ""
echo " # Restore missing services from registry"
echo " $base_name restore"
echo ""
echo "Notes:"
echo " - Configuration editing modifies run-engine settings (GDB, session manager, etc.)"
echo " - Use --server-config for the actual server configuration file"
@@ -150,26 +348,13 @@ function print_help() {
echo " - attach command automatically detects the configured session manager and connects appropriately"
echo " - attach always provides interactive access to the server console"
echo " - Use 'logs' command to view service logs without interaction"
echo " - restore command checks registry and helps recreate missing services"
echo ""
echo "Environment Variables:"
echo " AC_SERVICE_CONFIG_DIR - Override default config directory for services registry"
}
function register_service() {
local service_name="$1"
local provider="$2"
local service_type="$3"
local config_file="$CONFIG_DIR/$service_name.conf"
# Add to registry
local tmp_file=$(mktemp)
jq --arg name "$service_name" \
--arg provider "$provider" \
--arg type "$service_type" \
--arg config "$config_file" \
'. += [{"name": $name, "provider": $provider, "type": $type, "config": $config}]' \
"$REGISTRY_FILE" > "$tmp_file"
mv "$tmp_file" "$REGISTRY_FILE"
echo -e "${GREEN}Service $service_name registered successfully${NC}"
}
function validate_service_exists() {
local service_name="$1"
@@ -210,47 +395,42 @@ function validate_service_exists() {
function sync_registry() {
echo -e "${YELLOW}Syncing service registry with actual services...${NC}"
local services=$(jq -c '.[]' "$REGISTRY_FILE")
local tmp_file=$(mktemp)
if [ ! -f "$REGISTRY_FILE" ] || [ ! -s "$REGISTRY_FILE" ]; then
echo -e "${YELLOW}No services registry found or empty${NC}"
return 0
fi
# Initialize with empty array
local services_count=$(jq length "$REGISTRY_FILE")
if [ "$services_count" -eq 0 ]; then
echo -e "${YELLOW}No services registered${NC}"
return 0
fi
local tmp_file=$(mktemp)
echo "[]" > "$tmp_file"
# Check each service in registry
while read -r service_info; do
if [ -n "$service_info" ]; then
local name=$(echo "$service_info" | jq -r '.name')
local provider=$(echo "$service_info" | jq -r '.provider')
if validate_service_exists "$name" "$provider"; then
# Service exists, add it to the new registry
jq --argjson service "$service_info" '. += [$service]' "$tmp_file" > "$tmp_file.new"
mv "$tmp_file.new" "$tmp_file"
else
echo -e "${YELLOW}Service '$name' no longer exists. Removing from registry.${NC}"
# Don't add to new registry
fi
for i in $(seq 0 $((services_count-1))); do
local service=$(jq -r ".[$i]" "$REGISTRY_FILE")
local name=$(echo "$service" | jq -r '.name')
local provider=$(echo "$service" | jq -r '.provider')
if validate_service_exists "$name" "$provider"; then
# Service exists, add it to the new registry
jq --argjson service "$service" '. += [$service]' "$tmp_file" > "$tmp_file.new"
mv "$tmp_file.new" "$tmp_file"
else
echo -e "${YELLOW}Service '$name' no longer exists. Removing from registry.${NC}"
# Don't add to new registry
fi
done <<< "$services"
done
# Replace registry with synced version
mv "$tmp_file" "$REGISTRY_FILE"
echo -e "${GREEN}Registry synchronized.${NC}"
}
function unregister_service() {
local service_name="$1"
# Remove from registry
local tmp_file=$(mktemp)
jq --arg name "$service_name" '. | map(select(.name != $name))' "$REGISTRY_FILE" > "$tmp_file"
mv "$tmp_file" "$REGISTRY_FILE"
# Remove configuration file
rm -f "$CONFIG_DIR/$service_name.conf"
echo -e "${GREEN}Service $service_name unregistered${NC}"
}
function get_service_info() {
local service_name="$1"
@@ -317,6 +497,15 @@ function pm2_create_service() {
if eval "$pm2_cmd"; then
echo -e "${GREEN}PM2 service '$service_name' created successfully${NC}"
pm2 save
# Setup PM2 startup for persistence across reboots
echo -e "${BLUE}Configuring PM2 startup for persistence...${NC}"
pm2 startup --auto >/dev/null 2>&1 || true
# Add to registry (extract command and args from the full command)
local clean_command="$command$additional_args"
add_service_to_registry "$service_name" "pm2" "executable" "$command" "$additional_args" "" "$restart_policy" "none" "0" "$max_memory $max_restarts" ""
return 0
else
echo -e "${RED}Failed to create PM2 service '$service_name'${NC}"
@@ -334,8 +523,8 @@ function pm2_remove_service() {
# Stop the service if it's running
if pm2 describe "$service_name" >/dev/null 2>&1; then
pm2 stop "$service_name" 2>/dev/null || true
pm2 delete "$service_name" 2>/dev/null
pm2 stop "$service_name" 2>&1 || true
pm2 delete "$service_name" 2>&1 || true
# Wait for PM2 to process the stop/delete command with timeout
local timeout=10
@@ -357,8 +546,13 @@ function pm2_remove_service() {
pm2 save
echo -e "${GREEN}PM2 service '$service_name' stopped and removed${NC}"
# Remove from registry
remove_service_from_registry "$service_name"
else
echo -e "${YELLOW}PM2 service '$service_name' not found or already removed${NC}"
# Still try to remove from registry in case it's orphaned
remove_service_from_registry "$service_name"
fi
return 0
@@ -391,6 +585,7 @@ function pm2_service_logs() {
# Systemd service management functions
function get_systemd_dir() {
local type="$1"
if [ "$type" = "--system" ]; then
echo "/etc/systemd/system"
else
@@ -403,17 +598,32 @@ function systemd_create_service() {
local command="$2"
local restart_policy="$3"
local systemd_type="--user"
local bin_path=""
local gdb_enabled="0"
local server_config=""
shift 3
check_systemd || return 1
# Parse systemd type
# Parse systemd type and extract additional parameters
while [[ $# -gt 0 ]]; do
case "$1" in
--system|--user)
systemd_type="$1"
shift
;;
--bin-path)
bin_path="$2"
shift 2
;;
--gdb-enabled)
gdb_enabled="$2"
shift 2
;;
--server-config)
server_config="$2"
shift 2
;;
*)
command+=" $1"
shift
@@ -421,6 +631,18 @@ function systemd_create_service() {
esac
done
# If bin_path is not provided, try to extract from command
if [ -z "$bin_path" ]; then
# Try to extract bin path from run-engine command
if [[ "$command" =~ run-engine[[:space:]]+start[[:space:]]+([^[:space:]]+) ]]; then
local binary_path="${BASH_REMATCH[1]}"
bin_path="$(dirname "$binary_path")"
else
# Fallback to current directory
bin_path="$(pwd)"
fi
fi
local systemd_dir=$(get_systemd_dir "$systemd_type")
local service_file="$systemd_dir/$service_name.service"
@@ -457,6 +679,11 @@ function systemd_create_service() {
# Create service file
echo -e "${YELLOW}Creating systemd service: $service_name${NC}"
# Ensure bin_path is absolute
if [[ ! "$bin_path" = /* ]]; then
bin_path="$(realpath "$bin_path")"
fi
if [ "$systemd_type" = "--system" ]; then
# System service template (with User directive)
cat > "$service_file" << EOF
@@ -471,7 +698,7 @@ Restart=$restart_policy
RestartSec=3
User=$(whoami)
Group=$(id -gn)
WorkingDirectory=$(realpath "$bin_path")
WorkingDirectory=$bin_path
StandardOutput=journal+console
StandardError=journal+console
@@ -490,7 +717,7 @@ Type=${service_type}
ExecStart=$command
Restart=$restart_policy
RestartSec=3
WorkingDirectory=$(realpath "$bin_path")
WorkingDirectory=$bin_path
StandardOutput=journal+console
StandardError=journal+console
@@ -498,10 +725,6 @@ StandardError=journal+console
WantedBy=default.target
EOF
fi
if [ "$systemd_type" = "--system" ]; then
sed -i 's/WantedBy=default.target/WantedBy=multi-user.target/' "$service_file"
fi
# Reload systemd and enable service
if [ "$systemd_type" = "--system" ]; then
@@ -513,6 +736,10 @@ EOF
fi
echo -e "${GREEN}Systemd service '$service_name' created successfully${NC}"
# Add to registry
add_service_to_registry "$service_name" "systemd" "service" "$command" "" "$systemd_type" "$restart_policy" "$session_manager" "$gdb_enabled" "" "$server_config"
return 0
}
@@ -572,6 +799,10 @@ function systemd_remove_service() {
if [ "$removal_failed" = "true" ]; then
echo -e "${YELLOW}Note: Service may still be running but configuration was removed${NC}"
fi
# Remove from registry
remove_service_from_registry "$service_name"
return 0
else
echo -e "${RED}Failed to remove systemd service file '$service_file'${NC}"
@@ -659,7 +890,7 @@ function create_service() {
# Default values for run-engine configuration
local provider="auto"
local bin_path="$BINPATH/bin" # get from config or environment
local bin_path="${BINPATH:-$ROOT_DIR/bin}" # get from config or environment
local server_config=""
local session_manager="none"
local gdb_enabled="0"
@@ -839,8 +1070,6 @@ EOF
# Check if service creation was successful
if [ "$service_creation_success" = "true" ]; then
# Register the service
register_service "$service_name" "$provider" "$service_type"
echo -e "${GREEN}Service '$service_name' created successfully${NC}"
echo -e "${BLUE}Run-engine config: $run_engine_config${NC}"
@@ -880,14 +1109,20 @@ function update_service() {
# Extract service information
local provider=$(echo "$service_info" | jq -r '.provider')
local service_type=$(echo "$service_info" | jq -r '.type')
local config_file=$(echo "$service_info" | jq -r '.config')
local config_file="$CONFIG_DIR/$service_name.conf"
# Load current configuration
if [ ! -f "$config_file" ]; then
echo -e "${RED}Error: Service configuration file not found: $config_file${NC}"
return 1
fi
source "$config_file"
# Load current run-engine configuration
if [ -f "$RUN_ENGINE_CONFIG_FILE" ]; then
source "$RUN_ENGINE_CONFIG_FILE"
else
echo -e "${YELLOW}Warning: Run-engine configuration file not found: $RUN_ENGINE_CONFIG_FILE${NC}"
fi
# Parse options to update
@@ -1020,11 +1255,13 @@ function delete_service() {
# Extract provider and config
local provider=$(echo "$service_info" | jq -r '.provider')
local config_file=$(echo "$service_info" | jq -r '.config')
local config_file="$CONFIG_DIR/$service_name.conf"
# Load configuration to get run-engine config file
if [ -f "$config_file" ]; then
source "$config_file"
else
echo -e "${YELLOW}Warning: Service configuration file not found: $config_file${NC}"
fi
echo -e "${YELLOW}Deleting service '$service_name' (provider: $provider)...${NC}"
@@ -1048,8 +1285,9 @@ function delete_service() {
echo -e "${GREEN}Removed run-engine config: $RUN_ENGINE_CONFIG_FILE${NC}"
fi
# Unregister service
unregister_service "$service_name"
# Remove configuration file
rm -f "$config_file"
echo -e "${GREEN}Service '$service_name' deleted successfully${NC}"
else
echo -e "${RED}Failed to remove service '$service_name' from $provider${NC}"
@@ -1166,7 +1404,7 @@ function edit_config() {
fi
# Get configuration file path
local config_file=$(echo "$service_info" | jq -r '.config')
local config_file="$CONFIG_DIR/$service_name.conf"
# Load configuration to get run-engine config file
source "$config_file"
@@ -1191,7 +1429,7 @@ function attach_to_service() {
# Extract provider
local provider=$(echo "$service_info" | jq -r '.provider')
local config_file=$(echo "$service_info" | jq -r '.config')
local config_file="$CONFIG_DIR/$service_name.conf"
# Load configuration to get run-engine config file
if [ ! -f "$config_file" ]; then
@@ -1206,6 +1444,11 @@ function attach_to_service() {
echo -e "${RED}Error: Run-engine configuration file not found: $RUN_ENGINE_CONFIG_FILE${NC}"
return 1
fi
if [ ! -f "$RUN_ENGINE_CONFIG_FILE" ]; then
echo -e "${RED}Error: Run-engine configuration file not found: $RUN_ENGINE_CONFIG_FILE${NC}"
return 1
fi
source "$RUN_ENGINE_CONFIG_FILE"
@@ -1264,9 +1507,22 @@ function attach_interactive_shell() {
# For systemd without session manager, show helpful message
local service_info=$(get_service_info "$service_name")
local config_file=$(echo "$service_info" | jq -r '.config')
local config_file="$CONFIG_DIR/$service_name.conf"
# Check if config file exists before sourcing
if [ ! -f "$config_file" ]; then
echo -e "${RED}Error: Service configuration file not found: $config_file${NC}"
return 1
fi
source "$config_file"
# Check if RUN_ENGINE_CONFIG_FILE exists before sourcing
if [ ! -f "$RUN_ENGINE_CONFIG_FILE" ]; then
echo -e "${RED}Error: Run-engine configuration file not found: $RUN_ENGINE_CONFIG_FILE${NC}"
return 1
fi
source "$RUN_ENGINE_CONFIG_FILE"
echo -e "${RED}Error: Cannot attach to systemd service '$service_name'${NC}"
@@ -1375,6 +1631,9 @@ case "${1:-help}" in
list)
list_services "$2"
;;
restore)
restore_missing_services
;;
start|stop|restart|status)
if [ $# -lt 2 ]; then
echo -e "${RED}Error: Service name required for $1 command${NC}"