summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/startup-scripts/README.md95
-rwxr-xr-xapps/startup-scripts/src/migrate-registry.sh144
-rwxr-xr-xapps/startup-scripts/src/service-manager.sh407
3 files changed, 561 insertions, 85 deletions
diff --git a/apps/startup-scripts/README.md b/apps/startup-scripts/README.md
index 7b057581d7..176ec3ed6c 100644
--- a/apps/startup-scripts/README.md
+++ b/apps/startup-scripts/README.md
@@ -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,29 +387,85 @@ cp examples/restarter-world.sh restarter-realm2.sh
## 🛠️ Service Management
-### PM2 Services
+### Service Registry and Persistence
-When using PM2 as the service provider:
+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
-# 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
+# Migrate existing registry to new format
+./migrate-registry.sh
-# Save PM2 configuration
-pm2 save
-pm2 startup # Auto-start on boot
+# 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)
@@ -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
+```
+
+
diff --git a/apps/startup-scripts/src/migrate-registry.sh b/apps/startup-scripts/src/migrate-registry.sh
new file mode 100755
index 0000000000..c5898794f5
--- /dev/null
+++ b/apps/startup-scripts/src/migrate-registry.sh
@@ -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"
diff --git a/apps/startup-scripts/src/service-manager.sh b/apps/startup-scripts/src/service-manager.sh
index 980dfbb3a0..34dc4c4d5a 100755
--- a/apps/startup-scripts/src/service-manager.sh
+++ b/apps/startup-scripts/src/service-manager.sh
@@ -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}"