refactoring and adding automations

This commit is contained in:
Deckard
2025-10-17 01:40:50 -04:00
parent 4bf22d1829
commit 859a214e12
65 changed files with 4622 additions and 956 deletions

549
V1/scripts/deploy-and-check.sh Executable file
View File

@@ -0,0 +1,549 @@
#!/bin/bash
# ==============================================
# AzerothCore Docker Deployment & Health Check Script
# ==============================================
# This script deploys the complete AzerothCore stack and performs comprehensive health checks
# Usage: ./deploy-and-check.sh [--skip-deploy] [--quick-check] [--setup]
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script options
SKIP_DEPLOY=false
QUICK_CHECK=false
RUN_SETUP=false
MODULES_ENABLED=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--skip-deploy)
SKIP_DEPLOY=true
shift
;;
--quick-check)
QUICK_CHECK=true
shift
;;
--setup)
RUN_SETUP=true
shift
;;
-h|--help)
echo "Usage: $0 [--skip-deploy] [--quick-check] [--setup]"
echo " --skip-deploy Skip deployment, only run health checks"
echo " --quick-check Run basic health checks only"
echo " --setup Run interactive server setup before deployment"
exit 0
;;
*)
echo "Unknown option $1"
exit 1
;;
esac
done
# Function to print colored output
print_status() {
local status=$1
local message=$2
case $status in
"INFO")
echo -e "${BLUE} ${message}${NC}"
;;
"SUCCESS")
echo -e "${GREEN}${message}${NC}"
;;
"WARNING")
echo -e "${YELLOW}⚠️ ${message}${NC}"
;;
"ERROR")
echo -e "${RED}${message}${NC}"
;;
"HEADER")
echo -e "\n${BLUE}=== ${message} ===${NC}"
;;
esac
}
# Function to check if a port is accessible
check_port() {
local port=$1
local service_name=$2
local timeout=${3:-5}
if timeout $timeout bash -c "echo >/dev/tcp/localhost/$port" 2>/dev/null; then
print_status "SUCCESS" "$service_name (port $port): CONNECTED"
return 0
else
print_status "ERROR" "$service_name (port $port): FAILED"
return 1
fi
}
# Function to format seconds as MM:SS
format_time() {
local total_seconds=$1
local minutes=$((total_seconds / 60))
local seconds=$((total_seconds % 60))
printf "%d:%02d" "$minutes" "$seconds"
}
# Function to wait for a service to be ready
wait_for_service() {
local service_name=$1
local max_attempts=$2
local check_command=$3
local container_name=""
# Extract container name from common patterns
if echo "$check_command" | grep -q "ac-client-data"; then
container_name="ac-client-data"
elif echo "$check_command" | grep -q "ac-db-import"; then
container_name="ac-db-import"
elif echo "$check_command" | grep -q "ac-mysql"; then
container_name="ac-mysql"
elif echo "$check_command" | grep -q "ac-worldserver"; then
container_name="ac-worldserver"
elif echo "$check_command" | grep -q "ac-authserver"; then
container_name="ac-authserver"
fi
local timeout_formatted=$(format_time $((max_attempts * 5)))
print_status "INFO" "Waiting for $service_name to be ready... (timeout: $timeout_formatted)"
for i in $(seq 1 $max_attempts); do
if eval "$check_command" &>/dev/null; then
print_status "SUCCESS" "$service_name is ready!"
return 0
fi
if [ $i -eq $max_attempts ]; then
print_status "ERROR" "$service_name failed to start after $max_attempts attempts"
if [ -n "$container_name" ]; then
print_status "INFO" "Last few log lines from $container_name:"
docker logs "$container_name" --tail 5 2>/dev/null | sed 's/^/ /' || echo " (no logs available)"
fi
return 1
fi
# Show progress with more informative output
local elapsed=$((i * 5))
local remaining=$(( (max_attempts - i) * 5))
local elapsed_formatted=$(format_time $elapsed)
local remaining_formatted=$(format_time $remaining)
if [ -n "$container_name" ]; then
# Get container status
local status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null || echo "unknown")
local health=$(docker inspect --format='{{.State.Health.Status}}' "$container_name" 2>/dev/null || echo "no-health-check")
# Show different progress info based on service
case "$service_name" in
"Client Data")
local last_log=$(docker logs "$container_name" --tail 1 2>/dev/null | head -c 80 || echo "...")
printf "${YELLOW}${NC} %s elapsed, %s remaining | Status: %s | Latest: %s\n" "$elapsed_formatted" "$remaining_formatted" "$status" "$last_log"
;;
"Database Import")
printf "${YELLOW}${NC} %s elapsed, %s remaining | Status: %s | Importing databases...\n" "$elapsed_formatted" "$remaining_formatted" "$status"
;;
*)
printf "${YELLOW}${NC} %s elapsed, %s remaining | Status: %s" "$elapsed_formatted" "$remaining_formatted" "$status"
if [ "$health" != "no-health-check" ]; then
printf " | Health: %s" "$health"
fi
printf "\n"
;;
esac
else
printf "${YELLOW}${NC} %s elapsed, %s remaining | Checking...\n" "$elapsed_formatted" "$remaining_formatted"
fi
sleep 5
done
}
# Function to check container health
check_container_health() {
local container_name=$1
local status=$(docker inspect --format='{{.State.Health.Status}}' $container_name 2>/dev/null || echo "no-health-check")
if [ "$status" = "healthy" ]; then
print_status "SUCCESS" "$container_name: healthy"
return 0
elif [ "$status" = "no-health-check" ] || [ "$status" = "<no value>" ]; then
# Check if container is running
if docker ps --format '{{.Names}}' | grep -q "^${container_name}$"; then
print_status "SUCCESS" "$container_name: running (no health check)"
return 0
else
print_status "ERROR" "$container_name: not running"
return 1
fi
else
print_status "WARNING" "$container_name: $status"
return 1
fi
}
# Function to check web service health
check_web_service() {
local url=$1
local service_name=$2
local expected_pattern=$3
response=$(curl -s --max-time 10 "$url" 2>/dev/null || echo "")
if [ -n "$expected_pattern" ]; then
if echo "$response" | grep -q "$expected_pattern"; then
print_status "SUCCESS" "$service_name: HTTP OK (content verified)"
return 0
else
print_status "ERROR" "$service_name: HTTP OK but content verification failed"
return 1
fi
else
if [ -n "$response" ]; then
print_status "SUCCESS" "$service_name: HTTP OK"
return 0
else
print_status "ERROR" "$service_name: HTTP failed"
return 1
fi
fi
}
# Function to deploy the stack
deploy_stack() {
print_status "HEADER" "DEPLOYING AZEROTHCORE STACK"
# Check if custom environment files exist first, then fallback to base files
DB_ENV_FILE="./docker-compose-azerothcore-database-custom.env"
SERVICES_ENV_FILE="./docker-compose-azerothcore-services-custom.env"
MODULES_ENV_FILE="./docker-compose-azerothcore-modules-custom.env"
TOOLS_ENV_FILE="./docker-compose-azerothcore-tools-custom.env"
# Fallback to base files if custom files don't exist
if [ ! -f "$DB_ENV_FILE" ]; then
DB_ENV_FILE="./docker-compose-azerothcore-database.env"
fi
if [ ! -f "$SERVICES_ENV_FILE" ]; then
SERVICES_ENV_FILE="./docker-compose-azerothcore-services.env"
fi
if [ ! -f "$MODULES_ENV_FILE" ]; then
MODULES_ENV_FILE="./docker-compose-azerothcore-modules.env"
fi
if [ ! -f "$TOOLS_ENV_FILE" ]; then
TOOLS_ENV_FILE="./docker-compose-azerothcore-tools.env"
fi
# Check if required environment files exist
for env_file in "$DB_ENV_FILE" "$SERVICES_ENV_FILE" "$TOOLS_ENV_FILE"; do
if [ ! -f "$env_file" ]; then
print_status "ERROR" "Environment file $env_file not found"
print_status "INFO" "Run ./scripts/setup-server.sh first to create environment files"
exit 1
fi
done
# Check if modules are enabled (set global variable)
if [ -f "$MODULES_ENV_FILE" ]; then
MODULES_ENABLED=true
else
MODULES_ENABLED=false
fi
print_status "INFO" "Step 1: Deploying database layer..."
docker compose --env-file "$DB_ENV_FILE" -f ./docker-compose-azerothcore-database.yml up -d --remove-orphans
# Wait for database initialization
wait_for_service "MySQL" 24 "docker exec ac-mysql mysql -uroot -pazerothcore123 -e 'SELECT 1' >/dev/null 2>&1"
# Wait for database import (can succeed with backup restore OR fail without backup)
print_status "INFO" "Waiting for Database Import to complete (backup restore attempt)..."
local import_result=""
local elapsed=0
local max_time=180 # 3 minutes max for import to complete
while [ $elapsed -lt $max_time ]; do
local import_status=$(docker inspect ac-db-import --format='{{.State.Status}}' 2>/dev/null || echo "unknown")
if [ "$import_status" = "exited" ]; then
local exit_code=$(docker inspect ac-db-import --format='{{.State.ExitCode}}' 2>/dev/null || echo "unknown")
if [ "$exit_code" = "0" ]; then
print_status "SUCCESS" "Database Import completed successfully (backup restored)"
import_result="restored"
break
else
print_status "INFO" "Database Import failed (no valid backup found - expected for fresh setup)"
import_result="failed"
break
fi
fi
printf "${YELLOW}${NC} ${elapsed}s elapsed, $((max_time - elapsed))s remaining | Status: $import_status | Checking for backup...\n"
sleep 5
elapsed=$((elapsed + 5))
done
if [ -z "$import_result" ]; then
print_status "ERROR" "Database Import did not complete within timeout"
exit 1
fi
# If import failed (no backup), wait for init to create databases
if [ "$import_result" = "failed" ]; then
print_status "INFO" "Waiting for Database Init to create fresh databases..."
local init_elapsed=0
local init_max_time=120 # 2 minutes for init
while [ $init_elapsed -lt $init_max_time ]; do
local init_status=$(docker inspect ac-db-init --format='{{.State.Status}}' 2>/dev/null || echo "created")
if [ "$init_status" = "exited" ]; then
local init_exit_code=$(docker inspect ac-db-init --format='{{.State.ExitCode}}' 2>/dev/null || echo "unknown")
if [ "$init_exit_code" = "0" ]; then
print_status "SUCCESS" "Database Init completed successfully (fresh databases created)"
break
else
print_status "ERROR" "Database Init failed"
print_status "INFO" "Last few log lines from ac-db-init:"
docker logs ac-db-init --tail 10 2>/dev/null || true
exit 1
fi
elif [ "$init_status" = "running" ]; then
printf "${YELLOW}${NC} ${init_elapsed}s elapsed, $((init_max_time - init_elapsed))s remaining | Status: $init_status | Creating databases...\n"
else
printf "${YELLOW}${NC} ${init_elapsed}s elapsed, $((init_max_time - init_elapsed))s remaining | Status: $init_status | Waiting to start...\n"
fi
sleep 5
init_elapsed=$((init_elapsed + 5))
done
if [ $init_elapsed -ge $init_max_time ]; then
print_status "ERROR" "Database Init did not complete within timeout"
exit 1
fi
fi
print_status "INFO" "Step 2: Deploying services layer..."
docker compose --env-file "$SERVICES_ENV_FILE" -f ./docker-compose-azerothcore-services.yml up -d 2>&1 | grep -v "Found orphan containers"
# Wait for client data extraction
print_status "INFO" "Waiting for client data download and extraction (optimized: 8-15 minutes typical)..."
print_status "INFO" "Press Ctrl+C to exit if needed..."
wait_for_service "Client Data" 360 "docker logs ac-client-data 2>/dev/null | grep -q 'Game data setup complete'"
# Wait for worldserver to be healthy
wait_for_service "World Server" 24 "check_container_health ac-worldserver"
# Deploy modules if enabled
if [ "$MODULES_ENABLED" = true ]; then
print_status "INFO" "Step 3: Deploying modules layer..."
# Ensure ac-modules is recreated with the correct environment
# It may have been created earlier by the services layer using services env
if docker ps -a --format '{{.Names}}' | grep -q '^ac-modules$'; then
print_status "INFO" "Recreating ac-modules with modules env (removing existing container)"
docker rm -f ac-modules >/dev/null 2>&1 || true
fi
docker compose --env-file "$MODULES_ENV_FILE" -f ./docker-compose-azerothcore-modules.yml up -d 2>&1 | grep -v "Found orphan containers"
# Wait for modules to be ready
sleep 5
STEP_NUMBER=4
else
print_status "INFO" "Modules layer skipped (no custom modules configuration found)"
STEP_NUMBER=3
fi
print_status "INFO" "Step $STEP_NUMBER: Deploying tools layer..."
docker compose --env-file "$TOOLS_ENV_FILE" -f ./docker-compose-azerothcore-tools.yml up -d
# Wait for tools to be ready
sleep 10
print_status "SUCCESS" "Deployment completed!"
}
# Function to perform health checks
perform_health_checks() {
print_status "HEADER" "CONTAINER HEALTH STATUS"
# Check all containers
local containers=("ac-mysql" "ac-backup" "ac-authserver" "ac-worldserver" "ac-phpmyadmin" "ac-keira3")
# Add modules container if modules are enabled
if [ "$MODULES_ENABLED" = true ]; then
containers+=("ac-modules")
fi
local container_failures=0
for container in "${containers[@]}"; do
# Only check containers that actually exist
if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then
if ! check_container_health "$container"; then
# Only count as failure if container is not running, not just missing health check
if ! docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
((container_failures++))
fi
fi
fi
done
print_status "HEADER" "PORT CONNECTIVITY TESTS"
# Database Layer
print_status "INFO" "Database Layer:"
local port_failures=0
if ! check_port 64306 "MySQL"; then ((port_failures++)); fi
# Services Layer
print_status "INFO" "Services Layer:"
if ! check_port 3784 "Auth Server"; then ((port_failures++)); fi
if ! check_port 8215 "World Server"; then ((port_failures++)); fi
if ! check_port 7778 "SOAP API"; then ((port_failures++)); fi
# Tools Layer
print_status "INFO" "Tools Layer:"
if ! check_port 8081 "PHPMyAdmin"; then ((port_failures++)); fi
if ! check_port 4201 "Keira3"; then ((port_failures++)); fi
if [ "$QUICK_CHECK" = false ]; then
print_status "HEADER" "WEB SERVICE HEALTH CHECKS"
local web_failures=0
if ! check_web_service "http://localhost:8081/" "PHPMyAdmin" "phpMyAdmin"; then ((web_failures++)); fi
if ! check_web_service "http://localhost:4201/health" "Keira3" "healthy"; then ((web_failures++)); fi
print_status "HEADER" "DATABASE CONNECTIVITY TEST"
# Test database connectivity and verify schemas
if docker exec ac-mysql mysql -uroot -pazerothcore123 -e "SHOW DATABASES;" 2>/dev/null | grep -q "acore_auth"; then
print_status "SUCCESS" "Database schemas: verified"
else
print_status "ERROR" "Database schemas: verification failed"
((web_failures++))
fi
# Test realm configuration
realm_count=$(docker exec ac-mysql mysql -uroot -pazerothcore123 -e "USE acore_auth; SELECT COUNT(*) FROM realmlist;" 2>/dev/null | tail -1)
if [ "$realm_count" -gt 0 ] 2>/dev/null; then
print_status "SUCCESS" "Realm configuration: $realm_count realm(s) configured"
else
print_status "ERROR" "Realm configuration: no realms found"
((web_failures++))
fi
fi
print_status "HEADER" "DEPLOYMENT SUMMARY"
# Summary
local total_failures=$((container_failures + port_failures + ${web_failures:-0}))
if [ $total_failures -eq 0 ]; then
print_status "SUCCESS" "All services are healthy and operational!"
print_status "INFO" "Available services:"
echo " 🌐 PHPMyAdmin: http://localhost:8081"
echo " 🛠️ Keira3: http://localhost:4201"
echo " 🎮 Game Server: localhost:8215"
echo " 🔐 Auth Server: localhost:3784"
echo " 🔧 SOAP API: localhost:7778"
echo " 🗄️ MySQL: localhost:64306"
echo ""
print_status "INFO" "Default credentials:"
echo " 🗄️ MySQL: root / azerothcore123"
return 0
else
print_status "ERROR" "Health check failed with $total_failures issue(s)"
print_status "INFO" "Check container logs for details: docker logs <container-name>"
return 1
fi
}
# Function to show container status
show_container_status() {
print_status "HEADER" "CONTAINER STATUS OVERVIEW"
echo -e "${BLUE}Container Name\t\tStatus\t\t\tPorts${NC}"
echo "=================================================================="
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep ac- | while read line; do
echo "$line"
done
}
# Main execution
main() {
print_status "HEADER" "AZEROTHCORE DEPLOYMENT & HEALTH CHECK"
# Check if docker is available
if ! command -v docker &> /dev/null; then
print_status "ERROR" "Docker is not installed or not in PATH"
exit 1
fi
# Check if docker compose is available
if ! docker compose version &> /dev/null; then
print_status "ERROR" "Docker Compose is not available"
exit 1
fi
# Run setup if requested
if [ "$RUN_SETUP" = true ]; then
print_status "HEADER" "RUNNING SERVER SETUP"
print_status "INFO" "Starting interactive server configuration..."
# Change to parent directory to run setup script
cd "$(dirname "$(pwd)")"
if [ -f "scripts/setup-server.sh" ]; then
bash scripts/setup-server.sh
if [ $? -ne 0 ]; then
print_status "ERROR" "Server setup failed or was cancelled"
exit 1
fi
else
print_status "ERROR" "Setup script not found at scripts/setup-server.sh"
exit 1
fi
# Return to scripts directory
cd scripts
print_status "SUCCESS" "Server setup completed!"
echo ""
fi
# Deploy the stack unless skipped
if [ "$SKIP_DEPLOY" = false ]; then
deploy_stack
else
print_status "INFO" "Skipping deployment, running health checks only..."
fi
# Show container status
show_container_status
# Perform health checks
if perform_health_checks; then
print_status "SUCCESS" "🎉 AzerothCore stack is fully operational!"
exit 0
else
print_status "ERROR" "❌ Health check failed - see issues above"
exit 1
fi
}
# Run main function
main "$@"