mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-02-08 21:21:11 +00:00
Compare commits
9 Commits
feat/setup
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c57c388d26 | ||
|
|
6170c6e43b | ||
|
|
74bbc464ac | ||
|
|
1edc675530 | ||
|
|
56769e81d5 | ||
|
|
654d81bb38 | ||
|
|
6a05fe785f | ||
|
|
c46f25a1a9 | ||
|
|
517adc4225 |
@@ -105,21 +105,21 @@ NETWORK_GATEWAY=172.20.0.1
|
|||||||
# =====================
|
# =====================
|
||||||
# Change this to your server's public IP or domain name
|
# Change this to your server's public IP or domain name
|
||||||
SERVER_ADDRESS=127.0.0.1
|
SERVER_ADDRESS=127.0.0.1
|
||||||
REALM_PORT=8215
|
REALM_PORT=8085
|
||||||
|
|
||||||
# =====================
|
# =====================
|
||||||
# Ports
|
# Ports
|
||||||
# =====================
|
# =====================
|
||||||
# Authentication server
|
# Authentication server
|
||||||
AUTH_EXTERNAL_PORT=3784
|
AUTH_EXTERNAL_PORT=3724
|
||||||
AUTH_PORT=3724
|
AUTH_PORT=3724
|
||||||
|
|
||||||
# World server
|
# World server
|
||||||
WORLD_EXTERNAL_PORT=8215
|
WORLD_EXTERNAL_PORT=8085
|
||||||
WORLD_PORT=8085
|
WORLD_PORT=8085
|
||||||
|
|
||||||
# SOAP/Remote access
|
# SOAP/Remote access
|
||||||
SOAP_EXTERNAL_PORT=7778
|
SOAP_EXTERNAL_PORT=7878
|
||||||
SOAP_PORT=7878
|
SOAP_PORT=7878
|
||||||
|
|
||||||
# MySQL database (for external access)
|
# MySQL database (for external access)
|
||||||
|
|||||||
@@ -118,11 +118,11 @@ ALPINE_IMAGE=alpine:latest
|
|||||||
# =====================
|
# =====================
|
||||||
# Ports
|
# Ports
|
||||||
# =====================
|
# =====================
|
||||||
AUTH_EXTERNAL_PORT=3784
|
AUTH_EXTERNAL_PORT=3724
|
||||||
AUTH_PORT=3724
|
AUTH_PORT=3724
|
||||||
WORLD_EXTERNAL_PORT=8215
|
WORLD_EXTERNAL_PORT=8085
|
||||||
WORLD_PORT=8085
|
WORLD_PORT=8085
|
||||||
SOAP_EXTERNAL_PORT=7778
|
SOAP_EXTERNAL_PORT=7878
|
||||||
SOAP_PORT=7878
|
SOAP_PORT=7878
|
||||||
|
|
||||||
# =====================
|
# =====================
|
||||||
@@ -136,7 +136,7 @@ NETWORK_GATEWAY=172.20.0.1
|
|||||||
# Server address / realm
|
# Server address / realm
|
||||||
# =====================
|
# =====================
|
||||||
SERVER_ADDRESS=127.0.0.1
|
SERVER_ADDRESS=127.0.0.1
|
||||||
REALM_PORT=8215
|
REALM_PORT=8085
|
||||||
|
|
||||||
# =====================
|
# =====================
|
||||||
# MySQL / Database Layer
|
# MySQL / Database Layer
|
||||||
@@ -561,3 +561,6 @@ MODULE_DUELS=0
|
|||||||
MODULE_WOW_CORE=0
|
MODULE_WOW_CORE=0
|
||||||
MODULE_CLANCENTAUR=0
|
MODULE_CLANCENTAUR=0
|
||||||
MODULE_DELVES=0
|
MODULE_DELVES=0
|
||||||
|
MODULE_MOD_DISABLE_ACHIEVEMENTS=0
|
||||||
|
MODULE_LUA_BATTLEPASS=0
|
||||||
|
MODULE_MOD_GM_DISCORD=0
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ cp .env.prebuilt .env
|
|||||||
|
|
||||||
Pre-built images include the **RealmMaster profile** (32 modules) and are automatically built nightly. See **[docs/PREBUILT_IMAGES.md](docs/PREBUILT_IMAGES.md)** for details.
|
Pre-built images include the **RealmMaster profile** (32 modules) and are automatically built nightly. See **[docs/PREBUILT_IMAGES.md](docs/PREBUILT_IMAGES.md)** for details.
|
||||||
|
|
||||||
|
**Note:** Remote deployments require one additional step after migration - see [Remote Deployment Guide](docs/GETTING_STARTED.md#remote-deployment).
|
||||||
|
|
||||||
See [Getting Started](#getting-started) for detailed walkthrough.
|
See [Getting Started](#getting-started) for detailed walkthrough.
|
||||||
|
|
||||||
## What You Get
|
## What You Get
|
||||||
|
|||||||
37
build.sh
37
build.sh
@@ -8,10 +8,8 @@ set -euo pipefail
|
|||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
ENV_PATH="$ROOT_DIR/.env"
|
ENV_PATH="$ROOT_DIR/.env"
|
||||||
DEFAULT_ENV_PATH="$ENV_PATH"
|
|
||||||
TEMPLATE_PATH="$ROOT_DIR/.env.template"
|
TEMPLATE_PATH="$ROOT_DIR/.env.template"
|
||||||
source "$ROOT_DIR/scripts/bash/project_name.sh"
|
source "$ROOT_DIR/scripts/bash/project_name.sh"
|
||||||
source "$ROOT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
|
|
||||||
# Default project name (read from .env or template)
|
# Default project name (read from .env or template)
|
||||||
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_PATH" "$TEMPLATE_PATH")"
|
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_PATH" "$TEMPLATE_PATH")"
|
||||||
@@ -19,6 +17,11 @@ ASSUME_YES=0
|
|||||||
FORCE_REBUILD=0
|
FORCE_REBUILD=0
|
||||||
SKIP_SOURCE_SETUP=0
|
SKIP_SOURCE_SETUP=0
|
||||||
CUSTOM_SOURCE_PATH=""
|
CUSTOM_SOURCE_PATH=""
|
||||||
|
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
|
||||||
|
info(){ printf '%b\n' "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
ok(){ printf '%b\n' "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn(){ printf '%b\n' "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
err(){ printf '%b\n' "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
show_build_header(){
|
show_build_header(){
|
||||||
printf '\n%b\n' "${BLUE}🔨 AZEROTHCORE BUILD SYSTEM 🔨${NC}"
|
printf '\n%b\n' "${BLUE}🔨 AZEROTHCORE BUILD SYSTEM 🔨${NC}"
|
||||||
@@ -67,9 +70,39 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
require_cmd(){
|
||||||
|
command -v "$1" >/dev/null 2>&1 || { err "Missing required command: $1"; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
require_cmd docker
|
require_cmd docker
|
||||||
require_cmd python3
|
require_cmd python3
|
||||||
|
|
||||||
|
read_env(){
|
||||||
|
local key="$1" default="${2:-}"
|
||||||
|
local value=""
|
||||||
|
if [ -f "$ENV_PATH" ]; then
|
||||||
|
value="$(grep -E "^${key}=" "$ENV_PATH" 2>/dev/null | tail -n1 | cut -d'=' -f2- | tr -d '\r' | sed 's/[[:space:]]*#.*//' | sed 's/[[:space:]]*$//')"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$default"
|
||||||
|
fi
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_env_value(){
|
||||||
|
local key="$1" value="$2" env_file="$ENV_PATH"
|
||||||
|
[ -n "$env_file" ] || return 0
|
||||||
|
if [ ! -f "$env_file" ]; then
|
||||||
|
printf '%s=%s\n' "$key" "$value" >> "$env_file"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if grep -q "^${key}=" "$env_file"; then
|
||||||
|
sed -i "s|^${key}=.*|${key}=${value}|" "$env_file"
|
||||||
|
else
|
||||||
|
printf '\n%s=%s\n' "$key" "$value" >> "$env_file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
MODULE_HELPER="$ROOT_DIR/scripts/python/modules.py"
|
MODULE_HELPER="$ROOT_DIR/scripts/python/modules.py"
|
||||||
MODULE_STATE_INITIALIZED=0
|
MODULE_STATE_INITIALIZED=0
|
||||||
declare -a MODULES_COMPILE_LIST=()
|
declare -a MODULES_COMPILE_LIST=()
|
||||||
|
|||||||
@@ -5545,6 +5545,48 @@
|
|||||||
"requires": [],
|
"requires": [],
|
||||||
"post_install_hooks": [],
|
"post_install_hooks": [],
|
||||||
"config_cleanup": []
|
"config_cleanup": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "MODULE_MOD_DISABLE_ACHIEVEMENTS",
|
||||||
|
"name": "mod-disable-achievements",
|
||||||
|
"repo": "https://github.com/olive-spore-734/mod-disable-achievements.git",
|
||||||
|
"description": "SQL with a long list of WotLK Achievements and their IDs, which should make it much easier to find and disable some. Made for AzerothCore.",
|
||||||
|
"type": "sql",
|
||||||
|
"category": "database",
|
||||||
|
"notes": "Discovered via GitHub topic 'azerothcore-module'",
|
||||||
|
"status": "active",
|
||||||
|
"order": 5000,
|
||||||
|
"requires": [],
|
||||||
|
"post_install_hooks": [],
|
||||||
|
"config_cleanup": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "MODULE_LUA_BATTLEPASS",
|
||||||
|
"name": "lua-battlepass",
|
||||||
|
"repo": "https://github.com/Shonik/lua-battlepass.git",
|
||||||
|
"description": "Battle Pass System for AzerothCore",
|
||||||
|
"type": "lua",
|
||||||
|
"category": "scripting",
|
||||||
|
"notes": "Discovered via GitHub topic 'azerothcore-lua'",
|
||||||
|
"status": "active",
|
||||||
|
"order": 5000,
|
||||||
|
"requires": [],
|
||||||
|
"post_install_hooks": [],
|
||||||
|
"config_cleanup": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "MODULE_MOD_GM_DISCORD",
|
||||||
|
"name": "mod-gm-discord",
|
||||||
|
"repo": "https://github.com/Diabloxx/mod-gm-discord.git",
|
||||||
|
"description": "GM to Discord Tools",
|
||||||
|
"type": "cpp",
|
||||||
|
"category": "uncategorized",
|
||||||
|
"notes": "Discovered via GitHub topic 'azerothcore-module'",
|
||||||
|
"status": "active",
|
||||||
|
"order": 5000,
|
||||||
|
"requires": [],
|
||||||
|
"post_install_hooks": [],
|
||||||
|
"config_cleanup": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
"MODULE_ARAC",
|
"MODULE_ARAC",
|
||||||
"MODULE_ASSISTANT",
|
"MODULE_ASSISTANT",
|
||||||
"MODULE_REAGENT_BANK",
|
"MODULE_REAGENT_BANK",
|
||||||
"MODULE_BLACK_MARKET_AUCTION_HOUSE",
|
|
||||||
"MODULE_ELUNA",
|
"MODULE_ELUNA",
|
||||||
"MODULE_AIO",
|
"MODULE_AIO",
|
||||||
"MODULE_ELUNA_SCRIPTS",
|
"MODULE_ELUNA_SCRIPTS",
|
||||||
|
"MODULE_LUA_AH_BOT",
|
||||||
"MODULE_EVENT_SCRIPTS",
|
"MODULE_EVENT_SCRIPTS",
|
||||||
"MODULE_ACTIVE_CHAT",
|
"MODULE_ACTIVE_CHAT",
|
||||||
"MODULE_GUILDHOUSE",
|
"MODULE_GUILDHOUSE",
|
||||||
|
|||||||
13
config/systemd/docker.service.d/nfs-dependencies.conf
Normal file
13
config/systemd/docker.service.d/nfs-dependencies.conf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# AzerothCore RealmMaster - Docker NFS Dependencies
|
||||||
|
# Ensures Docker waits for NFS mounts before starting to prevent race conditions
|
||||||
|
# where containers create local directories before NFS mounts are ready
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
# Wait for NFS mounts to be active before starting Docker
|
||||||
|
After=nfs-azerothcore.mount nfs-containers.mount
|
||||||
|
|
||||||
|
# Require the primary backup NFS mount (critical for data integrity)
|
||||||
|
Requires=nfs-azerothcore.mount
|
||||||
|
|
||||||
|
# Prefer the containers NFS mount but don't fail if unavailable
|
||||||
|
Wants=nfs-containers.mount
|
||||||
66
deploy.sh
66
deploy.sh
@@ -11,10 +11,8 @@ set -euo pipefail
|
|||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
||||||
ENV_PATH="$ROOT_DIR/.env"
|
ENV_PATH="$ROOT_DIR/.env"
|
||||||
DEFAULT_ENV_PATH="$ENV_PATH"
|
|
||||||
TEMPLATE_PATH="$ROOT_DIR/.env.template"
|
TEMPLATE_PATH="$ROOT_DIR/.env.template"
|
||||||
source "$ROOT_DIR/scripts/bash/project_name.sh"
|
source "$ROOT_DIR/scripts/bash/project_name.sh"
|
||||||
source "$ROOT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
|
|
||||||
# Default project name (read from .env or template)
|
# Default project name (read from .env or template)
|
||||||
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_PATH" "$TEMPLATE_PATH")"
|
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_PATH" "$TEMPLATE_PATH")"
|
||||||
@@ -34,6 +32,7 @@ REMOTE_IDENTITY=""
|
|||||||
REMOTE_PROJECT_DIR=""
|
REMOTE_PROJECT_DIR=""
|
||||||
REMOTE_SKIP_STORAGE=0
|
REMOTE_SKIP_STORAGE=0
|
||||||
REMOTE_COPY_SOURCE=0
|
REMOTE_COPY_SOURCE=0
|
||||||
|
REMOTE_SETUP_SOURCE=""
|
||||||
REMOTE_ARGS_PROVIDED=0
|
REMOTE_ARGS_PROVIDED=0
|
||||||
REMOTE_AUTO_DEPLOY=0
|
REMOTE_AUTO_DEPLOY=0
|
||||||
REMOTE_CLEAN_CONTAINERS=0
|
REMOTE_CLEAN_CONTAINERS=0
|
||||||
@@ -48,6 +47,12 @@ MODULE_STATE_INITIALIZED=0
|
|||||||
declare -a MODULES_COMPILE_LIST=()
|
declare -a MODULES_COMPILE_LIST=()
|
||||||
declare -a COMPOSE_FILE_ARGS=()
|
declare -a COMPOSE_FILE_ARGS=()
|
||||||
|
|
||||||
|
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
|
||||||
|
info(){ printf '%b\n' "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
ok(){ printf '%b\n' "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn(){ printf '%b\n' "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
err(){ printf '%b\n' "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
show_deployment_header(){
|
show_deployment_header(){
|
||||||
printf '\n%b\n' "${BLUE}⚔️ AZEROTHCORE REALM DEPLOYMENT ⚔️${NC}"
|
printf '\n%b\n' "${BLUE}⚔️ AZEROTHCORE REALM DEPLOYMENT ⚔️${NC}"
|
||||||
printf '%b\n' "${BLUE}═══════════════════════════════════════${NC}"
|
printf '%b\n' "${BLUE}═══════════════════════════════════════${NC}"
|
||||||
@@ -257,6 +262,8 @@ Options:
|
|||||||
--remote-project-dir DIR Remote project directory (default: ~/<project-name>)
|
--remote-project-dir DIR Remote project directory (default: ~/<project-name>)
|
||||||
--remote-skip-storage Skip syncing the storage directory during migration
|
--remote-skip-storage Skip syncing the storage directory during migration
|
||||||
--remote-copy-source Copy the local project directory to remote instead of relying on git
|
--remote-copy-source Copy the local project directory to remote instead of relying on git
|
||||||
|
--remote-setup-source Automatically run setup-source.sh on remote (clone AzerothCore SQL)
|
||||||
|
--remote-skip-source-setup Skip source repository setup (you'll run manually later)
|
||||||
--remote-auto-deploy Run './deploy.sh --yes --no-watch' on the remote host after migration
|
--remote-auto-deploy Run './deploy.sh --yes --no-watch' on the remote host after migration
|
||||||
--remote-clean-containers Stop/remove remote containers & project images during migration
|
--remote-clean-containers Stop/remove remote containers & project images during migration
|
||||||
--remote-storage-path PATH Override STORAGE_PATH/STORAGE_PATH_LOCAL in the remote .env
|
--remote-storage-path PATH Override STORAGE_PATH/STORAGE_PATH_LOCAL in the remote .env
|
||||||
@@ -290,6 +297,8 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--remote-project-dir) REMOTE_PROJECT_DIR="$2"; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift 2;;
|
--remote-project-dir) REMOTE_PROJECT_DIR="$2"; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift 2;;
|
||||||
--remote-skip-storage) REMOTE_SKIP_STORAGE=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
--remote-skip-storage) REMOTE_SKIP_STORAGE=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
||||||
--remote-copy-source) REMOTE_COPY_SOURCE=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
--remote-copy-source) REMOTE_COPY_SOURCE=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
||||||
|
--remote-setup-source) REMOTE_SETUP_SOURCE=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
||||||
|
--remote-skip-source-setup) REMOTE_SETUP_SOURCE=0; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
||||||
--remote-auto-deploy) REMOTE_AUTO_DEPLOY=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
--remote-auto-deploy) REMOTE_AUTO_DEPLOY=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
||||||
--remote-clean-containers) REMOTE_CLEAN_CONTAINERS=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
--remote-clean-containers) REMOTE_CLEAN_CONTAINERS=1; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift;;
|
||||||
--remote-storage-path) REMOTE_STORAGE_OVERRIDE="$2"; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift 2;;
|
--remote-storage-path) REMOTE_STORAGE_OVERRIDE="$2"; REMOTE_MODE=1; REMOTE_ARGS_PROVIDED=1; shift 2;;
|
||||||
@@ -307,6 +316,10 @@ if [ "$REMOTE_CLEAN_CONTAINERS" -eq 1 ] && [ "$REMOTE_PRESERVE_CONTAINERS" -eq 1
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
require_cmd(){
|
||||||
|
command -v "$1" >/dev/null 2>&1 || { err "Missing required command: $1"; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
require_cmd docker
|
require_cmd docker
|
||||||
require_cmd python3
|
require_cmd python3
|
||||||
|
|
||||||
@@ -332,6 +345,18 @@ if [ "$REMOTE_MODE" -eq 1 ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
read_env(){
|
||||||
|
local key="$1" default="${2:-}"
|
||||||
|
local value=""
|
||||||
|
if [ -f "$ENV_PATH" ]; then
|
||||||
|
value="$(grep -E "^${key}=" "$ENV_PATH" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$default"
|
||||||
|
fi
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
init_compose_files(){
|
init_compose_files(){
|
||||||
compose_overrides::build_compose_args "$ROOT_DIR" "$ENV_PATH" "$DEFAULT_COMPOSE_FILE" COMPOSE_FILE_ARGS
|
compose_overrides::build_compose_args "$ROOT_DIR" "$ENV_PATH" "$DEFAULT_COMPOSE_FILE" COMPOSE_FILE_ARGS
|
||||||
}
|
}
|
||||||
@@ -734,6 +759,10 @@ run_remote_migration(){
|
|||||||
args+=(--env-file "$REMOTE_ENV_FILE")
|
args+=(--env-file "$REMOTE_ENV_FILE")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$REMOTE_SETUP_SOURCE" ]; then
|
||||||
|
args+=(--setup-source "$REMOTE_SETUP_SOURCE")
|
||||||
|
fi
|
||||||
|
|
||||||
(cd "$ROOT_DIR" && ./scripts/bash/migrate-stack.sh "${args[@]}")
|
(cd "$ROOT_DIR" && ./scripts/bash/migrate-stack.sh "${args[@]}")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,6 +900,24 @@ apply_server_config(){
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_realmlist(){
|
||||||
|
info "Updating realmlist in database with current SERVER_ADDRESS and REALM_PORT..."
|
||||||
|
|
||||||
|
local update_script="$ROOT_DIR/scripts/bash/update-realmlist.sh"
|
||||||
|
if [ ! -x "$update_script" ]; then
|
||||||
|
warn "Realmlist update script not found or not executable: $update_script"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the update script
|
||||||
|
if bash "$update_script"; then
|
||||||
|
ok "Realmlist updated successfully"
|
||||||
|
else
|
||||||
|
warn "Could not update realmlist - this is normal if database is still initializing"
|
||||||
|
info "The realmlist will be updated on next deployment or you can run: ./scripts/bash/update-realmlist.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
main(){
|
main(){
|
||||||
if [ "$ASSUME_YES" -ne 1 ]; then
|
if [ "$ASSUME_YES" -ne 1 ]; then
|
||||||
if [ -t 0 ]; then
|
if [ -t 0 ]; then
|
||||||
@@ -927,29 +974,32 @@ main(){
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
show_step 1 4 "Checking build requirements"
|
show_step 1 7 "Checking build requirements"
|
||||||
if ! prompt_build_if_needed; then
|
if ! prompt_build_if_needed; then
|
||||||
err "Build required but not completed. Deployment cancelled."
|
err "Build required but not completed. Deployment cancelled."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$KEEP_RUNNING" -ne 1 ]; then
|
if [ "$KEEP_RUNNING" -ne 1 ]; then
|
||||||
show_step 2 4 "Stopping runtime stack"
|
show_step 2 7 "Stopping runtime stack"
|
||||||
stop_runtime_stack
|
stop_runtime_stack
|
||||||
fi
|
fi
|
||||||
|
|
||||||
show_step 3 5 "Importing user database files"
|
show_step 3 7 "Importing user database files"
|
||||||
info "Checking for database files in ./import/db/ and ./database-import/"
|
info "Checking for database files in ./import/db/ and ./database-import/"
|
||||||
bash "$ROOT_DIR/scripts/bash/import-database-files.sh"
|
bash "$ROOT_DIR/scripts/bash/import-database-files.sh"
|
||||||
|
|
||||||
show_step 4 6 "Bringing your realm online"
|
show_step 4 7 "Bringing your realm online"
|
||||||
info "Pulling images and waiting for containers to become healthy; this may take a few minutes on first deploy."
|
info "Pulling images and waiting for containers to become healthy; this may take a few minutes on first deploy."
|
||||||
stage_runtime
|
stage_runtime
|
||||||
|
|
||||||
show_step 5 6 "Applying server configuration"
|
show_step 5 7 "Applying server configuration"
|
||||||
apply_server_config
|
apply_server_config
|
||||||
|
|
||||||
show_step 6 6 "Finalizing deployment"
|
show_step 6 7 "Updating realmlist"
|
||||||
|
update_realmlist
|
||||||
|
|
||||||
|
show_step 7 7 "Finalizing deployment"
|
||||||
mark_deployment_complete
|
mark_deployment_complete
|
||||||
|
|
||||||
show_realm_ready
|
show_realm_ready
|
||||||
|
|||||||
@@ -199,7 +199,32 @@ The remote deployment process transfers:
|
|||||||
- ✅ Docker images (exported to `local-storage/images/`)
|
- ✅ Docker images (exported to `local-storage/images/`)
|
||||||
- ✅ Project files (scripts, configs, docker-compose.yml, .env)
|
- ✅ Project files (scripts, configs, docker-compose.yml, .env)
|
||||||
- ✅ Storage directory (unless `--remote-skip-storage` is used)
|
- ✅ Storage directory (unless `--remote-skip-storage` is used)
|
||||||
- ❌ Build artifacts (source code, compilation files stay local)
|
- ❌ AzerothCore source repository (must be set up separately - see below)
|
||||||
|
|
||||||
|
**IMPORTANT: AzerothCore Source Setup**
|
||||||
|
|
||||||
|
The AzerothCore source repository (~2GB) is NOT synced during migration to avoid slow transfers. However, it's **required** for database initialization.
|
||||||
|
|
||||||
|
**Option 1: Automatic Setup (Recommended)**
|
||||||
|
|
||||||
|
Use the `--remote-setup-source` flag to automatically clone the source on the remote host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh --remote-host your-server --remote-user youruser --remote-setup-source
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: Manual Setup**
|
||||||
|
|
||||||
|
After migration completes, SSH to the remote host and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh your-server
|
||||||
|
cd ~/AzerothCore-RealmMaster # or your custom project directory
|
||||||
|
./scripts/bash/setup-source.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Without this step, database initialization will fail with:**
|
||||||
|
`❌ FATAL: SQL source directory not found`
|
||||||
|
|
||||||
### Module Presets
|
### Module Presets
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,21 @@ ls storage/config/mod_*.conf*
|
|||||||
|
|
||||||
**Database connection issues**
|
**Database connection issues**
|
||||||
```bash
|
```bash
|
||||||
|
# Check if source repository is set up (common issue after remote deployment)
|
||||||
|
ls -la local-storage/source/azerothcore*/data/sql/base/db_world/
|
||||||
|
|
||||||
|
# If empty or missing, set up source:
|
||||||
|
./scripts/bash/setup-source.sh
|
||||||
|
|
||||||
|
# Then restart database import:
|
||||||
|
docker compose run --rm ac-db-import
|
||||||
|
|
||||||
|
# Error: "SQL source directory not found"
|
||||||
|
# This means the AzerothCore source repository hasn't been cloned.
|
||||||
|
# Solution: Run ./scripts/bash/setup-source.sh
|
||||||
|
# See docs/GETTING_STARTED.md for details
|
||||||
|
|
||||||
|
# Legacy database issues:
|
||||||
# Verify MySQL is running and responsive
|
# Verify MySQL is running and responsive
|
||||||
docker exec ac-mysql mysql -u root -p -e "SELECT 1;"
|
docker exec ac-mysql mysql -u root -p -e "SELECT 1;"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ INVOCATION_DIR="$PWD"
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
source "$SCRIPT_DIR/lib/common.sh"
|
|
||||||
|
|
||||||
# Load environment defaults if present
|
# Load environment defaults if present
|
||||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||||
@@ -64,7 +63,8 @@ Examples:
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
die(){ fatal "$1"; }
|
err(){ printf 'Error: %s\n' "$*" >&2; }
|
||||||
|
die(){ err "$1"; exit 1; }
|
||||||
|
|
||||||
normalize_token(){
|
normalize_token(){
|
||||||
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'
|
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'
|
||||||
|
|||||||
@@ -6,7 +6,15 @@ INVOCATION_DIR="$PWD"
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
source "$SCRIPT_DIR/lib/common.sh"
|
COLOR_RED='\033[0;31m'
|
||||||
|
COLOR_GREEN='\033[0;32m'
|
||||||
|
COLOR_YELLOW='\033[1;33m'
|
||||||
|
COLOR_RESET='\033[0m'
|
||||||
|
|
||||||
|
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
|
||||||
|
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
|
||||||
|
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
|
||||||
|
fatal(){ err "$*"; exit 1; }
|
||||||
|
|
||||||
SUPPORTED_DBS=(auth characters world)
|
SUPPORTED_DBS=(auth characters world)
|
||||||
declare -A SUPPORTED_SET=()
|
declare -A SUPPORTED_SET=()
|
||||||
|
|||||||
@@ -6,7 +6,18 @@ set -euo pipefail
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
source "$SCRIPT_DIR/lib/common.sh"
|
COLOR_RED='\033[0;31m'
|
||||||
|
COLOR_GREEN='\033[0;32m'
|
||||||
|
COLOR_YELLOW='\033[1;33m'
|
||||||
|
COLOR_BLUE='\033[0;34m'
|
||||||
|
COLOR_CYAN='\033[0;36m'
|
||||||
|
COLOR_RESET='\033[0m'
|
||||||
|
|
||||||
|
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
|
||||||
|
info(){ printf '%b\n' "${COLOR_CYAN}$*${COLOR_RESET}"; }
|
||||||
|
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
|
||||||
|
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
|
||||||
|
fatal(){ err "$*"; exit 1; }
|
||||||
|
|
||||||
MYSQL_PW=""
|
MYSQL_PW=""
|
||||||
BACKUP_DIR=""
|
BACKUP_DIR=""
|
||||||
|
|||||||
@@ -153,8 +153,33 @@ if [ -f "$RESTORE_SUCCESS_MARKER" ]; then
|
|||||||
if verify_databases_populated; then
|
if verify_databases_populated; then
|
||||||
echo "✅ Backup restoration completed successfully"
|
echo "✅ Backup restoration completed successfully"
|
||||||
cat "$RESTORE_SUCCESS_MARKER" || true
|
cat "$RESTORE_SUCCESS_MARKER" || true
|
||||||
echo "🚫 Skipping database import - data already restored from backup"
|
|
||||||
exit 0
|
# Check if there are pending module SQL updates to apply
|
||||||
|
echo "🔍 Checking for pending module SQL updates..."
|
||||||
|
local has_pending_updates=0
|
||||||
|
|
||||||
|
# Check if module SQL staging directory has files
|
||||||
|
if [ -d "/azerothcore/data/sql/updates/db_world" ] && [ -n "$(find /azerothcore/data/sql/updates/db_world -name 'MODULE_*.sql' -type f 2>/dev/null)" ]; then
|
||||||
|
echo " ⚠️ Found staged module SQL updates that may need application"
|
||||||
|
has_pending_updates=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$has_pending_updates" -eq 0 ]; then
|
||||||
|
echo "🚫 Skipping database import - data already restored and no pending updates"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📦 Running dbimport to apply pending module SQL updates..."
|
||||||
|
cd /azerothcore/env/dist/bin
|
||||||
|
seed_dbimport_conf
|
||||||
|
|
||||||
|
if ./dbimport; then
|
||||||
|
echo "✅ Module SQL updates applied successfully!"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "⚠️ dbimport reported issues - check logs for details"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "⚠️ Restoration marker found, but databases are empty - forcing re-import"
|
echo "⚠️ Restoration marker found, but databases are empty - forcing re-import"
|
||||||
@@ -470,6 +495,65 @@ echo "🚀 Running database import..."
|
|||||||
cd /azerothcore/env/dist/bin
|
cd /azerothcore/env/dist/bin
|
||||||
seed_dbimport_conf
|
seed_dbimport_conf
|
||||||
|
|
||||||
|
validate_sql_source(){
|
||||||
|
local sql_base_dir="/azerothcore/data/sql/base"
|
||||||
|
local required_dirs=("db_auth" "db_world" "db_characters")
|
||||||
|
local missing_dirs=()
|
||||||
|
|
||||||
|
echo "🔍 Validating SQL source availability..."
|
||||||
|
|
||||||
|
if [ ! -d "$sql_base_dir" ]; then
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
❌ FATAL: SQL source directory not found at $sql_base_dir
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
The AzerothCore source repository is not mounted or doesn't exist.
|
||||||
|
This directory should contain SQL schemas for database initialization.
|
||||||
|
|
||||||
|
📋 REMEDIATION STEPS:
|
||||||
|
|
||||||
|
1. SSH to this host:
|
||||||
|
ssh $(whoami)@$(hostname)
|
||||||
|
|
||||||
|
2. Navigate to project directory and run source setup:
|
||||||
|
cd $PROJECT_ROOT && ./scripts/bash/setup-source.sh
|
||||||
|
|
||||||
|
3. Restart database import:
|
||||||
|
docker compose run --rm ac-db-import
|
||||||
|
|
||||||
|
📦 ALTERNATIVE (Prebuilt Images):
|
||||||
|
|
||||||
|
If using Docker images with bundled SQL schemas:
|
||||||
|
- Set AC_SQL_SOURCE_PATH in .env to point to bundled location
|
||||||
|
- Example: AC_SQL_SOURCE_PATH=/bundled/sql
|
||||||
|
|
||||||
|
📚 Documentation: docs/GETTING_STARTED.md#database-setup
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for dir in "${required_dirs[@]}"; do
|
||||||
|
local full_path="$sql_base_dir/$dir"
|
||||||
|
if [ ! -d "$full_path" ] || [ -z "$(ls -A "$full_path" 2>/dev/null)" ]; then
|
||||||
|
missing_dirs+=("$dir")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing_dirs[@]} -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "❌ FATAL: SQL source directories are empty or missing:"
|
||||||
|
printf ' - %s\n' "${missing_dirs[@]}"
|
||||||
|
echo ""
|
||||||
|
echo "The AzerothCore source directory exists but hasn't been populated with SQL files."
|
||||||
|
echo "Run './scripts/bash/setup-source.sh' on the host to clone and populate the repository."
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ SQL source validation passed - all required schemas present"
|
||||||
|
}
|
||||||
|
|
||||||
maybe_run_base_import(){
|
maybe_run_base_import(){
|
||||||
local mysql_host="${CONTAINER_MYSQL:-ac-mysql}"
|
local mysql_host="${CONTAINER_MYSQL:-ac-mysql}"
|
||||||
local mysql_port="${MYSQL_PORT:-3306}"
|
local mysql_port="${MYSQL_PORT:-3306}"
|
||||||
@@ -506,6 +590,8 @@ maybe_run_base_import(){
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Validate SQL source is available before attempting import
|
||||||
|
validate_sql_source
|
||||||
maybe_run_base_import
|
maybe_run_base_import
|
||||||
if ./dbimport; then
|
if ./dbimport; then
|
||||||
echo "✅ Database import completed successfully!"
|
echo "✅ Database import completed successfully!"
|
||||||
|
|||||||
@@ -9,16 +9,35 @@ ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|||||||
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
||||||
ENV_FILE="$ROOT_DIR/.env"
|
ENV_FILE="$ROOT_DIR/.env"
|
||||||
TEMPLATE_FILE="$ROOT_DIR/.env.template"
|
TEMPLATE_FILE="$ROOT_DIR/.env.template"
|
||||||
ENV_PATH="$ENV_FILE"
|
|
||||||
DEFAULT_ENV_PATH="$ENV_FILE"
|
|
||||||
source "$ROOT_DIR/scripts/bash/project_name.sh"
|
source "$ROOT_DIR/scripts/bash/project_name.sh"
|
||||||
source "$ROOT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
|
|
||||||
# Default project name (read from .env or template)
|
# Default project name (read from .env or template)
|
||||||
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_FILE" "$TEMPLATE_FILE")"
|
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_FILE" "$TEMPLATE_FILE")"
|
||||||
source "$ROOT_DIR/scripts/bash/compose_overrides.sh"
|
source "$ROOT_DIR/scripts/bash/compose_overrides.sh"
|
||||||
declare -a COMPOSE_FILE_ARGS=()
|
declare -a COMPOSE_FILE_ARGS=()
|
||||||
|
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
info(){ echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
ok(){ echo -e "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
err(){ echo -e "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
|
read_env(){
|
||||||
|
local key="$1" default="${2:-}" value=""
|
||||||
|
if [ -f "$ENV_FILE" ]; then
|
||||||
|
value="$(grep -E "^${key}=" "$ENV_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$default"
|
||||||
|
fi
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
resolve_project_name(){
|
resolve_project_name(){
|
||||||
local raw_name sanitized
|
local raw_name sanitized
|
||||||
raw_name="$(read_env COMPOSE_PROJECT_NAME "$DEFAULT_PROJECT_NAME")"
|
raw_name="$(read_env COMPOSE_PROJECT_NAME "$DEFAULT_PROJECT_NAME")"
|
||||||
@@ -41,6 +60,13 @@ show_header(){
|
|||||||
echo -e "${BLUE} 📊 Enabling Management UIs 📊${NC}\n"
|
echo -e "${BLUE} 📊 Enabling Management UIs 📊${NC}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_command(){
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
err "Required command '$1' not found in PATH."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
ensure_mysql_running(){
|
ensure_mysql_running(){
|
||||||
local mysql_service="ac-mysql"
|
local mysql_service="ac-mysql"
|
||||||
local mysql_container
|
local mysql_container
|
||||||
@@ -82,7 +108,7 @@ EOF
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
require_cmd docker
|
ensure_command docker
|
||||||
docker info >/dev/null 2>&1 || { err "Docker daemon unavailable."; exit 1; }
|
docker info >/dev/null 2>&1 || { err "Docker daemon unavailable."; exit 1; }
|
||||||
|
|
||||||
PROJECT_NAME="$(resolve_project_name)"
|
PROJECT_NAME="$(resolve_project_name)"
|
||||||
|
|||||||
@@ -6,7 +6,17 @@ INVOCATION_DIR="$PWD"
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
cd "$SCRIPT_DIR/../.." # Go to project root
|
cd "$SCRIPT_DIR/../.." # Go to project root
|
||||||
|
|
||||||
source "$SCRIPT_DIR/lib/common.sh"
|
COLOR_RED='\033[0;31m'
|
||||||
|
COLOR_GREEN='\033[0;32m'
|
||||||
|
COLOR_YELLOW='\033[1;33m'
|
||||||
|
COLOR_BLUE='\033[0;34m'
|
||||||
|
COLOR_RESET='\033[0m'
|
||||||
|
|
||||||
|
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
|
||||||
|
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
|
||||||
|
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
|
||||||
|
info(){ printf '%b\n' "${COLOR_BLUE}$*${COLOR_RESET}"; }
|
||||||
|
fatal(){ err "$*"; exit 1; }
|
||||||
|
|
||||||
# Source environment variables
|
# Source environment variables
|
||||||
if [ -f ".env" ]; then
|
if [ -f ".env" ]; then
|
||||||
@@ -270,4 +280,4 @@ if [[ $processed -gt 0 ]]; then
|
|||||||
log ""
|
log ""
|
||||||
log "Character imports completed! Processed files moved to $IMPORT_DIR/processed/"
|
log "Character imports completed! Processed files moved to $IMPORT_DIR/processed/"
|
||||||
log "You can now log in and access your imported characters."
|
log "You can now log in and access your imported characters."
|
||||||
fi
|
fi
|
||||||
96
scripts/bash/install-docker-nfs-fix.sh
Normal file
96
scripts/bash/install-docker-nfs-fix.sh
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# AzerothCore RealmMaster - Install Docker NFS Dependencies Fix
|
||||||
|
# This script installs a systemd drop-in configuration to ensure Docker
|
||||||
|
# waits for NFS mounts before starting, preventing backup folder deletion issues
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
DROP_IN_SOURCE="$PROJECT_ROOT/config/systemd/docker.service.d/nfs-dependencies.conf"
|
||||||
|
DROP_IN_TARGET="/etc/systemd/system/docker.service.d/nfs-dependencies.conf"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
log_info() { echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
log_ok() { echo -e "${GREEN}✅ $*${NC}"; }
|
||||||
|
log_warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
log_err() { echo -e "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
log_err "This script must be run as root (use sudo)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if source file exists
|
||||||
|
if [ ! -f "$DROP_IN_SOURCE" ]; then
|
||||||
|
log_err "Source configuration file not found: $DROP_IN_SOURCE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if NFS mounts exist
|
||||||
|
log_info "Checking NFS mount configuration..."
|
||||||
|
if ! systemctl list-units --type=mount | grep -q "nfs-azerothcore.mount"; then
|
||||||
|
log_warn "nfs-azerothcore.mount not found. This fix requires NFS mounts to be configured."
|
||||||
|
log_warn "Continue anyway? (y/n)"
|
||||||
|
read -r response
|
||||||
|
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||||
|
log_info "Installation cancelled."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create drop-in directory
|
||||||
|
log_info "Creating systemd drop-in directory..."
|
||||||
|
mkdir -p "$(dirname "$DROP_IN_TARGET")"
|
||||||
|
log_ok "Drop-in directory ready: $(dirname "$DROP_IN_TARGET")"
|
||||||
|
|
||||||
|
# Install configuration file
|
||||||
|
log_info "Installing NFS dependencies configuration..."
|
||||||
|
cp "$DROP_IN_SOURCE" "$DROP_IN_TARGET"
|
||||||
|
chmod 644 "$DROP_IN_TARGET"
|
||||||
|
log_ok "Configuration installed: $DROP_IN_TARGET"
|
||||||
|
|
||||||
|
# Show what was installed
|
||||||
|
echo ""
|
||||||
|
log_info "Installed configuration:"
|
||||||
|
echo "---"
|
||||||
|
cat "$DROP_IN_TARGET"
|
||||||
|
echo "---"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Reload systemd
|
||||||
|
log_info "Reloading systemd daemon..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
log_ok "Systemd daemon reloaded"
|
||||||
|
|
||||||
|
# Verify configuration
|
||||||
|
log_info "Verifying Docker service dependencies..."
|
||||||
|
echo ""
|
||||||
|
systemctl show -p After,Requires,Wants docker.service | grep -E '^(After|Requires|Wants)='
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if Docker is running
|
||||||
|
if systemctl is-active --quiet docker.service; then
|
||||||
|
log_warn "Docker is currently running"
|
||||||
|
log_warn "The new configuration will take effect on next Docker restart or system reboot"
|
||||||
|
echo ""
|
||||||
|
log_info "To apply immediately, restart Docker (WARNING: will stop all containers):"
|
||||||
|
echo " sudo systemctl restart docker.service"
|
||||||
|
echo ""
|
||||||
|
log_info "Or reboot the system:"
|
||||||
|
echo " sudo reboot"
|
||||||
|
else
|
||||||
|
log_ok "Docker is not running - configuration will apply on next start"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_ok "Docker NFS dependencies fix installed successfully!"
|
||||||
|
log_info "Docker will now wait for NFS mounts before starting"
|
||||||
|
log_info "This prevents backup folders from being deleted during server restarts"
|
||||||
@@ -127,23 +127,17 @@ read_env() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Read value from .env.template file (used during setup)
|
# Read value from .env.template file (used during setup)
|
||||||
# This is similar to read_env but specifically for template files.
|
# This is similar to read_env but specifically for template files
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# get_template_value KEY [TEMPLATE_FILE] [DEFAULT]
|
# get_template_value KEY [TEMPLATE_FILE]
|
||||||
# value=$(get_template_value "MYSQL_PASSWORD")
|
# value=$(get_template_value "MYSQL_PASSWORD")
|
||||||
# value=$(get_template_value "DOCKER_IMAGE_TAG" ".env.template" "latest")
|
|
||||||
#
|
#
|
||||||
get_template_value() {
|
get_template_value() {
|
||||||
local key="$1"
|
local key="$1"
|
||||||
local template_file="${2:-${TEMPLATE_FILE:-${TEMPLATE_PATH:-.env.template}}}"
|
local template_file="${2:-${TEMPLATE_FILE:-${TEMPLATE_PATH:-.env.template}}}"
|
||||||
local fallback="${3:-}"
|
|
||||||
|
|
||||||
if [ ! -f "$template_file" ]; then
|
if [ ! -f "$template_file" ]; then
|
||||||
if [ -n "$fallback" ]; then
|
|
||||||
echo "$fallback"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fatal "Template file not found: $template_file"
|
fatal "Template file not found: $template_file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -153,11 +147,8 @@ get_template_value() {
|
|||||||
raw_line=$(grep "^${key}=" "$template_file" 2>/dev/null | head -1)
|
raw_line=$(grep "^${key}=" "$template_file" 2>/dev/null | head -1)
|
||||||
|
|
||||||
if [ -z "$raw_line" ]; then
|
if [ -z "$raw_line" ]; then
|
||||||
if [ -n "$fallback" ]; then
|
err "Key '$key' not found in template: $template_file"
|
||||||
echo "$fallback"
|
return 1
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fatal "Key '$key' not found in template: $template_file"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
value="${raw_line#*=}"
|
value="${raw_line#*=}"
|
||||||
@@ -168,10 +159,6 @@ get_template_value() {
|
|||||||
value="${BASH_REMATCH[1]}"
|
value="${BASH_REMATCH[1]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$value" ] && [ -n "$fallback" ]; then
|
|
||||||
value="$fallback"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$value"
|
echo "$value"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ Options:
|
|||||||
--port PORT SSH port (default: 22)
|
--port PORT SSH port (default: 22)
|
||||||
--identity PATH SSH private key (passed to scp/ssh)
|
--identity PATH SSH private key (passed to scp/ssh)
|
||||||
--project-dir DIR Remote project directory (default: ~/<project-name>)
|
--project-dir DIR Remote project directory (default: ~/<project-name>)
|
||||||
|
--setup-source 0|1 Auto-setup AzerothCore source on remote (0=skip, 1=setup, unset=prompt)
|
||||||
--env-file PATH Use this env file for image lookup and upload (default: ./.env)
|
--env-file PATH Use this env file for image lookup and upload (default: ./.env)
|
||||||
--tarball PATH Output path for the image tar (default: ./local-storage/images/acore-modules-images.tar)
|
--tarball PATH Output path for the image tar (default: ./local-storage/images/acore-modules-images.tar)
|
||||||
--storage PATH Remote storage directory (default: <project-dir>/storage)
|
--storage PATH Remote storage directory (default: <project-dir>/storage)
|
||||||
@@ -168,6 +169,7 @@ SKIP_STORAGE=0
|
|||||||
ASSUME_YES=0
|
ASSUME_YES=0
|
||||||
COPY_SOURCE=0
|
COPY_SOURCE=0
|
||||||
SKIP_ENV=0
|
SKIP_ENV=0
|
||||||
|
REMOTE_SETUP_SOURCE=""
|
||||||
PRESERVE_CONTAINERS=0
|
PRESERVE_CONTAINERS=0
|
||||||
CLEAN_CONTAINERS=0
|
CLEAN_CONTAINERS=0
|
||||||
|
|
||||||
@@ -181,6 +183,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--env-file) ENV_FILE="$2"; shift 2;;
|
--env-file) ENV_FILE="$2"; shift 2;;
|
||||||
--tarball) TARBALL="$2"; shift 2;;
|
--tarball) TARBALL="$2"; shift 2;;
|
||||||
--storage) REMOTE_STORAGE="$2"; shift 2;;
|
--storage) REMOTE_STORAGE="$2"; shift 2;;
|
||||||
|
--setup-source) REMOTE_SETUP_SOURCE="$2"; shift 2;;
|
||||||
--skip-storage) SKIP_STORAGE=1; shift;;
|
--skip-storage) SKIP_STORAGE=1; shift;;
|
||||||
--skip-env) SKIP_ENV=1; shift;;
|
--skip-env) SKIP_ENV=1; shift;;
|
||||||
--preserve-containers) PRESERVE_CONTAINERS=1; shift;;
|
--preserve-containers) PRESERVE_CONTAINERS=1; shift;;
|
||||||
@@ -253,7 +256,15 @@ STAGE_SQL_PATH_RAW="$(read_env_value STAGE_PATH_MODULE_SQL "${LOCAL_STORAGE_ROOT
|
|||||||
if [ -z "${STORAGE_PATH_LOCAL:-}" ]; then
|
if [ -z "${STORAGE_PATH_LOCAL:-}" ]; then
|
||||||
STORAGE_PATH_LOCAL="$LOCAL_STORAGE_ROOT"
|
STORAGE_PATH_LOCAL="$LOCAL_STORAGE_ROOT"
|
||||||
fi
|
fi
|
||||||
# Expand any env references (e.g., ${STORAGE_PATH_LOCAL})
|
# Ensure STORAGE_PATH is defined to avoid set -u failures during expansion
|
||||||
|
if [ -z "${STORAGE_PATH:-}" ]; then
|
||||||
|
STORAGE_PATH="$(read_env_value STORAGE_PATH "./storage")"
|
||||||
|
fi
|
||||||
|
# Ensure STORAGE_MODULE_SQL_PATH is defined to avoid set -u failures during expansion
|
||||||
|
if [ -z "${STORAGE_MODULE_SQL_PATH:-}" ]; then
|
||||||
|
STORAGE_MODULE_SQL_PATH="$(read_env_value STORAGE_MODULE_SQL_PATH "${STORAGE_PATH}/module-sql-updates")"
|
||||||
|
fi
|
||||||
|
# Expand any env references (e.g., ${STORAGE_PATH_LOCAL}, ${STORAGE_MODULE_SQL_PATH})
|
||||||
STAGE_SQL_PATH_RAW="$(eval "echo \"$STAGE_SQL_PATH_RAW\"")"
|
STAGE_SQL_PATH_RAW="$(eval "echo \"$STAGE_SQL_PATH_RAW\"")"
|
||||||
LOCAL_STAGE_SQL_DIR="$(resolve_path_relative_to_project "$STAGE_SQL_PATH_RAW" "$PROJECT_ROOT")"
|
LOCAL_STAGE_SQL_DIR="$(resolve_path_relative_to_project "$STAGE_SQL_PATH_RAW" "$PROJECT_ROOT")"
|
||||||
REMOTE_STAGE_SQL_DIR="$(resolve_path_relative_to_project "$STAGE_SQL_PATH_RAW" "$PROJECT_DIR")"
|
REMOTE_STAGE_SQL_DIR="$(resolve_path_relative_to_project "$STAGE_SQL_PATH_RAW" "$PROJECT_DIR")"
|
||||||
@@ -438,6 +449,76 @@ setup_remote_repository(){
|
|||||||
echo " • Repository synchronized ✓"
|
echo " • Repository synchronized ✓"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_source_if_needed(){
|
||||||
|
local should_setup="${REMOTE_SETUP_SOURCE:-}"
|
||||||
|
|
||||||
|
# Check if source already exists and is populated
|
||||||
|
echo " • Checking for existing AzerothCore source repository..."
|
||||||
|
if run_ssh "[ -d '$PROJECT_DIR/local-storage/source/azerothcore-playerbots/data/sql/base/db_world' ] && [ -n \"\$(ls -A '$PROJECT_DIR/local-storage/source/azerothcore-playerbots/data/sql/base/db_world' 2>/dev/null)\" ]" 2>/dev/null; then
|
||||||
|
echo " ✅ Source repository already populated on remote"
|
||||||
|
return 0
|
||||||
|
elif run_ssh "[ -d '$PROJECT_DIR/local-storage/source/azerothcore/data/sql/base/db_world' ] && [ -n \"\$(ls -A '$PROJECT_DIR/local-storage/source/azerothcore/data/sql/base/db_world' 2>/dev/null)\" ]" 2>/dev/null; then
|
||||||
|
echo " ✅ Source repository already populated on remote"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " ⚠️ Source repository not found or empty on remote"
|
||||||
|
|
||||||
|
# If not set, ask user (unless --yes)
|
||||||
|
if [ -z "$should_setup" ]; then
|
||||||
|
if [ "$ASSUME_YES" = "1" ]; then
|
||||||
|
# Auto-yes in non-interactive: default to YES for safety
|
||||||
|
echo " ℹ️ Auto-confirming source setup (--yes flag)"
|
||||||
|
should_setup=1
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "📦 AzerothCore Source Repository Setup"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
echo "The remote server needs AzerothCore source code for database schemas."
|
||||||
|
echo "This will clone ~2GB repository (one-time operation, takes 2-5 minutes)."
|
||||||
|
echo ""
|
||||||
|
echo "Without this, database initialization will FAIL."
|
||||||
|
echo ""
|
||||||
|
read -rp "Set up source repository now? [Y/n]: " answer
|
||||||
|
answer="${answer:-Y}"
|
||||||
|
case "${answer,,}" in
|
||||||
|
y|yes) should_setup=1 ;;
|
||||||
|
*) should_setup=0 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$should_setup" != "1" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "⚠️ WARNING: Source setup skipped"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
echo "You MUST run this manually on the remote host BEFORE starting services:"
|
||||||
|
echo ""
|
||||||
|
echo " ssh $USER@$HOST"
|
||||||
|
echo " cd $PROJECT_DIR"
|
||||||
|
echo " ./scripts/bash/setup-source.sh"
|
||||||
|
echo ""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " 🔧 Setting up AzerothCore source repository on remote..."
|
||||||
|
echo " ⏳ Cloning AzerothCore (this may take 2-5 minutes)..."
|
||||||
|
|
||||||
|
# Run setup-source.sh on remote, capturing output
|
||||||
|
if run_ssh "cd '$PROJECT_DIR' && ./scripts/bash/setup-source.sh" 2>&1 | sed 's/^/ /'; then
|
||||||
|
echo " ✅ Source repository setup complete"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo " ❌ Source setup failed (check output above for details)"
|
||||||
|
echo " ⚠️ Run manually: ssh $USER@$HOST 'cd $PROJECT_DIR && ./scripts/bash/setup-source.sh'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
cleanup_stale_docker_resources(){
|
cleanup_stale_docker_resources(){
|
||||||
if [ "$PRESERVE_CONTAINERS" -eq 1 ]; then
|
if [ "$PRESERVE_CONTAINERS" -eq 1 ]; then
|
||||||
echo "⋅ Skipping remote container/image cleanup (--preserve-containers)"
|
echo "⋅ Skipping remote container/image cleanup (--preserve-containers)"
|
||||||
@@ -469,6 +550,9 @@ cleanup_stale_docker_resources(){
|
|||||||
|
|
||||||
validate_remote_environment
|
validate_remote_environment
|
||||||
|
|
||||||
|
# Set up source repository if needed (after project files are synced)
|
||||||
|
setup_source_if_needed || true # Don't fail entire deployment if source setup fails
|
||||||
|
|
||||||
collect_deploy_image_refs
|
collect_deploy_image_refs
|
||||||
|
|
||||||
echo "⋅ Exporting deployment images to $TARBALL"
|
echo "⋅ Exporting deployment images to $TARBALL"
|
||||||
|
|||||||
@@ -6,7 +6,17 @@ INVOCATION_DIR="$PWD"
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
source "$SCRIPT_DIR/lib/common.sh"
|
COLOR_RED='\033[0;31m'
|
||||||
|
COLOR_GREEN='\033[0;32m'
|
||||||
|
COLOR_YELLOW='\033[1;33m'
|
||||||
|
COLOR_BLUE='\033[0;34m'
|
||||||
|
COLOR_RESET='\033[0m'
|
||||||
|
|
||||||
|
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
|
||||||
|
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
|
||||||
|
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
|
||||||
|
info(){ printf '%b\n' "${COLOR_BLUE}$*${COLOR_RESET}"; }
|
||||||
|
fatal(){ err "$*"; exit 1; }
|
||||||
|
|
||||||
MYSQL_PW=""
|
MYSQL_PW=""
|
||||||
PDUMP_FILE=""
|
PDUMP_FILE=""
|
||||||
@@ -331,4 +341,4 @@ log "Import completed successfully!"
|
|||||||
log "Characters on account $TARGET_ACCOUNT: $CHARACTER_COUNT"
|
log "Characters on account $TARGET_ACCOUNT: $CHARACTER_COUNT"
|
||||||
[[ -n "$BACKUP_FILE" ]] && log "Backup created: $BACKUP_FILE"
|
[[ -n "$BACKUP_FILE" ]] && log "Backup created: $BACKUP_FILE"
|
||||||
|
|
||||||
info "Character import from pdump completed. You can now log in and play!"
|
info "Character import from pdump completed. You can now log in and play!"
|
||||||
@@ -8,18 +8,15 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
ENV_FILE="$PROJECT_DIR/.env"
|
ENV_FILE="$PROJECT_DIR/.env"
|
||||||
TEMPLATE_FILE="$PROJECT_DIR/.env.template"
|
TEMPLATE_FILE="$PROJECT_DIR/.env.template"
|
||||||
ENV_PATH="$ENV_FILE"
|
|
||||||
DEFAULT_ENV_PATH="$ENV_FILE"
|
|
||||||
source "$PROJECT_DIR/scripts/bash/project_name.sh"
|
source "$PROJECT_DIR/scripts/bash/project_name.sh"
|
||||||
source "$PROJECT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
|
|
||||||
# Default project name (read from .env or template)
|
# Default project name (read from .env or template)
|
||||||
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_FILE" "$TEMPLATE_FILE")"
|
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_FILE" "$TEMPLATE_FILE")"
|
||||||
|
|
||||||
BLUE="${BLUE:-\033[0;34m}"
|
BLUE='\033[0;34m'
|
||||||
GREEN="${GREEN:-\033[0;32m}"
|
GREEN='\033[0;32m'
|
||||||
YELLOW="${YELLOW:-\033[1;33m}"
|
YELLOW='\033[1;33m'
|
||||||
NC="${NC:-\033[0m}"
|
NC='\033[0m'
|
||||||
|
|
||||||
show_rebuild_step(){
|
show_rebuild_step(){
|
||||||
local step="$1" total="$2" message="$3"
|
local step="$1" total="$2" message="$3"
|
||||||
@@ -38,6 +35,33 @@ Options:
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_env(){
|
||||||
|
local key="$1" default="$2" env_path="$ENV_FILE" value
|
||||||
|
if [ -f "$env_path" ]; then
|
||||||
|
value="$(grep -E "^${key}=" "$env_path" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="${!key:-}"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$default"
|
||||||
|
fi
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_env_value(){
|
||||||
|
local key="$1" value="$2" env_file="$ENV_FILE"
|
||||||
|
[ -n "$env_file" ] || return 0
|
||||||
|
if [ ! -f "$env_file" ]; then
|
||||||
|
printf '%s=%s\n' "$key" "$value" >> "$env_file"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if grep -q "^${key}=" "$env_file"; then
|
||||||
|
sed -i "s|^${key}=.*|${key}=${value}|" "$env_file"
|
||||||
|
else
|
||||||
|
printf '\n%s=%s\n' "$key" "$value" >> "$env_file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
find_image_with_suffix(){
|
find_image_with_suffix(){
|
||||||
local suffix="$1"
|
local suffix="$1"
|
||||||
@@ -319,6 +343,20 @@ echo " • Source date: $BUILD_SOURCE_DATE"
|
|||||||
|
|
||||||
# Get image names and tags from .env.template
|
# Get image names and tags from .env.template
|
||||||
TEMPLATE_FILE="$PROJECT_DIR/.env.template"
|
TEMPLATE_FILE="$PROJECT_DIR/.env.template"
|
||||||
|
get_template_value() {
|
||||||
|
local key="$1"
|
||||||
|
local fallback="$2"
|
||||||
|
if [ -f "$TEMPLATE_FILE" ]; then
|
||||||
|
local value
|
||||||
|
value=$(grep "^${key}=" "$TEMPLATE_FILE" | head -1 | cut -d'=' -f2- | sed 's/^"\(.*\)"$/\1/')
|
||||||
|
if [[ "$value" =~ ^\$\{[^}]*:-([^}]*)\}$ ]]; then
|
||||||
|
value="${BASH_REMATCH[1]}"
|
||||||
|
fi
|
||||||
|
[ -n "$value" ] && echo "$value" || echo "$fallback"
|
||||||
|
else
|
||||||
|
echo "$fallback"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
strip_tag(){
|
strip_tag(){
|
||||||
local image="$1"
|
local image="$1"
|
||||||
@@ -370,13 +408,13 @@ tag_if_exists(){
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
SOURCE_IMAGE_TAG="$(read_env DOCKER_IMAGE_TAG "$(get_template_value "DOCKER_IMAGE_TAG" "$TEMPLATE_FILE" "master")")"
|
SOURCE_IMAGE_TAG="$(read_env DOCKER_IMAGE_TAG "$(get_template_value "DOCKER_IMAGE_TAG" "master")")"
|
||||||
[ -z "$SOURCE_IMAGE_TAG" ] && SOURCE_IMAGE_TAG="master"
|
[ -z "$SOURCE_IMAGE_TAG" ] && SOURCE_IMAGE_TAG="master"
|
||||||
|
|
||||||
AUTHSERVER_BASE_REPO="$(strip_tag "$(read_env AC_AUTHSERVER_IMAGE_BASE "$(get_template_value "AC_AUTHSERVER_IMAGE_BASE" "$TEMPLATE_FILE" "acore/ac-wotlk-authserver")")")"
|
AUTHSERVER_BASE_REPO="$(strip_tag "$(read_env AC_AUTHSERVER_IMAGE_BASE "$(get_template_value "AC_AUTHSERVER_IMAGE_BASE" "acore/ac-wotlk-authserver")")")"
|
||||||
WORLDSERVER_BASE_REPO="$(strip_tag "$(read_env AC_WORLDSERVER_IMAGE_BASE "$(get_template_value "AC_WORLDSERVER_IMAGE_BASE" "$TEMPLATE_FILE" "acore/ac-wotlk-worldserver")")")"
|
WORLDSERVER_BASE_REPO="$(strip_tag "$(read_env AC_WORLDSERVER_IMAGE_BASE "$(get_template_value "AC_WORLDSERVER_IMAGE_BASE" "acore/ac-wotlk-worldserver")")")"
|
||||||
DB_IMPORT_BASE_REPO="$(strip_tag "$(read_env AC_DB_IMPORT_IMAGE_BASE "$(get_template_value "AC_DB_IMPORT_IMAGE_BASE" "$TEMPLATE_FILE" "acore/ac-wotlk-db-import")")")"
|
DB_IMPORT_BASE_REPO="$(strip_tag "$(read_env AC_DB_IMPORT_IMAGE_BASE "$(get_template_value "AC_DB_IMPORT_IMAGE_BASE" "acore/ac-wotlk-db-import")")")"
|
||||||
CLIENT_DATA_BASE_REPO="$(strip_tag "$(read_env AC_CLIENT_DATA_IMAGE_BASE "$(get_template_value "AC_CLIENT_DATA_IMAGE_BASE" "$TEMPLATE_FILE" "acore/ac-wotlk-client-data")")")"
|
CLIENT_DATA_BASE_REPO="$(strip_tag "$(read_env AC_CLIENT_DATA_IMAGE_BASE "$(get_template_value "AC_CLIENT_DATA_IMAGE_BASE" "acore/ac-wotlk-client-data")")")"
|
||||||
|
|
||||||
BUILT_AUTHSERVER_IMAGE="$AUTHSERVER_BASE_REPO:$SOURCE_IMAGE_TAG"
|
BUILT_AUTHSERVER_IMAGE="$AUTHSERVER_BASE_REPO:$SOURCE_IMAGE_TAG"
|
||||||
BUILT_WORLDSERVER_IMAGE="$WORLDSERVER_BASE_REPO:$SOURCE_IMAGE_TAG"
|
BUILT_WORLDSERVER_IMAGE="$WORLDSERVER_BASE_REPO:$SOURCE_IMAGE_TAG"
|
||||||
|
|||||||
177
scripts/bash/setup-user-environment.sh
Normal file
177
scripts/bash/setup-user-environment.sh
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Setup user environment with sudo access and bash completion
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
log_info() { echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
log_ok() { echo -e "${GREEN}✅ $*${NC}"; }
|
||||||
|
log_warn() { echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
|
||||||
|
TARGET_USER="${1:-${USER}}"
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "This script must be run as root (use sudo)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_info "Setting up environment for user: $TARGET_USER"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. Add user to sudo group
|
||||||
|
log_info "Step 1/4: Adding $TARGET_USER to sudo group..."
|
||||||
|
if groups "$TARGET_USER" | grep -q "\bsudo\b"; then
|
||||||
|
log_ok "User already in sudo group"
|
||||||
|
else
|
||||||
|
usermod -aG sudo "$TARGET_USER"
|
||||||
|
log_ok "Added $TARGET_USER to sudo group"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Change default shell to bash
|
||||||
|
log_info "Step 2/4: Setting default shell to bash..."
|
||||||
|
CURRENT_SHELL=$(getent passwd "$TARGET_USER" | cut -d: -f7)
|
||||||
|
if [ "$CURRENT_SHELL" = "/bin/bash" ]; then
|
||||||
|
log_ok "Default shell already set to bash"
|
||||||
|
else
|
||||||
|
chsh -s /bin/bash "$TARGET_USER"
|
||||||
|
log_ok "Changed default shell from $CURRENT_SHELL to /bin/bash"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Create .bashrc with bash completion
|
||||||
|
log_info "Step 3/4: Setting up bash completion..."
|
||||||
|
USER_HOME=$(getent passwd "$TARGET_USER" | cut -d: -f6)
|
||||||
|
BASHRC="$USER_HOME/.bashrc"
|
||||||
|
|
||||||
|
if [ -f "$BASHRC" ]; then
|
||||||
|
log_warn ".bashrc already exists, checking for bash completion..."
|
||||||
|
if grep -q "bash_completion" "$BASHRC"; then
|
||||||
|
log_ok "Bash completion already configured in .bashrc"
|
||||||
|
else
|
||||||
|
log_info "Adding bash completion to existing .bashrc..."
|
||||||
|
cat >> "$BASHRC" << 'EOF'
|
||||||
|
|
||||||
|
# Enable bash completion
|
||||||
|
if ! shopt -oq posix; then
|
||||||
|
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||||
|
. /usr/share/bash-completion/bash_completion
|
||||||
|
elif [ -f /etc/bash_completion ]; then
|
||||||
|
. /etc/bash_completion
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chown "$TARGET_USER:$TARGET_USER" "$BASHRC"
|
||||||
|
log_ok "Bash completion added to .bashrc"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_info "Creating new .bashrc with bash completion..."
|
||||||
|
cat > "$BASHRC" << 'EOF'
|
||||||
|
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||||
|
|
||||||
|
# If not running interactively, don't do anything
|
||||||
|
case $- in
|
||||||
|
*i*) ;;
|
||||||
|
*) return;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# History settings
|
||||||
|
HISTCONTROL=ignoreboth
|
||||||
|
HISTSIZE=10000
|
||||||
|
HISTFILESIZE=20000
|
||||||
|
shopt -s histappend
|
||||||
|
|
||||||
|
# Check window size after each command
|
||||||
|
shopt -s checkwinsize
|
||||||
|
|
||||||
|
# Make less more friendly for non-text input files
|
||||||
|
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||||
|
|
||||||
|
# Set a fancy prompt
|
||||||
|
PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
||||||
|
|
||||||
|
# Enable color support for ls and grep
|
||||||
|
if [ -x /usr/bin/dircolors ]; then
|
||||||
|
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||||
|
alias ls='ls --color=auto'
|
||||||
|
alias grep='grep --color=auto'
|
||||||
|
alias fgrep='fgrep --color=auto'
|
||||||
|
alias egrep='egrep --color=auto'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Some more ls aliases
|
||||||
|
alias ll='ls -alF'
|
||||||
|
alias la='ls -A'
|
||||||
|
alias l='ls -CF'
|
||||||
|
|
||||||
|
# Enable bash completion
|
||||||
|
if ! shopt -oq posix; then
|
||||||
|
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||||
|
. /usr/share/bash-completion/bash_completion
|
||||||
|
elif [ -f /etc/bash_completion ]; then
|
||||||
|
. /etc/bash_completion
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Docker completion (if docker is installed)
|
||||||
|
if [ -f /usr/share/bash-completion/completions/docker ]; then
|
||||||
|
. /usr/share/bash-completion/completions/docker
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chown "$TARGET_USER:$TARGET_USER" "$BASHRC"
|
||||||
|
chmod 644 "$BASHRC"
|
||||||
|
log_ok "Created .bashrc with bash completion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Create .bash_profile to source .bashrc for login shells
|
||||||
|
log_info "Step 4/4: Setting up bash_profile for login shells..."
|
||||||
|
BASH_PROFILE="$USER_HOME/.bash_profile"
|
||||||
|
|
||||||
|
if [ -f "$BASH_PROFILE" ]; then
|
||||||
|
if grep -q "\.bashrc" "$BASH_PROFILE"; then
|
||||||
|
log_ok ".bash_profile already sources .bashrc"
|
||||||
|
else
|
||||||
|
log_info "Adding .bashrc sourcing to existing .bash_profile..."
|
||||||
|
cat >> "$BASH_PROFILE" << 'EOF'
|
||||||
|
|
||||||
|
# Source .bashrc if it exists
|
||||||
|
if [ -f ~/.bashrc ]; then
|
||||||
|
. ~/.bashrc
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chown "$TARGET_USER:$TARGET_USER" "$BASH_PROFILE"
|
||||||
|
log_ok ".bash_profile updated to source .bashrc"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_info "Creating .bash_profile..."
|
||||||
|
cat > "$BASH_PROFILE" << 'EOF'
|
||||||
|
# ~/.bash_profile: executed by bash(1) for login shells.
|
||||||
|
|
||||||
|
# Source .bashrc if it exists
|
||||||
|
if [ -f ~/.bashrc ]; then
|
||||||
|
. ~/.bashrc
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chown "$TARGET_USER:$TARGET_USER" "$BASH_PROFILE"
|
||||||
|
chmod 644 "$BASH_PROFILE"
|
||||||
|
log_ok "Created .bash_profile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
log_ok "Environment setup complete for $TARGET_USER!"
|
||||||
|
echo ""
|
||||||
|
echo "Changes applied:"
|
||||||
|
echo " ✓ Added to sudo group (password required)"
|
||||||
|
echo " ✓ Default shell changed to /bin/bash"
|
||||||
|
echo " ✓ Bash completion enabled (.bashrc)"
|
||||||
|
echo " ✓ Login shell configured (.bash_profile)"
|
||||||
|
echo ""
|
||||||
|
log_warn "Important: You need to log out and log back in for shell changes to take effect"
|
||||||
|
log_info "To test sudo: sudo -v (will prompt for password)"
|
||||||
|
log_info "To test tab completion: type 'systemctl rest' and press TAB"
|
||||||
|
log_info "To verify shell: echo \$SHELL (should show /bin/bash)"
|
||||||
|
echo ""
|
||||||
@@ -1,261 +0,0 @@
|
|||||||
# CLI parsing for setup.sh
|
|
||||||
|
|
||||||
init_cli_defaults() {
|
|
||||||
CLI_DEPLOYMENT_TYPE=""
|
|
||||||
CLI_PERMISSION_SCHEME=""
|
|
||||||
CLI_CUSTOM_UID=""
|
|
||||||
CLI_CUSTOM_GID=""
|
|
||||||
CLI_SERVER_ADDRESS=""
|
|
||||||
CLI_REALM_PORT=""
|
|
||||||
CLI_AUTH_PORT=""
|
|
||||||
CLI_SOAP_PORT=""
|
|
||||||
CLI_MYSQL_PORT=""
|
|
||||||
CLI_MYSQL_PASSWORD=""
|
|
||||||
CLI_STORAGE_PATH=""
|
|
||||||
CLI_BACKUP_DAYS=""
|
|
||||||
CLI_BACKUP_HOURS=""
|
|
||||||
CLI_BACKUP_TIME=""
|
|
||||||
CLI_MODULE_MODE=""
|
|
||||||
CLI_MODULE_PRESET=""
|
|
||||||
CLI_PLAYERBOT_ENABLED=""
|
|
||||||
CLI_PLAYERBOT_MIN=""
|
|
||||||
CLI_PLAYERBOT_MAX=""
|
|
||||||
CLI_CONFIG_PRESET=""
|
|
||||||
FORCE_OVERWRITE=0
|
|
||||||
CLI_ENABLE_MODULES_RAW=()
|
|
||||||
}
|
|
||||||
|
|
||||||
print_help() {
|
|
||||||
cat <<'HELP'
|
|
||||||
Usage: ./setup.sh [options]
|
|
||||||
|
|
||||||
Description:
|
|
||||||
Interactive wizard that generates .env for the
|
|
||||||
profiles-based compose. Prompts for deployment type, ports, storage,
|
|
||||||
MySQL credentials, backup retention, and module presets or manual
|
|
||||||
toggles.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h, --help Show this help message and exit
|
|
||||||
--non-interactive Use defaults/arguments without prompting
|
|
||||||
--deployment-type TYPE Deployment type: local, lan, or public
|
|
||||||
--permission-scheme SCHEME Permissions: local, nfs, or custom
|
|
||||||
--custom-uid UID UID when --permission-scheme=custom
|
|
||||||
--custom-gid GID GID when --permission-scheme=custom
|
|
||||||
--server-address ADDRESS Realm/public address
|
|
||||||
--realm-port PORT Client connection port (default 8215)
|
|
||||||
--auth-port PORT Authserver external port (default 3784)
|
|
||||||
--soap-port PORT SOAP external port (default 7778)
|
|
||||||
--mysql-port PORT MySQL external port (default 64306)
|
|
||||||
--mysql-password PASSWORD MySQL root password (default azerothcore123)
|
|
||||||
--storage-path PATH Storage directory
|
|
||||||
--backup-retention-days N Daily backup retention (default 3)
|
|
||||||
--backup-retention-hours N Hourly backup retention (default 6)
|
|
||||||
--backup-daily-time HH Daily backup hour 00-23 (default 09)
|
|
||||||
--module-mode MODE suggested, playerbots, manual, or none
|
|
||||||
--module-config NAME Use preset NAME from config/module-profiles/<NAME>.json
|
|
||||||
--server-config NAME Use server preset NAME from config/presets/<NAME>.conf
|
|
||||||
--enable-modules LIST Comma-separated module list (MODULE_* or shorthand)
|
|
||||||
--playerbot-enabled 0|1 Override PLAYERBOT_ENABLED flag
|
|
||||||
--playerbot-min-bots N Override PLAYERBOT_MIN_BOTS value
|
|
||||||
--playerbot-max-bots N Override PLAYERBOT_MAX_BOTS value
|
|
||||||
--force Overwrite existing .env without prompting
|
|
||||||
HELP
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_cli_args() {
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
-h|--help)
|
|
||||||
print_help
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
--non-interactive)
|
|
||||||
NON_INTERACTIVE=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--deployment-type)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--deployment-type requires a value"; exit 1; }
|
|
||||||
CLI_DEPLOYMENT_TYPE="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--deployment-type=*)
|
|
||||||
CLI_DEPLOYMENT_TYPE="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--permission-scheme)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--permission-scheme requires a value"; exit 1; }
|
|
||||||
CLI_PERMISSION_SCHEME="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--permission-scheme=*)
|
|
||||||
CLI_PERMISSION_SCHEME="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--custom-uid)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--custom-uid requires a value"; exit 1; }
|
|
||||||
CLI_CUSTOM_UID="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--custom-uid=*)
|
|
||||||
CLI_CUSTOM_UID="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--custom-gid)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--custom-gid requires a value"; exit 1; }
|
|
||||||
CLI_CUSTOM_GID="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--custom-gid=*)
|
|
||||||
CLI_CUSTOM_GID="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--server-address)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--server-address requires a value"; exit 1; }
|
|
||||||
CLI_SERVER_ADDRESS="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--server-address=*)
|
|
||||||
CLI_SERVER_ADDRESS="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--realm-port)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--realm-port requires a value"; exit 1; }
|
|
||||||
CLI_REALM_PORT="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--realm-port=*)
|
|
||||||
CLI_REALM_PORT="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--auth-port)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--auth-port requires a value"; exit 1; }
|
|
||||||
CLI_AUTH_PORT="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--auth-port=*)
|
|
||||||
CLI_AUTH_PORT="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--soap-port)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--soap-port requires a value"; exit 1; }
|
|
||||||
CLI_SOAP_PORT="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--soap-port=*)
|
|
||||||
CLI_SOAP_PORT="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--mysql-port)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--mysql-port requires a value"; exit 1; }
|
|
||||||
CLI_MYSQL_PORT="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--mysql-port=*)
|
|
||||||
CLI_MYSQL_PORT="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--mysql-password)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--mysql-password requires a value"; exit 1; }
|
|
||||||
CLI_MYSQL_PASSWORD="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--mysql-password=*)
|
|
||||||
CLI_MYSQL_PASSWORD="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--storage-path)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--storage-path requires a value"; exit 1; }
|
|
||||||
CLI_STORAGE_PATH="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--storage-path=*)
|
|
||||||
CLI_STORAGE_PATH="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--backup-retention-days)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--backup-retention-days requires a value"; exit 1; }
|
|
||||||
CLI_BACKUP_DAYS="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--backup-retention-days=*)
|
|
||||||
CLI_BACKUP_DAYS="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--backup-retention-hours)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--backup-retention-hours requires a value"; exit 1; }
|
|
||||||
CLI_BACKUP_HOURS="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--backup-retention-hours=*)
|
|
||||||
CLI_BACKUP_HOURS="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--backup-daily-time)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--backup-daily-time requires a value"; exit 1; }
|
|
||||||
CLI_BACKUP_TIME="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--backup-daily-time=*)
|
|
||||||
CLI_BACKUP_TIME="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--module-mode)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--module-mode requires a value"; exit 1; }
|
|
||||||
CLI_MODULE_MODE="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--module-mode=*)
|
|
||||||
CLI_MODULE_MODE="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--module-config)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--module-config requires a value"; exit 1; }
|
|
||||||
CLI_MODULE_PRESET="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--module-config=*)
|
|
||||||
CLI_MODULE_PRESET="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--server-config)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--server-config requires a value"; exit 1; }
|
|
||||||
CLI_CONFIG_PRESET="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--server-config=*)
|
|
||||||
CLI_CONFIG_PRESET="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--enable-modules)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--enable-modules requires a value"; exit 1; }
|
|
||||||
CLI_ENABLE_MODULES_RAW+=("$2"); shift 2
|
|
||||||
;;
|
|
||||||
--enable-modules=*)
|
|
||||||
CLI_ENABLE_MODULES_RAW+=("${1#*=}"); shift
|
|
||||||
;;
|
|
||||||
--playerbot-enabled)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--playerbot-enabled requires 0 or 1"; exit 1; }
|
|
||||||
CLI_PLAYERBOT_ENABLED="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--playerbot-enabled=*)
|
|
||||||
CLI_PLAYERBOT_ENABLED="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--playerbot-min-bots)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--playerbot-min-bots requires a value"; exit 1; }
|
|
||||||
CLI_PLAYERBOT_MIN="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--playerbot-min-bots=*)
|
|
||||||
CLI_PLAYERBOT_MIN="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--playerbot-max-bots)
|
|
||||||
[[ $# -ge 2 ]] || { say ERROR "--playerbot-max-bots requires a value"; exit 1; }
|
|
||||||
CLI_PLAYERBOT_MAX="$2"; shift 2
|
|
||||||
;;
|
|
||||||
--playerbot-max-bots=*)
|
|
||||||
CLI_PLAYERBOT_MAX="${1#*=}"; shift
|
|
||||||
;;
|
|
||||||
--force)
|
|
||||||
FORCE_OVERWRITE=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown argument: $1" >&2
|
|
||||||
echo "Use --help for usage" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_cli_module_flags() {
|
|
||||||
# setup.sh -> scripts/bash/setup/modules.sh (normalize_module_name)
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say)
|
|
||||||
if [ ${#CLI_ENABLE_MODULES_RAW[@]} -gt 0 ]; then
|
|
||||||
local raw part norm
|
|
||||||
for raw in "${CLI_ENABLE_MODULES_RAW[@]}"; do
|
|
||||||
IFS=',' read -ra parts <<<"$raw"
|
|
||||||
for part in "${parts[@]}"; do
|
|
||||||
part="${part//[[:space:]]/}"
|
|
||||||
[ -z "$part" ] && continue
|
|
||||||
norm="$(normalize_module_name "$part")"
|
|
||||||
if [ -z "${KNOWN_MODULE_LOOKUP[$norm]}" ]; then
|
|
||||||
say WARNING "Ignoring unknown module identifier: ${part}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
MODULE_ENABLE_SET["$norm"]=1
|
|
||||||
done
|
|
||||||
done
|
|
||||||
unset raw part norm parts
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ${#CLI_ENABLE_MODULES_RAW[@]} -gt 0 ] && [ -z "$CLI_MODULE_MODE" ]; then
|
|
||||||
CLI_MODULE_MODE="manual"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
# Interactive configuration flow for setup.sh
|
|
||||||
|
|
||||||
select_deployment_type() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say)
|
|
||||||
say HEADER "DEPLOYMENT TYPE"
|
|
||||||
echo "1) 🏠 Local Development (${DEFAULT_LOCAL_ADDRESS})"
|
|
||||||
echo "2) 🌐 LAN Server (local network IP) (autodetect)"
|
|
||||||
echo "3) ☁️ Public Server (domain or public IP) (manual)"
|
|
||||||
local DEPLOYMENT_TYPE_INPUT="${CLI_DEPLOYMENT_TYPE}"
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ] && [ -z "$DEPLOYMENT_TYPE_INPUT" ]; then
|
|
||||||
DEPLOYMENT_TYPE_INPUT="local"
|
|
||||||
fi
|
|
||||||
while true; do
|
|
||||||
if [ -z "$DEPLOYMENT_TYPE_INPUT" ]; then
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 Select deployment type [1-3]: ${NC}")" DEPLOYMENT_TYPE_INPUT
|
|
||||||
fi
|
|
||||||
case "${DEPLOYMENT_TYPE_INPUT,,}" in
|
|
||||||
1|local)
|
|
||||||
DEPLOYMENT_TYPE=local
|
|
||||||
;;
|
|
||||||
2|lan)
|
|
||||||
DEPLOYMENT_TYPE=lan
|
|
||||||
;;
|
|
||||||
3|public)
|
|
||||||
DEPLOYMENT_TYPE=public
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ -n "$CLI_DEPLOYMENT_TYPE" ] || [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
say ERROR "Invalid deployment type: ${DEPLOYMENT_TYPE_INPUT}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
say ERROR "Please select 1, 2, or 3"
|
|
||||||
DEPLOYMENT_TYPE_INPUT=""
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
break
|
|
||||||
done
|
|
||||||
if [ -n "$CLI_DEPLOYMENT_TYPE" ] || [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
say INFO "Deployment type set to ${DEPLOYMENT_TYPE}."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_server() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say, ask, validate_ip, validate_port)
|
|
||||||
say HEADER "SERVER CONFIGURATION"
|
|
||||||
if [ -n "$CLI_SERVER_ADDRESS" ]; then
|
|
||||||
SERVER_ADDRESS="$CLI_SERVER_ADDRESS"
|
|
||||||
elif [ "$DEPLOYMENT_TYPE" = "local" ]; then
|
|
||||||
SERVER_ADDRESS=$DEFAULT_LOCAL_ADDRESS
|
|
||||||
elif [ "$DEPLOYMENT_TYPE" = "lan" ]; then
|
|
||||||
local LAN_IP
|
|
||||||
LAN_IP=$(ip route get $ROUTE_DETECTION_IP 2>/dev/null | awk 'NR==1{print $7}')
|
|
||||||
SERVER_ADDRESS=$(ask "Enter server IP address" "${CLI_SERVER_ADDRESS:-${LAN_IP:-$DEFAULT_FALLBACK_LAN_IP}}" validate_ip)
|
|
||||||
else
|
|
||||||
SERVER_ADDRESS=$(ask "Enter server address (IP or domain)" "${CLI_SERVER_ADDRESS:-$DEFAULT_DOMAIN_PLACEHOLDER}" )
|
|
||||||
fi
|
|
||||||
|
|
||||||
REALM_PORT=$(ask "Enter client connection port" "${CLI_REALM_PORT:-$DEFAULT_REALM_PORT}" validate_port)
|
|
||||||
AUTH_EXTERNAL_PORT=$(ask "Enter auth server port" "${CLI_AUTH_PORT:-$DEFAULT_AUTH_PORT}" validate_port)
|
|
||||||
SOAP_EXTERNAL_PORT=$(ask "Enter SOAP API port" "${CLI_SOAP_PORT:-$DEFAULT_SOAP_PORT}" validate_port)
|
|
||||||
MYSQL_EXTERNAL_PORT=$(ask "Enter MySQL external port" "${CLI_MYSQL_PORT:-$DEFAULT_MYSQL_PORT}" validate_port)
|
|
||||||
}
|
|
||||||
|
|
||||||
choose_permission_scheme() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say, ask, validate_number)
|
|
||||||
say HEADER "PERMISSION SCHEME"
|
|
||||||
local CURRENT_UID CURRENT_GID CURRENT_USER_PAIR CURRENT_USER_NAME CURRENT_GROUP_NAME
|
|
||||||
CURRENT_UID="$(id -u 2>/dev/null || echo 1000)"
|
|
||||||
CURRENT_GID="$(id -g 2>/dev/null || echo 1000)"
|
|
||||||
CURRENT_USER_NAME="$(id -un 2>/dev/null || echo user)"
|
|
||||||
CURRENT_GROUP_NAME="$(id -gn 2>/dev/null || echo users)"
|
|
||||||
CURRENT_USER_PAIR="${CURRENT_UID}:${CURRENT_GID}"
|
|
||||||
echo "1) 🏠 Local Root (${PERMISSION_LOCAL_USER})"
|
|
||||||
echo "2) 🗂️ Current User (${CURRENT_USER_NAME}:${CURRENT_GROUP_NAME} → ${CURRENT_USER_PAIR})"
|
|
||||||
echo "3) ⚙️ Custom"
|
|
||||||
local PERMISSION_SCHEME_INPUT="${CLI_PERMISSION_SCHEME}"
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ] && [ -z "$PERMISSION_SCHEME_INPUT" ]; then
|
|
||||||
PERMISSION_SCHEME_INPUT="local"
|
|
||||||
fi
|
|
||||||
while true; do
|
|
||||||
if [ -z "$PERMISSION_SCHEME_INPUT" ]; then
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 Select permission scheme [1-3]: ${NC}")" PERMISSION_SCHEME_INPUT
|
|
||||||
fi
|
|
||||||
case "${PERMISSION_SCHEME_INPUT,,}" in
|
|
||||||
1|local)
|
|
||||||
CONTAINER_USER="$PERMISSION_LOCAL_USER"
|
|
||||||
PERMISSION_SCHEME_NAME="local"
|
|
||||||
;;
|
|
||||||
2|nfs|user)
|
|
||||||
CONTAINER_USER="$CURRENT_USER_PAIR"
|
|
||||||
PERMISSION_SCHEME_NAME="user"
|
|
||||||
;;
|
|
||||||
3|custom)
|
|
||||||
local uid gid
|
|
||||||
uid="${CLI_CUSTOM_UID:-$(ask "Enter PUID (user id)" $DEFAULT_CUSTOM_UID validate_number)}"
|
|
||||||
gid="${CLI_CUSTOM_GID:-$(ask "Enter PGID (group id)" $DEFAULT_CUSTOM_GID validate_number)}"
|
|
||||||
CONTAINER_USER="${uid}:${gid}"
|
|
||||||
PERMISSION_SCHEME_NAME="custom"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ -n "$CLI_PERMISSION_SCHEME" ] || [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
say ERROR "Invalid permission scheme: ${PERMISSION_SCHEME_INPUT}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
say ERROR "Please select 1, 2, or 3"
|
|
||||||
PERMISSION_SCHEME_INPUT=""
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
break
|
|
||||||
done
|
|
||||||
if [ -n "$CLI_PERMISSION_SCHEME" ] || [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
say INFO "Permission scheme set to ${PERMISSION_SCHEME_NAME:-$PERMISSION_SCHEME_INPUT}."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_database() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say, ask)
|
|
||||||
say HEADER "DATABASE CONFIGURATION"
|
|
||||||
MYSQL_ROOT_PASSWORD=$(ask "Enter MySQL root password" "${CLI_MYSQL_PASSWORD:-$DEFAULT_MYSQL_PASSWORD}")
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_storage() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say, ask)
|
|
||||||
say HEADER "STORAGE CONFIGURATION"
|
|
||||||
if [ -n "$CLI_STORAGE_PATH" ]; then
|
|
||||||
STORAGE_PATH="$CLI_STORAGE_PATH"
|
|
||||||
elif [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
if [ "$DEPLOYMENT_TYPE" = "local" ]; then
|
|
||||||
STORAGE_PATH=$DEFAULT_LOCAL_STORAGE
|
|
||||||
else
|
|
||||||
STORAGE_PATH=$DEFAULT_MOUNT_STORAGE
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "1) 💾 ${DEFAULT_LOCAL_STORAGE} (local)"
|
|
||||||
echo "2) 🌐 ${DEFAULT_NFS_STORAGE} (NFS)"
|
|
||||||
echo "3) 📁 Custom"
|
|
||||||
while true; do
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 Select storage option [1-3]: ${NC}")" s
|
|
||||||
case "$s" in
|
|
||||||
1) STORAGE_PATH=$DEFAULT_LOCAL_STORAGE; break;;
|
|
||||||
2) STORAGE_PATH=$DEFAULT_NFS_STORAGE; break;;
|
|
||||||
3) STORAGE_PATH=$(ask "Enter custom storage path" "$DEFAULT_MOUNT_STORAGE"); break;;
|
|
||||||
*) say ERROR "Please select 1, 2, or 3";;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
say INFO "Storage path set to ${STORAGE_PATH}"
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_backups() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say, ask, validate_number)
|
|
||||||
say HEADER "BACKUP CONFIGURATION"
|
|
||||||
BACKUP_RETENTION_DAYS=$(ask "Daily backups retention (days)" "${CLI_BACKUP_DAYS:-$DEFAULT_BACKUP_DAYS}" validate_number)
|
|
||||||
BACKUP_RETENTION_HOURS=$(ask "Hourly backups retention (hours)" "${CLI_BACKUP_HOURS:-$DEFAULT_BACKUP_HOURS}" validate_number)
|
|
||||||
BACKUP_DAILY_TIME=$(ask "Daily backup hour (00-23, UTC)" "${CLI_BACKUP_TIME:-$DEFAULT_BACKUP_TIME}" validate_number)
|
|
||||||
}
|
|
||||||
|
|
||||||
select_server_preset() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say, ask)
|
|
||||||
if [ "$ENABLE_CONFIG_PRESETS" = "1" ]; then
|
|
||||||
say HEADER "SERVER CONFIGURATION PRESET"
|
|
||||||
|
|
||||||
if [ -n "$CLI_CONFIG_PRESET" ]; then
|
|
||||||
SERVER_CONFIG_PRESET="$CLI_CONFIG_PRESET"
|
|
||||||
say INFO "Using preset from command line: $SERVER_CONFIG_PRESET"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
declare -A CONFIG_PRESET_NAMES=()
|
|
||||||
declare -A CONFIG_PRESET_DESCRIPTIONS=()
|
|
||||||
declare -A CONFIG_MENU_INDEX=()
|
|
||||||
local config_dir="$SCRIPT_DIR/config/presets"
|
|
||||||
local menu_index=1
|
|
||||||
|
|
||||||
echo "Choose a server configuration preset:"
|
|
||||||
|
|
||||||
# setup.sh -> scripts/python/parse-config-presets.py (preset metadata)
|
|
||||||
if [ -x "$SCRIPT_DIR/scripts/python/parse-config-presets.py" ] && [ -d "$config_dir" ]; then
|
|
||||||
while IFS=$'\t' read -r preset_key preset_name preset_desc; do
|
|
||||||
[ -n "$preset_key" ] || continue
|
|
||||||
CONFIG_PRESET_NAMES["$preset_key"]="$preset_name"
|
|
||||||
CONFIG_PRESET_DESCRIPTIONS["$preset_key"]="$preset_desc"
|
|
||||||
CONFIG_MENU_INDEX[$menu_index]="$preset_key"
|
|
||||||
echo "$menu_index) $preset_name"
|
|
||||||
echo " $preset_desc"
|
|
||||||
menu_index=$((menu_index + 1))
|
|
||||||
done < <(python3 "$SCRIPT_DIR/scripts/python/parse-config-presets.py" list --presets-dir "$config_dir")
|
|
||||||
else
|
|
||||||
# Fallback if parser script not available
|
|
||||||
CONFIG_MENU_INDEX[1]="none"
|
|
||||||
CONFIG_PRESET_NAMES["none"]="Default (No Preset)"
|
|
||||||
CONFIG_PRESET_DESCRIPTIONS["none"]="Use default AzerothCore settings"
|
|
||||||
echo "1) Default (No Preset)"
|
|
||||||
echo " Use default AzerothCore settings without any modifications"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local max_config_option=$((menu_index - 1))
|
|
||||||
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
SERVER_CONFIG_PRESET="none"
|
|
||||||
say INFO "Non-interactive mode: Using default configuration preset"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
read -p "$(echo -e "${YELLOW}🎯 Select server configuration [1-$max_config_option]: ${NC}")" choice
|
|
||||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$max_config_option" ]; then
|
|
||||||
SERVER_CONFIG_PRESET="${CONFIG_MENU_INDEX[$choice]}"
|
|
||||||
local chosen_name="${CONFIG_PRESET_NAMES[$SERVER_CONFIG_PRESET]}"
|
|
||||||
say INFO "Selected: $chosen_name"
|
|
||||||
break
|
|
||||||
else
|
|
||||||
say ERROR "Please select a number between 1 and $max_config_option"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
# Config presets disabled - use default
|
|
||||||
SERVER_CONFIG_PRESET="none"
|
|
||||||
say INFO "Server configuration presets disabled - using default settings"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
# Setup defaults and template-backed constants for setup.sh
|
|
||||||
|
|
||||||
# setup.sh -> scripts/bash/lib/common.sh (shared helpers)
|
|
||||||
source "$SCRIPT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
|
|
||||||
# Feature Flags
|
|
||||||
# Set to 0 to disable server configuration preset selection
|
|
||||||
ENABLE_CONFIG_PRESETS="${ENABLE_CONFIG_PRESETS:-0}"
|
|
||||||
|
|
||||||
|
|
||||||
sanitize_project_name(){
|
|
||||||
project_name::sanitize "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_project_image_tag(){
|
|
||||||
local project="$1" tag="$2"
|
|
||||||
echo "${project}:${tag}"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -A TEMPLATE_VALUE_MAP=(
|
|
||||||
[DEFAULT_MYSQL_PASSWORD]=MYSQL_ROOT_PASSWORD
|
|
||||||
[DEFAULT_REALM_PORT]=WORLD_EXTERNAL_PORT
|
|
||||||
[DEFAULT_AUTH_PORT]=AUTH_EXTERNAL_PORT
|
|
||||||
[DEFAULT_SOAP_PORT]=SOAP_EXTERNAL_PORT
|
|
||||||
[DEFAULT_MYSQL_PORT]=MYSQL_EXTERNAL_PORT
|
|
||||||
[DEFAULT_PLAYERBOT_MIN]=PLAYERBOT_MIN_BOTS
|
|
||||||
[DEFAULT_PLAYERBOT_MAX]=PLAYERBOT_MAX_BOTS
|
|
||||||
[DEFAULT_LOCAL_STORAGE]=STORAGE_PATH
|
|
||||||
[DEFAULT_BACKUP_PATH]=BACKUP_PATH
|
|
||||||
[DEFAULT_COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED]=COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED
|
|
||||||
[DEFAULT_COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED]=COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED
|
|
||||||
[PERMISSION_LOCAL_USER]=DEFAULT_PERMISSION_LOCAL_USER
|
|
||||||
[PERMISSION_NFS_USER]=DEFAULT_PERMISSION_NFS_USER
|
|
||||||
[DEFAULT_CUSTOM_UID]=DEFAULT_CUSTOM_UID
|
|
||||||
[DEFAULT_CUSTOM_GID]=DEFAULT_CUSTOM_GID
|
|
||||||
[DEFAULT_LOCAL_ADDRESS]=SERVER_ADDRESS
|
|
||||||
[DEFAULT_BACKUP_DAYS]=BACKUP_RETENTION_DAYS
|
|
||||||
[DEFAULT_BACKUP_HOURS]=BACKUP_RETENTION_HOURS
|
|
||||||
[DEFAULT_BACKUP_TIME]=BACKUP_DAILY_TIME
|
|
||||||
[DEFAULT_BACKUP_HEALTHCHECK_MAX_MINUTES]=BACKUP_HEALTHCHECK_MAX_MINUTES
|
|
||||||
[DEFAULT_BACKUP_HEALTHCHECK_GRACE_SECONDS]=BACKUP_HEALTHCHECK_GRACE_SECONDS
|
|
||||||
[DEFAULT_NFS_STORAGE]=DEFAULT_NFS_STORAGE_PATH
|
|
||||||
[DEFAULT_MOUNT_STORAGE]=DEFAULT_MOUNT_STORAGE_PATH
|
|
||||||
[DEFAULT_MYSQL_IMAGE]=MYSQL_IMAGE
|
|
||||||
[DEFAULT_AC_DB_IMPORT_IMAGE]=AC_DB_IMPORT_IMAGE
|
|
||||||
[DEFAULT_AC_AUTHSERVER_IMAGE]=AC_AUTHSERVER_IMAGE
|
|
||||||
[DEFAULT_AC_WORLDSERVER_IMAGE]=AC_WORLDSERVER_IMAGE
|
|
||||||
[DEFAULT_AC_CLIENT_DATA_IMAGE]=AC_CLIENT_DATA_IMAGE
|
|
||||||
[DEFAULT_DOCKER_IMAGE_TAG]=DOCKER_IMAGE_TAG
|
|
||||||
[DEFAULT_AUTHSERVER_IMAGE_BASE]=AC_AUTHSERVER_IMAGE_BASE
|
|
||||||
[DEFAULT_WORLDSERVER_IMAGE_BASE]=AC_WORLDSERVER_IMAGE_BASE
|
|
||||||
[DEFAULT_DB_IMPORT_IMAGE_BASE]=AC_DB_IMPORT_IMAGE_BASE
|
|
||||||
[DEFAULT_CLIENT_DATA_IMAGE_BASE]=AC_CLIENT_DATA_IMAGE_BASE
|
|
||||||
[DEFAULT_AUTH_IMAGE_PLAYERBOTS]=AC_AUTHSERVER_IMAGE_PLAYERBOTS
|
|
||||||
[DEFAULT_WORLD_IMAGE_PLAYERBOTS]=AC_WORLDSERVER_IMAGE_PLAYERBOTS
|
|
||||||
[DEFAULT_CLIENT_DATA_IMAGE_PLAYERBOTS]=AC_CLIENT_DATA_IMAGE_PLAYERBOTS
|
|
||||||
[DEFAULT_AUTH_IMAGE_MODULES]=AC_AUTHSERVER_IMAGE_MODULES
|
|
||||||
[DEFAULT_WORLD_IMAGE_MODULES]=AC_WORLDSERVER_IMAGE_MODULES
|
|
||||||
[DEFAULT_ALPINE_GIT_IMAGE]=ALPINE_GIT_IMAGE
|
|
||||||
[DEFAULT_ALPINE_IMAGE]=ALPINE_IMAGE
|
|
||||||
[DEFAULT_DB_AUTH_NAME]=DB_AUTH_NAME
|
|
||||||
[DEFAULT_DB_WORLD_NAME]=DB_WORLD_NAME
|
|
||||||
[DEFAULT_DB_CHARACTERS_NAME]=DB_CHARACTERS_NAME
|
|
||||||
[DEFAULT_DB_PLAYERBOTS_NAME]=DB_PLAYERBOTS_NAME
|
|
||||||
[DEFAULT_CONTAINER_MYSQL]=CONTAINER_MYSQL
|
|
||||||
[DEFAULT_CONTAINER_DB_IMPORT]=CONTAINER_DB_IMPORT
|
|
||||||
[DEFAULT_CONTAINER_DB_INIT]=CONTAINER_DB_INIT
|
|
||||||
[DEFAULT_CONTAINER_BACKUP]=CONTAINER_BACKUP
|
|
||||||
[DEFAULT_CONTAINER_MODULES]=CONTAINER_MODULES
|
|
||||||
[DEFAULT_CONTAINER_POST_INSTALL]=CONTAINER_POST_INSTALL
|
|
||||||
[DEFAULT_COMPOSE_PROJECT_NAME]=COMPOSE_PROJECT_NAME
|
|
||||||
[DEFAULT_CLIENT_DATA_PATH]=CLIENT_DATA_PATH
|
|
||||||
[DEFAULT_CLIENT_DATA_CACHE_PATH]=CLIENT_DATA_CACHE_PATH
|
|
||||||
[DEFAULT_CLIENT_DATA_VERSION]=CLIENT_DATA_VERSION
|
|
||||||
[DEFAULT_NETWORK_NAME]=NETWORK_NAME
|
|
||||||
[DEFAULT_NETWORK_SUBNET]=NETWORK_SUBNET
|
|
||||||
[DEFAULT_NETWORK_GATEWAY]=NETWORK_GATEWAY
|
|
||||||
[DEFAULT_MYSQL_CHARACTER_SET]=MYSQL_CHARACTER_SET
|
|
||||||
[DEFAULT_MYSQL_COLLATION]=MYSQL_COLLATION
|
|
||||||
[DEFAULT_MYSQL_MAX_CONNECTIONS]=MYSQL_MAX_CONNECTIONS
|
|
||||||
[DEFAULT_MYSQL_INNODB_BUFFER_POOL_SIZE]=MYSQL_INNODB_BUFFER_POOL_SIZE
|
|
||||||
[DEFAULT_MYSQL_INNODB_LOG_FILE_SIZE]=MYSQL_INNODB_LOG_FILE_SIZE
|
|
||||||
[DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY]=MYSQL_INNODB_REDO_LOG_CAPACITY
|
|
||||||
[DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE]=MYSQL_RUNTIME_TMPFS_SIZE
|
|
||||||
[DEFAULT_MYSQL_DISABLE_BINLOG]=MYSQL_DISABLE_BINLOG
|
|
||||||
[DEFAULT_MYSQL_CONFIG_DIR]=MYSQL_CONFIG_DIR
|
|
||||||
[DEFAULT_MYSQL_HOST]=MYSQL_HOST
|
|
||||||
[DEFAULT_DB_WAIT_RETRIES]=DB_WAIT_RETRIES
|
|
||||||
[DEFAULT_DB_WAIT_SLEEP]=DB_WAIT_SLEEP
|
|
||||||
[DEFAULT_DB_RECONNECT_SECONDS]=DB_RECONNECT_SECONDS
|
|
||||||
[DEFAULT_DB_RECONNECT_ATTEMPTS]=DB_RECONNECT_ATTEMPTS
|
|
||||||
[DEFAULT_DB_UPDATES_ALLOWED_MODULES]=DB_UPDATES_ALLOWED_MODULES
|
|
||||||
[DEFAULT_DB_UPDATES_REDUNDANCY]=DB_UPDATES_REDUNDANCY
|
|
||||||
[DEFAULT_DB_LOGIN_WORKER_THREADS]=DB_LOGIN_WORKER_THREADS
|
|
||||||
[DEFAULT_DB_WORLD_WORKER_THREADS]=DB_WORLD_WORKER_THREADS
|
|
||||||
[DEFAULT_DB_CHARACTER_WORKER_THREADS]=DB_CHARACTER_WORKER_THREADS
|
|
||||||
[DEFAULT_DB_LOGIN_SYNCH_THREADS]=DB_LOGIN_SYNCH_THREADS
|
|
||||||
[DEFAULT_DB_WORLD_SYNCH_THREADS]=DB_WORLD_SYNCH_THREADS
|
|
||||||
[DEFAULT_DB_CHARACTER_SYNCH_THREADS]=DB_CHARACTER_SYNCH_THREADS
|
|
||||||
[DEFAULT_HOST_ZONEINFO_PATH]=HOST_ZONEINFO_PATH
|
|
||||||
[DEFAULT_ELUNA_SCRIPT_PATH]=AC_ELUNA_SCRIPT_PATH
|
|
||||||
[DEFAULT_PMA_EXTERNAL_PORT]=PMA_EXTERNAL_PORT
|
|
||||||
[DEFAULT_PMA_UPLOAD_LIMIT]=PMA_UPLOAD_LIMIT
|
|
||||||
[DEFAULT_PMA_MEMORY_LIMIT]=PMA_MEMORY_LIMIT
|
|
||||||
[DEFAULT_PMA_MAX_EXECUTION_TIME]=PMA_MAX_EXECUTION_TIME
|
|
||||||
[DEFAULT_KEIRA3_EXTERNAL_PORT]=KEIRA3_EXTERNAL_PORT
|
|
||||||
[DEFAULT_PMA_USER]=PMA_USER
|
|
||||||
[DEFAULT_PMA_ARBITRARY]=PMA_ARBITRARY
|
|
||||||
[DEFAULT_PMA_ABSOLUTE_URI]=PMA_ABSOLUTE_URI
|
|
||||||
[DEFAULT_AUTH_INTERNAL_PORT]=AUTH_PORT
|
|
||||||
[DEFAULT_WORLD_INTERNAL_PORT]=WORLD_PORT
|
|
||||||
[DEFAULT_SOAP_INTERNAL_PORT]=SOAP_PORT
|
|
||||||
[DEFAULT_MYSQL_INTERNAL_PORT]=MYSQL_PORT
|
|
||||||
[DEFAULT_TZ]=TZ
|
|
||||||
[DEFAULT_MYSQL_ROOT_HOST]=MYSQL_ROOT_HOST
|
|
||||||
[DEFAULT_MYSQL_USER]=MYSQL_USER
|
|
||||||
[DEFAULT_ELUNA_ENABLED]=AC_ELUNA_ENABLED
|
|
||||||
[DEFAULT_ELUNA_TRACE_BACK]=AC_ELUNA_TRACE_BACK
|
|
||||||
[DEFAULT_ELUNA_AUTO_RELOAD]=AC_ELUNA_AUTO_RELOAD
|
|
||||||
[DEFAULT_ELUNA_BYTECODE_CACHE]=AC_ELUNA_BYTECODE_CACHE
|
|
||||||
[DEFAULT_ELUNA_AUTO_RELOAD_INTERVAL]=AC_ELUNA_AUTO_RELOAD_INTERVAL
|
|
||||||
[DEFAULT_ELUNA_REQUIRE_PATHS]=AC_ELUNA_REQUIRE_PATHS
|
|
||||||
[DEFAULT_ELUNA_REQUIRE_CPATHS]=AC_ELUNA_REQUIRE_CPATHS
|
|
||||||
[DEFAULT_MODULE_ELUNA]=MODULE_ELUNA
|
|
||||||
)
|
|
||||||
|
|
||||||
for __template_var in "${!TEMPLATE_VALUE_MAP[@]}"; do
|
|
||||||
__template_key="${TEMPLATE_VALUE_MAP[$__template_var]}"
|
|
||||||
__template_value="$(get_template_value "${__template_key}")"
|
|
||||||
printf -v "${__template_var}" '%s' "${__template_value}"
|
|
||||||
readonly "${__template_var}"
|
|
||||||
done
|
|
||||||
unset __template_var __template_key __template_value
|
|
||||||
|
|
||||||
# Static values
|
|
||||||
readonly DEFAULT_FALLBACK_LAN_IP="192.168.1.100"
|
|
||||||
readonly DEFAULT_DOMAIN_PLACEHOLDER="your-domain.com"
|
|
||||||
|
|
||||||
# Module preset names (not in template)
|
|
||||||
readonly DEFAULT_PRESET_SUGGESTED="suggested-modules"
|
|
||||||
readonly DEFAULT_PRESET_PLAYERBOTS="suggested-modules-playerbots"
|
|
||||||
|
|
||||||
# Health check configuration (loaded via loop)
|
|
||||||
readonly -a HEALTHCHECK_KEYS=(
|
|
||||||
MYSQL_HEALTHCHECK_INTERVAL
|
|
||||||
MYSQL_HEALTHCHECK_TIMEOUT
|
|
||||||
MYSQL_HEALTHCHECK_RETRIES
|
|
||||||
MYSQL_HEALTHCHECK_START_PERIOD
|
|
||||||
AUTH_HEALTHCHECK_INTERVAL
|
|
||||||
AUTH_HEALTHCHECK_TIMEOUT
|
|
||||||
AUTH_HEALTHCHECK_RETRIES
|
|
||||||
AUTH_HEALTHCHECK_START_PERIOD
|
|
||||||
WORLD_HEALTHCHECK_INTERVAL
|
|
||||||
WORLD_HEALTHCHECK_TIMEOUT
|
|
||||||
WORLD_HEALTHCHECK_RETRIES
|
|
||||||
WORLD_HEALTHCHECK_START_PERIOD
|
|
||||||
BACKUP_HEALTHCHECK_INTERVAL
|
|
||||||
BACKUP_HEALTHCHECK_TIMEOUT
|
|
||||||
BACKUP_HEALTHCHECK_RETRIES
|
|
||||||
BACKUP_HEALTHCHECK_START_PERIOD
|
|
||||||
)
|
|
||||||
for __hc_key in "${HEALTHCHECK_KEYS[@]}"; do
|
|
||||||
__hc_value="$(get_template_value "${__hc_key}")"
|
|
||||||
printf -v "DEFAULT_${__hc_key}" '%s' "$__hc_value"
|
|
||||||
readonly "DEFAULT_${__hc_key}"
|
|
||||||
done
|
|
||||||
unset __hc_key __hc_value
|
|
||||||
|
|
||||||
# Route detection IP (not in template)
|
|
||||||
readonly ROUTE_DETECTION_IP="1.1.1.1"
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
# .env rendering helpers for setup.sh
|
|
||||||
|
|
||||||
setup_write_env() {
|
|
||||||
local ENV_OUT="$(dirname "$0")/.env"
|
|
||||||
if [ -f "$ENV_OUT" ]; then
|
|
||||||
say WARNING ".env already exists at $(realpath "$ENV_OUT" 2>/dev/null || echo "$ENV_OUT"). It will be overwritten."
|
|
||||||
local cont
|
|
||||||
if [ "$FORCE_OVERWRITE" = "1" ]; then
|
|
||||||
cont=1
|
|
||||||
else
|
|
||||||
cont=$(ask_yn "Continue and overwrite?" n)
|
|
||||||
fi
|
|
||||||
[ "$cont" = "1" ] || { say ERROR "Aborted"; exit 1; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-$DEFAULT_DB_PLAYERBOTS_NAME}
|
|
||||||
HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-$DEFAULT_HOST_ZONEINFO_PATH}
|
|
||||||
MYSQL_INNODB_REDO_LOG_CAPACITY=${MYSQL_INNODB_REDO_LOG_CAPACITY:-$DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY}
|
|
||||||
MYSQL_RUNTIME_TMPFS_SIZE=${MYSQL_RUNTIME_TMPFS_SIZE:-$DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE}
|
|
||||||
COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED=${COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED:-$DEFAULT_COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED}
|
|
||||||
COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED=${COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED:-$DEFAULT_COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED}
|
|
||||||
MYSQL_DISABLE_BINLOG=${MYSQL_DISABLE_BINLOG:-$DEFAULT_MYSQL_DISABLE_BINLOG}
|
|
||||||
MYSQL_CONFIG_DIR=${MYSQL_CONFIG_DIR:-$DEFAULT_MYSQL_CONFIG_DIR}
|
|
||||||
CLIENT_DATA_PATH=${CLIENT_DATA_PATH:-$DEFAULT_CLIENT_DATA_PATH}
|
|
||||||
BACKUP_HEALTHCHECK_MAX_MINUTES=${BACKUP_HEALTHCHECK_MAX_MINUTES:-$DEFAULT_BACKUP_HEALTHCHECK_MAX_MINUTES}
|
|
||||||
BACKUP_HEALTHCHECK_GRACE_SECONDS=${BACKUP_HEALTHCHECK_GRACE_SECONDS:-$DEFAULT_BACKUP_HEALTHCHECK_GRACE_SECONDS}
|
|
||||||
DB_WAIT_RETRIES=${DB_WAIT_RETRIES:-$DEFAULT_DB_WAIT_RETRIES}
|
|
||||||
DB_WAIT_SLEEP=${DB_WAIT_SLEEP:-$DEFAULT_DB_WAIT_SLEEP}
|
|
||||||
DB_RECONNECT_SECONDS=${DB_RECONNECT_SECONDS:-$DEFAULT_DB_RECONNECT_SECONDS}
|
|
||||||
DB_RECONNECT_ATTEMPTS=${DB_RECONNECT_ATTEMPTS:-$DEFAULT_DB_RECONNECT_ATTEMPTS}
|
|
||||||
DB_UPDATES_ALLOWED_MODULES=${DB_UPDATES_ALLOWED_MODULES:-$DEFAULT_DB_UPDATES_ALLOWED_MODULES}
|
|
||||||
DB_UPDATES_REDUNDANCY=${DB_UPDATES_REDUNDANCY:-$DEFAULT_DB_UPDATES_REDUNDANCY}
|
|
||||||
DB_LOGIN_WORKER_THREADS=${DB_LOGIN_WORKER_THREADS:-$DEFAULT_DB_LOGIN_WORKER_THREADS}
|
|
||||||
DB_WORLD_WORKER_THREADS=${DB_WORLD_WORKER_THREADS:-$DEFAULT_DB_WORLD_WORKER_THREADS}
|
|
||||||
DB_CHARACTER_WORKER_THREADS=${DB_CHARACTER_WORKER_THREADS:-$DEFAULT_DB_CHARACTER_WORKER_THREADS}
|
|
||||||
DB_LOGIN_SYNCH_THREADS=${DB_LOGIN_SYNCH_THREADS:-$DEFAULT_DB_LOGIN_SYNCH_THREADS}
|
|
||||||
DB_WORLD_SYNCH_THREADS=${DB_WORLD_SYNCH_THREADS:-$DEFAULT_DB_WORLD_SYNCH_THREADS}
|
|
||||||
DB_CHARACTER_SYNCH_THREADS=${DB_CHARACTER_SYNCH_THREADS:-$DEFAULT_DB_CHARACTER_SYNCH_THREADS}
|
|
||||||
MYSQL_HEALTHCHECK_INTERVAL=${MYSQL_HEALTHCHECK_INTERVAL:-$DEFAULT_MYSQL_HEALTHCHECK_INTERVAL}
|
|
||||||
MYSQL_HEALTHCHECK_TIMEOUT=${MYSQL_HEALTHCHECK_TIMEOUT:-$DEFAULT_MYSQL_HEALTHCHECK_TIMEOUT}
|
|
||||||
MYSQL_HEALTHCHECK_RETRIES=${MYSQL_HEALTHCHECK_RETRIES:-$DEFAULT_MYSQL_HEALTHCHECK_RETRIES}
|
|
||||||
MYSQL_HEALTHCHECK_START_PERIOD=${MYSQL_HEALTHCHECK_START_PERIOD:-$DEFAULT_MYSQL_HEALTHCHECK_START_PERIOD}
|
|
||||||
AUTH_HEALTHCHECK_INTERVAL=${AUTH_HEALTHCHECK_INTERVAL:-$DEFAULT_AUTH_HEALTHCHECK_INTERVAL}
|
|
||||||
AUTH_HEALTHCHECK_TIMEOUT=${AUTH_HEALTHCHECK_TIMEOUT:-$DEFAULT_AUTH_HEALTHCHECK_TIMEOUT}
|
|
||||||
AUTH_HEALTHCHECK_RETRIES=${AUTH_HEALTHCHECK_RETRIES:-$DEFAULT_AUTH_HEALTHCHECK_RETRIES}
|
|
||||||
AUTH_HEALTHCHECK_START_PERIOD=${AUTH_HEALTHCHECK_START_PERIOD:-$DEFAULT_AUTH_HEALTHCHECK_START_PERIOD}
|
|
||||||
WORLD_HEALTHCHECK_INTERVAL=${WORLD_HEALTHCHECK_INTERVAL:-$DEFAULT_WORLD_HEALTHCHECK_INTERVAL}
|
|
||||||
WORLD_HEALTHCHECK_TIMEOUT=${WORLD_HEALTHCHECK_TIMEOUT:-$DEFAULT_WORLD_HEALTHCHECK_TIMEOUT}
|
|
||||||
WORLD_HEALTHCHECK_RETRIES=${WORLD_HEALTHCHECK_RETRIES:-$DEFAULT_WORLD_HEALTHCHECK_RETRIES}
|
|
||||||
WORLD_HEALTHCHECK_START_PERIOD=${WORLD_HEALTHCHECK_START_PERIOD:-$DEFAULT_WORLD_HEALTHCHECK_START_PERIOD}
|
|
||||||
for hc_key in "${HEALTHCHECK_KEYS[@]}"; do
|
|
||||||
default_var="DEFAULT_${hc_key}"
|
|
||||||
printf -v "$hc_key" '%s' "${!hc_key:-${!default_var}}"
|
|
||||||
done
|
|
||||||
unset hc_key default_var
|
|
||||||
MODULE_ELUNA=${MODULE_ELUNA:-$DEFAULT_MODULE_ELUNA}
|
|
||||||
BACKUP_PATH=${BACKUP_PATH:-$DEFAULT_BACKUP_PATH}
|
|
||||||
|
|
||||||
local project_image_prefix
|
|
||||||
project_image_prefix="$(sanitize_project_name "$DEFAULT_PROJECT_NAME")"
|
|
||||||
if [ "$STACK_IMAGE_MODE" = "playerbots" ]; then
|
|
||||||
AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$(resolve_project_image_tag "$project_image_prefix" "authserver-playerbots")"
|
|
||||||
AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$(resolve_project_image_tag "$project_image_prefix" "worldserver-playerbots")"
|
|
||||||
AC_DB_IMPORT_IMAGE_VALUE="$(resolve_project_image_tag "$project_image_prefix" "db-import-playerbots")"
|
|
||||||
AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE="$(resolve_project_image_tag "$project_image_prefix" "client-data-playerbots")"
|
|
||||||
else
|
|
||||||
AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_AUTH_IMAGE_PLAYERBOTS"
|
|
||||||
AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_WORLD_IMAGE_PLAYERBOTS"
|
|
||||||
AC_DB_IMPORT_IMAGE_VALUE="$DEFAULT_AC_DB_IMPORT_IMAGE"
|
|
||||||
AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_CLIENT_DATA_IMAGE_PLAYERBOTS"
|
|
||||||
fi
|
|
||||||
AC_AUTHSERVER_IMAGE_MODULES_VALUE="$(resolve_project_image_tag "$project_image_prefix" "authserver-modules-latest")"
|
|
||||||
AC_WORLDSERVER_IMAGE_MODULES_VALUE="$(resolve_project_image_tag "$project_image_prefix" "worldserver-modules-latest")"
|
|
||||||
|
|
||||||
{
|
|
||||||
cat <<EOF
|
|
||||||
# Generated by setup.sh
|
|
||||||
|
|
||||||
# Compose overrides (set to 1 to include matching file under compose-overrides/)
|
|
||||||
# mysql-expose.yml -> exposes MySQL externally via COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED
|
|
||||||
# worldserver-debug-logging.yml -> raises log verbosity via COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED
|
|
||||||
COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED=$COMPOSE_OVERRIDE_MYSQL_EXPOSE_ENABLED
|
|
||||||
COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED=$COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED
|
|
||||||
|
|
||||||
COMPOSE_PROJECT_NAME=$DEFAULT_PROJECT_NAME
|
|
||||||
|
|
||||||
STORAGE_PATH=$STORAGE_PATH
|
|
||||||
STORAGE_PATH_LOCAL=$LOCAL_STORAGE_ROOT
|
|
||||||
STORAGE_CONFIG_PATH=$(get_template_value "STORAGE_CONFIG_PATH")
|
|
||||||
STORAGE_LOGS_PATH=$(get_template_value "STORAGE_LOGS_PATH")
|
|
||||||
STORAGE_MODULES_PATH=$(get_template_value "STORAGE_MODULES_PATH")
|
|
||||||
STORAGE_LUA_SCRIPTS_PATH=$(get_template_value "STORAGE_LUA_SCRIPTS_PATH")
|
|
||||||
STORAGE_MODULES_META_PATH=$(get_template_value "STORAGE_MODULES_META_PATH")
|
|
||||||
STORAGE_MODULE_SQL_PATH=$(get_template_value "STORAGE_MODULE_SQL_PATH")
|
|
||||||
STORAGE_INSTALL_MARKERS_PATH=$(get_template_value "STORAGE_INSTALL_MARKERS_PATH")
|
|
||||||
STORAGE_CLIENT_DATA_PATH=$(get_template_value "STORAGE_CLIENT_DATA_PATH")
|
|
||||||
STORAGE_LOCAL_SOURCE_PATH=$(get_template_value "STORAGE_LOCAL_SOURCE_PATH")
|
|
||||||
BACKUP_PATH=$BACKUP_PATH
|
|
||||||
TZ=$DEFAULT_TZ
|
|
||||||
|
|
||||||
# Database
|
|
||||||
MYSQL_IMAGE=$DEFAULT_MYSQL_IMAGE
|
|
||||||
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
|
|
||||||
MYSQL_ROOT_HOST=$DEFAULT_MYSQL_ROOT_HOST
|
|
||||||
MYSQL_USER=$DEFAULT_MYSQL_USER
|
|
||||||
MYSQL_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
|
|
||||||
MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_PORT
|
|
||||||
MYSQL_DISABLE_BINLOG=${MYSQL_DISABLE_BINLOG:-$DEFAULT_MYSQL_DISABLE_BINLOG}
|
|
||||||
MYSQL_CONFIG_DIR=${MYSQL_CONFIG_DIR:-$DEFAULT_MYSQL_CONFIG_DIR}
|
|
||||||
MYSQL_CHARACTER_SET=$DEFAULT_MYSQL_CHARACTER_SET
|
|
||||||
MYSQL_COLLATION=$DEFAULT_MYSQL_COLLATION
|
|
||||||
MYSQL_MAX_CONNECTIONS=$DEFAULT_MYSQL_MAX_CONNECTIONS
|
|
||||||
MYSQL_INNODB_BUFFER_POOL_SIZE=$DEFAULT_MYSQL_INNODB_BUFFER_POOL_SIZE
|
|
||||||
MYSQL_INNODB_LOG_FILE_SIZE=$DEFAULT_MYSQL_INNODB_LOG_FILE_SIZE
|
|
||||||
MYSQL_INNODB_REDO_LOG_CAPACITY=${MYSQL_INNODB_REDO_LOG_CAPACITY:-$DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY}
|
|
||||||
MYSQL_RUNTIME_TMPFS_SIZE=${MYSQL_RUNTIME_TMPFS_SIZE:-$DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE}
|
|
||||||
MYSQL_HOST=$DEFAULT_MYSQL_HOST
|
|
||||||
DB_WAIT_RETRIES=$DB_WAIT_RETRIES
|
|
||||||
DB_WAIT_SLEEP=$DB_WAIT_SLEEP
|
|
||||||
DB_AUTH_NAME=$DEFAULT_DB_AUTH_NAME
|
|
||||||
DB_WORLD_NAME=$DEFAULT_DB_WORLD_NAME
|
|
||||||
DB_CHARACTERS_NAME=$DEFAULT_DB_CHARACTERS_NAME
|
|
||||||
DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-$DEFAULT_DB_PLAYERBOTS_NAME}
|
|
||||||
AC_DB_IMPORT_IMAGE=$AC_DB_IMPORT_IMAGE_VALUE
|
|
||||||
|
|
||||||
# Database Import Settings
|
|
||||||
DB_RECONNECT_SECONDS=$DB_RECONNECT_SECONDS
|
|
||||||
DB_RECONNECT_ATTEMPTS=$DB_RECONNECT_ATTEMPTS
|
|
||||||
DB_UPDATES_ALLOWED_MODULES=$DB_UPDATES_ALLOWED_MODULES
|
|
||||||
DB_UPDATES_REDUNDANCY=$DB_UPDATES_REDUNDANCY
|
|
||||||
DB_LOGIN_WORKER_THREADS=$DB_LOGIN_WORKER_THREADS
|
|
||||||
DB_WORLD_WORKER_THREADS=$DB_WORLD_WORKER_THREADS
|
|
||||||
DB_CHARACTER_WORKER_THREADS=$DB_CHARACTER_WORKER_THREADS
|
|
||||||
DB_LOGIN_SYNCH_THREADS=$DB_LOGIN_SYNCH_THREADS
|
|
||||||
DB_WORLD_SYNCH_THREADS=$DB_WORLD_SYNCH_THREADS
|
|
||||||
DB_CHARACTER_SYNCH_THREADS=$DB_CHARACTER_SYNCH_THREADS
|
|
||||||
|
|
||||||
# Services (images)
|
|
||||||
AC_AUTHSERVER_IMAGE=$DEFAULT_AC_AUTHSERVER_IMAGE
|
|
||||||
AC_WORLDSERVER_IMAGE=$DEFAULT_AC_WORLDSERVER_IMAGE
|
|
||||||
AC_AUTHSERVER_IMAGE_PLAYERBOTS=${AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE}
|
|
||||||
AC_WORLDSERVER_IMAGE_PLAYERBOTS=${AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE}
|
|
||||||
AC_AUTHSERVER_IMAGE_MODULES=${AC_AUTHSERVER_IMAGE_MODULES_VALUE}
|
|
||||||
AC_WORLDSERVER_IMAGE_MODULES=${AC_WORLDSERVER_IMAGE_MODULES_VALUE}
|
|
||||||
|
|
||||||
# Client data images
|
|
||||||
AC_CLIENT_DATA_IMAGE=$DEFAULT_AC_CLIENT_DATA_IMAGE
|
|
||||||
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=$AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE
|
|
||||||
CLIENT_DATA_CACHE_PATH=$DEFAULT_CLIENT_DATA_CACHE_PATH
|
|
||||||
CLIENT_DATA_PATH=$CLIENT_DATA_PATH
|
|
||||||
|
|
||||||
# Build artifacts
|
|
||||||
DOCKER_IMAGE_TAG=$DEFAULT_DOCKER_IMAGE_TAG
|
|
||||||
AC_AUTHSERVER_IMAGE_BASE=$DEFAULT_AUTHSERVER_IMAGE_BASE
|
|
||||||
AC_WORLDSERVER_IMAGE_BASE=$DEFAULT_WORLDSERVER_IMAGE_BASE
|
|
||||||
AC_DB_IMPORT_IMAGE_BASE=$DEFAULT_DB_IMPORT_IMAGE_BASE
|
|
||||||
AC_CLIENT_DATA_IMAGE_BASE=$DEFAULT_CLIENT_DATA_IMAGE_BASE
|
|
||||||
|
|
||||||
# Container user
|
|
||||||
CONTAINER_USER=$CONTAINER_USER
|
|
||||||
|
|
||||||
# Containers
|
|
||||||
CONTAINER_MYSQL=$DEFAULT_CONTAINER_MYSQL
|
|
||||||
CONTAINER_DB_IMPORT=$DEFAULT_CONTAINER_DB_IMPORT
|
|
||||||
CONTAINER_DB_INIT=$DEFAULT_CONTAINER_DB_INIT
|
|
||||||
CONTAINER_DB_GUARD=$(get_template_value "CONTAINER_DB_GUARD")
|
|
||||||
CONTAINER_BACKUP=$DEFAULT_CONTAINER_BACKUP
|
|
||||||
CONTAINER_MODULES=$DEFAULT_CONTAINER_MODULES
|
|
||||||
CONTAINER_POST_INSTALL=$DEFAULT_CONTAINER_POST_INSTALL
|
|
||||||
|
|
||||||
# Database Guard Defaults
|
|
||||||
DB_GUARD_RECHECK_SECONDS=$(get_template_value "DB_GUARD_RECHECK_SECONDS")
|
|
||||||
DB_GUARD_RETRY_SECONDS=$(get_template_value "DB_GUARD_RETRY_SECONDS")
|
|
||||||
DB_GUARD_WAIT_ATTEMPTS=$(get_template_value "DB_GUARD_WAIT_ATTEMPTS")
|
|
||||||
DB_GUARD_HEALTH_MAX_AGE=$(get_template_value "DB_GUARD_HEALTH_MAX_AGE")
|
|
||||||
DB_GUARD_HEALTHCHECK_INTERVAL=$(get_template_value "DB_GUARD_HEALTHCHECK_INTERVAL")
|
|
||||||
DB_GUARD_HEALTHCHECK_TIMEOUT=$(get_template_value "DB_GUARD_HEALTHCHECK_TIMEOUT")
|
|
||||||
DB_GUARD_HEALTHCHECK_RETRIES=$(get_template_value "DB_GUARD_HEALTHCHECK_RETRIES")
|
|
||||||
DB_GUARD_VERIFY_INTERVAL_SECONDS=$(get_template_value "DB_GUARD_VERIFY_INTERVAL_SECONDS")
|
|
||||||
|
|
||||||
# Module SQL staging
|
|
||||||
STAGE_PATH_MODULE_SQL=$(get_template_value "STAGE_PATH_MODULE_SQL")
|
|
||||||
|
|
||||||
# Modules rebuild source path
|
|
||||||
MODULES_REBUILD_SOURCE_PATH=$MODULES_REBUILD_SOURCE_PATH
|
|
||||||
|
|
||||||
# SQL Source Overlay
|
|
||||||
SOURCE_DIR=$(get_template_value "SOURCE_DIR")
|
|
||||||
AC_SQL_SOURCE_PATH=$(get_template_value "AC_SQL_SOURCE_PATH")
|
|
||||||
|
|
||||||
# Ports
|
|
||||||
AUTH_EXTERNAL_PORT=$AUTH_EXTERNAL_PORT
|
|
||||||
AUTH_PORT=$DEFAULT_AUTH_INTERNAL_PORT
|
|
||||||
WORLD_EXTERNAL_PORT=$REALM_PORT
|
|
||||||
WORLD_PORT=$DEFAULT_WORLD_INTERNAL_PORT
|
|
||||||
SOAP_EXTERNAL_PORT=$SOAP_EXTERNAL_PORT
|
|
||||||
SOAP_PORT=$DEFAULT_SOAP_INTERNAL_PORT
|
|
||||||
|
|
||||||
# Realm
|
|
||||||
SERVER_ADDRESS=$SERVER_ADDRESS
|
|
||||||
REALM_PORT=$REALM_PORT
|
|
||||||
|
|
||||||
# Backups
|
|
||||||
BACKUP_RETENTION_DAYS=$BACKUP_RETENTION_DAYS
|
|
||||||
BACKUP_RETENTION_HOURS=$BACKUP_RETENTION_HOURS
|
|
||||||
BACKUP_DAILY_TIME=$BACKUP_DAILY_TIME
|
|
||||||
BACKUP_INTERVAL_MINUTES=$(get_template_value "BACKUP_INTERVAL_MINUTES")
|
|
||||||
BACKUP_EXTRA_DATABASES=$(get_template_value "BACKUP_EXTRA_DATABASES")
|
|
||||||
BACKUP_HEALTHCHECK_MAX_MINUTES=$BACKUP_HEALTHCHECK_MAX_MINUTES
|
|
||||||
BACKUP_HEALTHCHECK_GRACE_SECONDS=$BACKUP_HEALTHCHECK_GRACE_SECONDS
|
|
||||||
|
|
||||||
EOF
|
|
||||||
echo
|
|
||||||
echo "# Modules"
|
|
||||||
for module_key in "${MODULE_KEYS[@]}"; do
|
|
||||||
local module_value="${!module_key:-0}"
|
|
||||||
# Only write enabled modules (value=1) to .env
|
|
||||||
if [ "$module_value" = "1" ]; then
|
|
||||||
printf "%s=%s\n" "$module_key" "$module_value"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
cat <<EOF
|
|
||||||
|
|
||||||
# Client data
|
|
||||||
CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-$DEFAULT_CLIENT_DATA_VERSION}
|
|
||||||
|
|
||||||
# Server configuration
|
|
||||||
SERVER_CONFIG_PRESET=$SERVER_CONFIG_PRESET
|
|
||||||
|
|
||||||
# Playerbot runtime
|
|
||||||
PLAYERBOT_ENABLED=$PLAYERBOT_ENABLED
|
|
||||||
PLAYERBOT_MIN_BOTS=$PLAYERBOT_MIN_BOTS
|
|
||||||
PLAYERBOT_MAX_BOTS=$PLAYERBOT_MAX_BOTS
|
|
||||||
STACK_IMAGE_MODE=$STACK_IMAGE_MODE
|
|
||||||
STACK_SOURCE_VARIANT=$STACK_SOURCE_VARIANT
|
|
||||||
MODULES_ENABLED_LIST=$MODULES_ENABLED_LIST
|
|
||||||
MODULES_CPP_LIST=$MODULES_CPP_LIST
|
|
||||||
MODULES_REQUIRES_CUSTOM_BUILD=$MODULES_REQUIRES_CUSTOM_BUILD
|
|
||||||
MODULES_REQUIRES_PLAYERBOT_SOURCE=$MODULES_REQUIRES_PLAYERBOT_SOURCE
|
|
||||||
|
|
||||||
# Eluna
|
|
||||||
AC_ELUNA_ENABLED=$DEFAULT_ELUNA_ENABLED
|
|
||||||
AC_ELUNA_TRACE_BACK=$DEFAULT_ELUNA_TRACE_BACK
|
|
||||||
AC_ELUNA_AUTO_RELOAD=$DEFAULT_ELUNA_AUTO_RELOAD
|
|
||||||
AC_ELUNA_BYTECODE_CACHE=$DEFAULT_ELUNA_BYTECODE_CACHE
|
|
||||||
AC_ELUNA_SCRIPT_PATH=$DEFAULT_ELUNA_SCRIPT_PATH
|
|
||||||
AC_ELUNA_REQUIRE_PATHS=$DEFAULT_ELUNA_REQUIRE_PATHS
|
|
||||||
AC_ELUNA_REQUIRE_CPATHS=$DEFAULT_ELUNA_REQUIRE_CPATHS
|
|
||||||
AC_ELUNA_AUTO_RELOAD_INTERVAL=$DEFAULT_ELUNA_AUTO_RELOAD_INTERVAL
|
|
||||||
|
|
||||||
# Tools
|
|
||||||
PMA_HOST=$DEFAULT_CONTAINER_MYSQL
|
|
||||||
PMA_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
|
|
||||||
PMA_USER=$DEFAULT_PMA_USER
|
|
||||||
PMA_EXTERNAL_PORT=$DEFAULT_PMA_EXTERNAL_PORT
|
|
||||||
PMA_ARBITRARY=$DEFAULT_PMA_ARBITRARY
|
|
||||||
PMA_ABSOLUTE_URI=$DEFAULT_PMA_ABSOLUTE_URI
|
|
||||||
PMA_UPLOAD_LIMIT=$DEFAULT_PMA_UPLOAD_LIMIT
|
|
||||||
PMA_MEMORY_LIMIT=$DEFAULT_PMA_MEMORY_LIMIT
|
|
||||||
PMA_MAX_EXECUTION_TIME=$DEFAULT_PMA_MAX_EXECUTION_TIME
|
|
||||||
KEIRA3_EXTERNAL_PORT=$DEFAULT_KEIRA3_EXTERNAL_PORT
|
|
||||||
KEIRA_DATABASE_HOST=$DEFAULT_CONTAINER_MYSQL
|
|
||||||
KEIRA_DATABASE_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
|
|
||||||
|
|
||||||
# Health checks
|
|
||||||
EOF
|
|
||||||
for hc_key in "${HEALTHCHECK_KEYS[@]}"; do
|
|
||||||
printf "%s=%s\n" "$hc_key" "${!hc_key}"
|
|
||||||
done
|
|
||||||
cat <<EOF
|
|
||||||
|
|
||||||
# Networking
|
|
||||||
NETWORK_NAME=$DEFAULT_NETWORK_NAME
|
|
||||||
NETWORK_SUBNET=$DEFAULT_NETWORK_SUBNET
|
|
||||||
NETWORK_GATEWAY=$DEFAULT_NETWORK_GATEWAY
|
|
||||||
|
|
||||||
# Storage helpers
|
|
||||||
HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-$DEFAULT_HOST_ZONEINFO_PATH}
|
|
||||||
|
|
||||||
# Helper images
|
|
||||||
ALPINE_GIT_IMAGE=$DEFAULT_ALPINE_GIT_IMAGE
|
|
||||||
ALPINE_IMAGE=$DEFAULT_ALPINE_IMAGE
|
|
||||||
EOF
|
|
||||||
} > "$ENV_OUT"
|
|
||||||
|
|
||||||
local staging_modules_dir="${LOCAL_STORAGE_ROOT_ABS}/modules"
|
|
||||||
mkdir -p "$staging_modules_dir"
|
|
||||||
|
|
||||||
local module_state_string=""
|
|
||||||
for module_state_var in "${MODULE_KEYS[@]}"; do
|
|
||||||
local module_value="${!module_state_var:-0}"
|
|
||||||
module_state_string+="${module_state_var}=${module_value}|"
|
|
||||||
done
|
|
||||||
printf '%s' "$module_state_string" > "${staging_modules_dir}/.modules_state"
|
|
||||||
if [ "$NEEDS_CXX_REBUILD" != "1" ]; then
|
|
||||||
rm -f "${staging_modules_dir}/.requires_rebuild" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
say SUCCESS ".env written to $ENV_OUT"
|
|
||||||
}
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
# Module selection workflow for setup.sh
|
|
||||||
|
|
||||||
setup_select_modules() {
|
|
||||||
local MODE_SELECTION=""
|
|
||||||
local MODE_PRESET_NAME=""
|
|
||||||
declare -A MODULE_PRESET_CONFIGS=()
|
|
||||||
declare -A MODULE_PRESET_LABELS=()
|
|
||||||
declare -A MODULE_PRESET_DESCRIPTIONS=()
|
|
||||||
declare -A MODULE_PRESET_ORDER=()
|
|
||||||
local CONFIG_DIR="$SCRIPT_DIR/config/module-profiles"
|
|
||||||
if [ ! -x "$MODULE_PROFILES_HELPER" ]; then
|
|
||||||
say ERROR "Profile helper not found or not executable at $MODULE_PROFILES_HELPER"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -d "$CONFIG_DIR" ]; then
|
|
||||||
while IFS=$'\t' read -r preset_name preset_modules preset_label preset_desc preset_order; do
|
|
||||||
[ -n "$preset_name" ] || continue
|
|
||||||
MODULE_PRESET_CONFIGS["$preset_name"]="$preset_modules"
|
|
||||||
MODULE_PRESET_LABELS["$preset_name"]="$preset_label"
|
|
||||||
MODULE_PRESET_DESCRIPTIONS["$preset_name"]="$preset_desc"
|
|
||||||
MODULE_PRESET_ORDER["$preset_name"]="${preset_order:-10000}"
|
|
||||||
done < <(python3 "$MODULE_PROFILES_HELPER" list "$CONFIG_DIR")
|
|
||||||
fi
|
|
||||||
|
|
||||||
local missing_presets=0
|
|
||||||
for required_preset in "$DEFAULT_PRESET_SUGGESTED" "$DEFAULT_PRESET_PLAYERBOTS"; do
|
|
||||||
if [ -z "${MODULE_PRESET_CONFIGS[$required_preset]:-}" ]; then
|
|
||||||
say ERROR "Missing module preset config/module-profiles/${required_preset}.json"
|
|
||||||
missing_presets=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$missing_presets" -eq 1 ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$CLI_MODULE_PRESET" ]; then
|
|
||||||
if [ -n "${MODULE_PRESET_CONFIGS[$CLI_MODULE_PRESET]:-}" ]; then
|
|
||||||
MODE_SELECTION="preset"
|
|
||||||
MODE_PRESET_NAME="$CLI_MODULE_PRESET"
|
|
||||||
else
|
|
||||||
say ERROR "Unknown module preset: $CLI_MODULE_PRESET"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$MODE_SELECTION" ] && [ "$MODE_SELECTION" != "preset" ]; then
|
|
||||||
MODE_PRESET_NAME=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$CLI_MODULE_MODE" ]; then
|
|
||||||
case "${CLI_MODULE_MODE,,}" in
|
|
||||||
1|suggested) MODE_SELECTION=1 ;;
|
|
||||||
2|playerbots) MODE_SELECTION=2 ;;
|
|
||||||
3|manual) MODE_SELECTION=3 ;;
|
|
||||||
4|none) MODE_SELECTION=4 ;;
|
|
||||||
*) say ERROR "Invalid module mode: ${CLI_MODULE_MODE}"; exit 1 ;;
|
|
||||||
esac
|
|
||||||
if [ "$MODE_SELECTION" = "1" ]; then
|
|
||||||
MODE_PRESET_NAME="$DEFAULT_PRESET_SUGGESTED"
|
|
||||||
elif [ "$MODE_SELECTION" = "2" ]; then
|
|
||||||
MODE_PRESET_NAME="$DEFAULT_PRESET_PLAYERBOTS"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$MODE_SELECTION" ] && [ ${#MODULE_ENABLE_SET[@]} -gt 0 ]; then
|
|
||||||
MODE_SELECTION=3
|
|
||||||
fi
|
|
||||||
if [ ${#MODULE_ENABLE_SET[@]} -gt 0 ] && [ -n "$MODE_SELECTION" ] && [ "$MODE_SELECTION" != "3" ] && [ "$MODE_SELECTION" != "4" ]; then
|
|
||||||
say INFO "Switching module preset to manual to honor --enable-modules list."
|
|
||||||
MODE_SELECTION=3
|
|
||||||
fi
|
|
||||||
if [ "$MODE_SELECTION" = "4" ] && [ ${#MODULE_ENABLE_SET[@]} -gt 0 ]; then
|
|
||||||
say ERROR "--enable-modules cannot be used together with module-mode=none."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$MODE_SELECTION" = "preset" ] && [ -n "$CLI_MODULE_PRESET" ]; then
|
|
||||||
MODE_PRESET_NAME="$CLI_MODULE_PRESET"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Function to determine source branch for a preset
|
|
||||||
get_preset_source_branch() {
|
|
||||||
local preset_name="$1"
|
|
||||||
local preset_modules="${MODULE_PRESET_CONFIGS[$preset_name]:-}"
|
|
||||||
|
|
||||||
# Check if playerbots module is in the preset
|
|
||||||
if [[ "$preset_modules" == *"MODULE_PLAYERBOTS"* ]]; then
|
|
||||||
echo "azerothcore-playerbots"
|
|
||||||
else
|
|
||||||
echo "azerothcore-wotlk"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Module config
|
|
||||||
say HEADER "MODULE PRESET"
|
|
||||||
printf " %s) %s\n" "1" "⭐ Suggested Modules"
|
|
||||||
printf " %s (%s)\n" "Baseline solo-friendly quality of life mix" "azerothcore-wotlk"
|
|
||||||
printf " %s) %s\n" "2" "🤖 Playerbots + Suggested modules"
|
|
||||||
printf " %s (%s)\n" "Suggested stack plus playerbots enabled" "azerothcore-playerbots"
|
|
||||||
printf " %s) %s\n" "3" "⚙️ Manual selection"
|
|
||||||
printf " %s (%s)\n" "Choose individual modules manually" "(depends on modules)"
|
|
||||||
printf " %s) %s\n" "4" "🚫 No modules"
|
|
||||||
printf " %s (%s)\n" "Pure AzerothCore with no modules" "azerothcore-wotlk"
|
|
||||||
|
|
||||||
local menu_index=5
|
|
||||||
declare -A MENU_PRESET_INDEX=()
|
|
||||||
local -a ORDERED_PRESETS=()
|
|
||||||
for preset_name in "${!MODULE_PRESET_CONFIGS[@]}"; do
|
|
||||||
if [ "$preset_name" = "$DEFAULT_PRESET_SUGGESTED" ] || [ "$preset_name" = "$DEFAULT_PRESET_PLAYERBOTS" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
local order="${MODULE_PRESET_ORDER[$preset_name]:-10000}"
|
|
||||||
ORDERED_PRESETS+=("$(printf '%05d::%s' "$order" "$preset_name")")
|
|
||||||
done
|
|
||||||
if [ ${#ORDERED_PRESETS[@]} -gt 0 ]; then
|
|
||||||
IFS=$'\n' ORDERED_PRESETS=($(printf '%s\n' "${ORDERED_PRESETS[@]}" | sort))
|
|
||||||
fi
|
|
||||||
|
|
||||||
for entry in "${ORDERED_PRESETS[@]}"; do
|
|
||||||
local preset_name="${entry#*::}"
|
|
||||||
[ -n "${MODULE_PRESET_CONFIGS[$preset_name]:-}" ] || continue
|
|
||||||
local pretty_name preset_desc
|
|
||||||
if [ -n "${MODULE_PRESET_LABELS[$preset_name]:-}" ]; then
|
|
||||||
pretty_name="${MODULE_PRESET_LABELS[$preset_name]}"
|
|
||||||
else
|
|
||||||
pretty_name=$(echo "$preset_name" | tr '_-' ' ' | awk '{for(i=1;i<=NF;i++){$i=toupper(substr($i,1,1)) substr($i,2)}}1')
|
|
||||||
fi
|
|
||||||
preset_desc="${MODULE_PRESET_DESCRIPTIONS[$preset_name]:-No description available}"
|
|
||||||
local source_branch
|
|
||||||
source_branch=$(get_preset_source_branch "$preset_name")
|
|
||||||
printf " %s) %s\n" "$menu_index" "$pretty_name"
|
|
||||||
printf " %s (%s)\n" "$preset_desc" "$source_branch"
|
|
||||||
MENU_PRESET_INDEX[$menu_index]="$preset_name"
|
|
||||||
menu_index=$((menu_index + 1))
|
|
||||||
done
|
|
||||||
local max_option=$((menu_index - 1))
|
|
||||||
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ] && [ -z "$MODE_SELECTION" ]; then
|
|
||||||
MODE_SELECTION=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$MODE_SELECTION" ]; then
|
|
||||||
local selection_input
|
|
||||||
while true; do
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 Select module configuration [1-${max_option}]: ${NC}")" selection_input
|
|
||||||
if [[ "$selection_input" =~ ^[0-9]+$ ]] && [ "$selection_input" -ge 1 ] && [ "$selection_input" -le "$max_option" ]; then
|
|
||||||
if [ -n "${MENU_PRESET_INDEX[$selection_input]:-}" ]; then
|
|
||||||
MODE_SELECTION="preset"
|
|
||||||
MODE_PRESET_NAME="${MENU_PRESET_INDEX[$selection_input]}"
|
|
||||||
else
|
|
||||||
MODE_SELECTION="$selection_input"
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
say ERROR "Please select a number between 1 and ${max_option}"
|
|
||||||
done
|
|
||||||
else
|
|
||||||
if [ "$MODE_SELECTION" = "preset" ]; then
|
|
||||||
say INFO "Module preset set to ${MODE_PRESET_NAME}."
|
|
||||||
else
|
|
||||||
say INFO "Module preset set to ${MODE_SELECTION}."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
local AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_AUTH_IMAGE_PLAYERBOTS"
|
|
||||||
local AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_WORLD_IMAGE_PLAYERBOTS"
|
|
||||||
local AC_AUTHSERVER_IMAGE_MODULES_VALUE="$DEFAULT_AUTH_IMAGE_MODULES"
|
|
||||||
local AC_WORLDSERVER_IMAGE_MODULES_VALUE="$DEFAULT_WORLD_IMAGE_MODULES"
|
|
||||||
local AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE="$DEFAULT_CLIENT_DATA_IMAGE_PLAYERBOTS"
|
|
||||||
local AC_DB_IMPORT_IMAGE_VALUE="$DEFAULT_AC_DB_IMPORT_IMAGE"
|
|
||||||
|
|
||||||
local mod_var
|
|
||||||
for mod_var in "${!MODULE_ENABLE_SET[@]}"; do
|
|
||||||
if [ -n "${KNOWN_MODULE_LOOKUP[$mod_var]:-}" ]; then
|
|
||||||
printf -v "$mod_var" '%s' "1"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
auto_enable_module_dependencies
|
|
||||||
ensure_module_platforms
|
|
||||||
|
|
||||||
if [ "${MODULE_OLLAMA_CHAT:-0}" = "1" ] && [ "${MODULE_PLAYERBOTS:-0}" != "1" ]; then
|
|
||||||
say INFO "Automatically enabling MODULE_PLAYERBOTS for MODULE_OLLAMA_CHAT."
|
|
||||||
MODULE_PLAYERBOTS=1
|
|
||||||
MODULE_ENABLE_SET["MODULE_PLAYERBOTS"]=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
declare -A DISABLED_MODULE_REASONS=(
|
|
||||||
[MODULE_AHBOT]="Requires upstream Addmod_ahbotScripts symbol (fails link)"
|
|
||||||
[MODULE_LEVEL_GRANT]="QuestCountLevel module relies on removed ConfigMgr APIs and fails to build"
|
|
||||||
)
|
|
||||||
|
|
||||||
PLAYERBOT_ENABLED=0
|
|
||||||
PLAYERBOT_MIN_BOTS="${DEFAULT_PLAYERBOT_MIN:-40}"
|
|
||||||
PLAYERBOT_MAX_BOTS="${DEFAULT_PLAYERBOT_MAX:-40}"
|
|
||||||
|
|
||||||
NEEDS_CXX_REBUILD=0
|
|
||||||
|
|
||||||
local module_mode_label=""
|
|
||||||
if [ "$MODE_SELECTION" = "1" ]; then
|
|
||||||
MODE_PRESET_NAME="$DEFAULT_PRESET_SUGGESTED"
|
|
||||||
apply_module_preset "${MODULE_PRESET_CONFIGS[$DEFAULT_PRESET_SUGGESTED]}"
|
|
||||||
local preset_label="${MODULE_PRESET_LABELS[$DEFAULT_PRESET_SUGGESTED]:-Suggested Modules}"
|
|
||||||
module_mode_label="preset 1 (${preset_label})"
|
|
||||||
elif [ "$MODE_SELECTION" = "2" ]; then
|
|
||||||
MODE_PRESET_NAME="$DEFAULT_PRESET_PLAYERBOTS"
|
|
||||||
apply_module_preset "${MODULE_PRESET_CONFIGS[$DEFAULT_PRESET_PLAYERBOTS]}"
|
|
||||||
local preset_label="${MODULE_PRESET_LABELS[$DEFAULT_PRESET_PLAYERBOTS]:-Playerbots + Suggested}"
|
|
||||||
module_mode_label="preset 2 (${preset_label})"
|
|
||||||
elif [ "$MODE_SELECTION" = "3" ]; then
|
|
||||||
MODE_PRESET_NAME=""
|
|
||||||
say INFO "Answer y/n for each module (organized by category)"
|
|
||||||
for key in "${!DISABLED_MODULE_REASONS[@]}"; do
|
|
||||||
say WARNING "${key#MODULE_}: ${DISABLED_MODULE_REASONS[$key]}"
|
|
||||||
done
|
|
||||||
local -a selection_keys=("${MODULE_KEYS_SORTED[@]}")
|
|
||||||
if [ ${#selection_keys[@]} -eq 0 ]; then
|
|
||||||
selection_keys=("${MODULE_KEYS[@]}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Define category display order and titles
|
|
||||||
local -a category_order=(
|
|
||||||
"automation" "quality-of-life" "gameplay-enhancement" "npc-service"
|
|
||||||
"pvp" "progression" "economy" "social" "account-wide"
|
|
||||||
"customization" "scripting" "admin" "premium" "minigame"
|
|
||||||
"content" "rewards" "developer" "database" "tooling" "uncategorized"
|
|
||||||
)
|
|
||||||
declare -A category_titles=(
|
|
||||||
["automation"]="🤖 Automation"
|
|
||||||
["quality-of-life"]="✨ Quality of Life"
|
|
||||||
["gameplay-enhancement"]="⚔️ Gameplay Enhancement"
|
|
||||||
["npc-service"]="🏪 NPC Services"
|
|
||||||
["pvp"]="⚡ PvP"
|
|
||||||
["progression"]="📈 Progression"
|
|
||||||
["economy"]="💰 Economy"
|
|
||||||
["social"]="👥 Social"
|
|
||||||
["account-wide"]="👤 Account-Wide"
|
|
||||||
["customization"]="🎨 Customization"
|
|
||||||
["scripting"]="📜 Scripting"
|
|
||||||
["admin"]="🔧 Admin Tools"
|
|
||||||
["premium"]="💎 Premium/VIP"
|
|
||||||
["minigame"]="🎮 Mini-Games"
|
|
||||||
["content"]="🏰 Content"
|
|
||||||
["rewards"]="🎁 Rewards"
|
|
||||||
["developer"]="🛠️ Developer Tools"
|
|
||||||
["database"]="🗄️ Database"
|
|
||||||
["tooling"]="🔨 Tooling"
|
|
||||||
["uncategorized"]="📦 Miscellaneous"
|
|
||||||
)
|
|
||||||
declare -A processed_categories=()
|
|
||||||
|
|
||||||
render_category() {
|
|
||||||
local cat="$1"
|
|
||||||
local module_list="${modules_by_category[$cat]:-}"
|
|
||||||
[ -n "$module_list" ] || return 0
|
|
||||||
|
|
||||||
local has_valid_modules=0
|
|
||||||
local -a module_array
|
|
||||||
IFS=' ' read -ra module_array <<< "$module_list"
|
|
||||||
for key in "${module_array[@]}"; do
|
|
||||||
[ -n "${KNOWN_MODULE_LOOKUP[$key]:-}" ] || continue
|
|
||||||
local status_lc="${MODULE_STATUS_MAP[$key],,}"
|
|
||||||
if [ -z "$status_lc" ] || [ "$status_lc" = "active" ]; then
|
|
||||||
has_valid_modules=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
[ "$has_valid_modules" = "1" ] || return 0
|
|
||||||
|
|
||||||
local cat_title="${category_titles[$cat]:-$cat}"
|
|
||||||
printf '\n%b\n' "${BOLD}${CYAN}═══ ${cat_title} ═══${NC}"
|
|
||||||
|
|
||||||
local first_in_cat=1
|
|
||||||
for key in "${module_array[@]}"; do
|
|
||||||
[ -n "${KNOWN_MODULE_LOOKUP[$key]:-}" ] || continue
|
|
||||||
local status_lc="${MODULE_STATUS_MAP[$key],,}"
|
|
||||||
if [ -n "$status_lc" ] && [ "$status_lc" != "active" ]; then
|
|
||||||
local reason="${MODULE_BLOCK_REASON_MAP[$key]:-Blocked in manifest}"
|
|
||||||
say WARNING "${key#MODULE_} is blocked: ${reason}"
|
|
||||||
printf -v "$key" '%s' "0"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$first_in_cat" -ne 1 ]; then
|
|
||||||
printf '\n'
|
|
||||||
fi
|
|
||||||
first_in_cat=0
|
|
||||||
local prompt_label
|
|
||||||
prompt_label="$(module_display_name "$key")"
|
|
||||||
if [ "${MODULE_NEEDS_BUILD_MAP[$key]}" = "1" ]; then
|
|
||||||
prompt_label="${prompt_label} (requires build)"
|
|
||||||
fi
|
|
||||||
local description="${MODULE_DESCRIPTION_MAP[$key]:-}"
|
|
||||||
if [ -n "$description" ]; then
|
|
||||||
printf '%b\n' "${BLUE}ℹ️ ${MODULE_NAME_MAP[$key]:-$key}: ${description}${NC}"
|
|
||||||
fi
|
|
||||||
local special_message="${MODULE_SPECIAL_MESSAGE_MAP[$key]:-}"
|
|
||||||
if [ -n "$special_message" ]; then
|
|
||||||
printf '%b\n' "${MAGENTA}💡 ${special_message}${NC}"
|
|
||||||
fi
|
|
||||||
local repo="${MODULE_REPO_MAP[$key]:-}"
|
|
||||||
if [ -n "$repo" ]; then
|
|
||||||
printf '%b\n' "${GREEN}🔗 ${repo}${NC}"
|
|
||||||
fi
|
|
||||||
local default_answer
|
|
||||||
default_answer="$(module_default "$key")"
|
|
||||||
local response
|
|
||||||
response=$(ask_yn "$prompt_label" "$default_answer")
|
|
||||||
if [ "$response" = "1" ]; then
|
|
||||||
printf -v "$key" '%s' "1"
|
|
||||||
else
|
|
||||||
printf -v "$key" '%s' "0"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
processed_categories["$cat"]=1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Group modules by category using arrays
|
|
||||||
declare -A modules_by_category
|
|
||||||
local key
|
|
||||||
for key in "${selection_keys[@]}"; do
|
|
||||||
[ -n "${KNOWN_MODULE_LOOKUP[$key]:-}" ] || continue
|
|
||||||
local category="${MODULE_CATEGORY_MAP[$key]:-uncategorized}"
|
|
||||||
if [ -z "${modules_by_category[$category]:-}" ]; then
|
|
||||||
modules_by_category[$category]="$key"
|
|
||||||
else
|
|
||||||
modules_by_category[$category]="${modules_by_category[$category]} $key"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Process modules by category (ordered, then any new categories)
|
|
||||||
local cat
|
|
||||||
for cat in "${category_order[@]}"; do
|
|
||||||
render_category "$cat"
|
|
||||||
done
|
|
||||||
for cat in "${!modules_by_category[@]}"; do
|
|
||||||
[ -n "${processed_categories[$cat]:-}" ] && continue
|
|
||||||
render_category "$cat"
|
|
||||||
done
|
|
||||||
module_mode_label="preset 3 (Manual)"
|
|
||||||
elif [ "$MODE_SELECTION" = "4" ]; then
|
|
||||||
for key in "${MODULE_KEYS[@]}"; do
|
|
||||||
printf -v "$key" '%s' "0"
|
|
||||||
done
|
|
||||||
module_mode_label="preset 4 (No modules)"
|
|
||||||
elif [ "$MODE_SELECTION" = "preset" ]; then
|
|
||||||
local preset_modules="${MODULE_PRESET_CONFIGS[$MODE_PRESET_NAME]}"
|
|
||||||
if [ -n "$preset_modules" ]; then
|
|
||||||
apply_module_preset "$preset_modules"
|
|
||||||
say INFO "Applied preset '${MODE_PRESET_NAME}'."
|
|
||||||
else
|
|
||||||
say WARNING "Preset '${MODE_PRESET_NAME}' did not contain any module selections."
|
|
||||||
fi
|
|
||||||
local preset_label="${MODULE_PRESET_LABELS[$MODE_PRESET_NAME]:-$MODE_PRESET_NAME}"
|
|
||||||
module_mode_label="preset (${preset_label})"
|
|
||||||
fi
|
|
||||||
|
|
||||||
auto_enable_module_dependencies
|
|
||||||
ensure_module_platforms
|
|
||||||
|
|
||||||
if [ -n "$CLI_PLAYERBOT_ENABLED" ]; then
|
|
||||||
if [[ "$CLI_PLAYERBOT_ENABLED" != "0" && "$CLI_PLAYERBOT_ENABLED" != "1" ]]; then
|
|
||||||
say ERROR "--playerbot-enabled must be 0 or 1"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
PLAYERBOT_ENABLED="$CLI_PLAYERBOT_ENABLED"
|
|
||||||
fi
|
|
||||||
if [ -n "$CLI_PLAYERBOT_MIN" ]; then
|
|
||||||
if ! [[ "$CLI_PLAYERBOT_MIN" =~ ^[0-9]+$ ]]; then
|
|
||||||
say ERROR "--playerbot-min-bots must be numeric"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
PLAYERBOT_MIN_BOTS="$CLI_PLAYERBOT_MIN"
|
|
||||||
fi
|
|
||||||
if [ -n "$CLI_PLAYERBOT_MAX" ]; then
|
|
||||||
if ! [[ "$CLI_PLAYERBOT_MAX" =~ ^[0-9]+$ ]]; then
|
|
||||||
say ERROR "--playerbot-max-bots must be numeric"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
PLAYERBOT_MAX_BOTS="$CLI_PLAYERBOT_MAX"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
|
|
||||||
if [ -z "$CLI_PLAYERBOT_ENABLED" ]; then
|
|
||||||
PLAYERBOT_ENABLED=1
|
|
||||||
fi
|
|
||||||
PLAYERBOT_MIN_BOTS=$(ask "Minimum concurrent playerbots" "${CLI_PLAYERBOT_MIN:-$DEFAULT_PLAYERBOT_MIN}" validate_number)
|
|
||||||
PLAYERBOT_MAX_BOTS=$(ask "Maximum concurrent playerbots" "${CLI_PLAYERBOT_MAX:-$DEFAULT_PLAYERBOT_MAX}" validate_number)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$PLAYERBOT_MIN_BOTS" ] && [ -n "$PLAYERBOT_MAX_BOTS" ]; then
|
|
||||||
if [ "$PLAYERBOT_MAX_BOTS" -lt "$PLAYERBOT_MIN_BOTS" ]; then
|
|
||||||
say WARNING "Playerbot max bots ($PLAYERBOT_MAX_BOTS) lower than min ($PLAYERBOT_MIN_BOTS); adjusting max to match min."
|
|
||||||
PLAYERBOT_MAX_BOTS="$PLAYERBOT_MIN_BOTS"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
for mod_var in "${MODULE_KEYS[@]}"; do
|
|
||||||
if [ "${MODULE_NEEDS_BUILD_MAP[$mod_var]}" = "1" ]; then
|
|
||||||
eval "value=\${$mod_var:-0}"
|
|
||||||
if [ "$value" = "1" ]; then
|
|
||||||
NEEDS_CXX_REBUILD=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
local enabled_module_keys=()
|
|
||||||
local enabled_cpp_module_keys=()
|
|
||||||
for mod_var in "${MODULE_KEYS[@]}"; do
|
|
||||||
eval "value=\${$mod_var:-0}"
|
|
||||||
if [ "$value" = "1" ]; then
|
|
||||||
enabled_module_keys+=("$mod_var")
|
|
||||||
if [ "${MODULE_NEEDS_BUILD_MAP[$mod_var]}" = "1" ]; then
|
|
||||||
enabled_cpp_module_keys+=("$mod_var")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
MODULES_ENABLED_LIST=""
|
|
||||||
MODULES_CPP_LIST=""
|
|
||||||
if [ ${#enabled_module_keys[@]} -gt 0 ]; then
|
|
||||||
MODULES_ENABLED_LIST="$(IFS=','; printf '%s' "${enabled_module_keys[*]}")"
|
|
||||||
fi
|
|
||||||
if [ ${#enabled_cpp_module_keys[@]} -gt 0 ]; then
|
|
||||||
MODULES_CPP_LIST="$(IFS=','; printf '%s' "${enabled_cpp_module_keys[*]}")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Determine source variant based ONLY on playerbots module
|
|
||||||
STACK_SOURCE_VARIANT="core"
|
|
||||||
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
|
|
||||||
STACK_SOURCE_VARIANT="playerbots"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Determine image mode based on source variant and build requirements
|
|
||||||
STACK_IMAGE_MODE="standard"
|
|
||||||
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
|
|
||||||
STACK_IMAGE_MODE="playerbots"
|
|
||||||
elif [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
|
||||||
STACK_IMAGE_MODE="modules"
|
|
||||||
fi
|
|
||||||
|
|
||||||
MODULES_REQUIRES_CUSTOM_BUILD="$NEEDS_CXX_REBUILD"
|
|
||||||
MODULES_REQUIRES_PLAYERBOT_SOURCE="0"
|
|
||||||
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
|
|
||||||
MODULES_REQUIRES_PLAYERBOT_SOURCE="1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export NEEDS_CXX_REBUILD
|
|
||||||
MODULE_MODE_LABEL="$module_mode_label"
|
|
||||||
}
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
# Module metadata and helpers for setup.sh
|
|
||||||
|
|
||||||
# setup.sh -> scripts/bash/lib/common.sh (shared helpers)
|
|
||||||
source "$SCRIPT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
|
|
||||||
normalize_module_name(){
|
|
||||||
local mod="$1"
|
|
||||||
mod="${mod^^}"
|
|
||||||
mod="${mod//-/_}"
|
|
||||||
mod="${mod//./_}"
|
|
||||||
mod="${mod// /_}"
|
|
||||||
if [[ "$mod" = MOD_* ]]; then
|
|
||||||
mod="${mod#MOD_}"
|
|
||||||
fi
|
|
||||||
if [[ "$mod" != MODULE_* ]]; then
|
|
||||||
mod="MODULE_${mod}"
|
|
||||||
fi
|
|
||||||
echo "$mod"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -A MODULE_ENABLE_SET=()
|
|
||||||
|
|
||||||
module_default(){
|
|
||||||
local key="$1"
|
|
||||||
if [ "${MODULE_ENABLE_SET[$key]:-0}" = "1" ]; then
|
|
||||||
echo y
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
local current
|
|
||||||
eval "current=\${$key:-${MODULE_DEFAULT_VALUES[$key]:-0}}"
|
|
||||||
if [ "$current" = "1" ]; then
|
|
||||||
echo y
|
|
||||||
else
|
|
||||||
echo n
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_module_preset(){
|
|
||||||
local preset_list="$1"
|
|
||||||
local IFS=','
|
|
||||||
for item in $preset_list; do
|
|
||||||
local mod="${item//[[:space:]]/}"
|
|
||||||
[ -z "$mod" ] && continue
|
|
||||||
if [ -n "${KNOWN_MODULE_LOOKUP[$mod]:-}" ]; then
|
|
||||||
printf -v "$mod" '%s' "1"
|
|
||||||
else
|
|
||||||
say WARNING "Preset references unknown module $mod"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==============================
|
|
||||||
# Module metadata / defaults
|
|
||||||
# ==============================
|
|
||||||
|
|
||||||
MODULE_MANIFEST_PATH="$SCRIPT_DIR/config/module-manifest.json"
|
|
||||||
MODULE_MANIFEST_HELPER="$SCRIPT_DIR/scripts/python/setup_manifest.py"
|
|
||||||
MODULE_PROFILES_HELPER="$SCRIPT_DIR/scripts/python/setup_profiles.py"
|
|
||||||
ENV_TEMPLATE_FILE="$SCRIPT_DIR/.env.template"
|
|
||||||
|
|
||||||
declare -a MODULE_KEYS=()
|
|
||||||
declare -a MODULE_KEYS_SORTED=()
|
|
||||||
declare -A MODULE_NAME_MAP=()
|
|
||||||
declare -A MODULE_TYPE_MAP=()
|
|
||||||
declare -A MODULE_STATUS_MAP=()
|
|
||||||
declare -A MODULE_BLOCK_REASON_MAP=()
|
|
||||||
declare -A MODULE_NEEDS_BUILD_MAP=()
|
|
||||||
declare -A MODULE_REQUIRES_MAP=()
|
|
||||||
declare -A MODULE_NOTES_MAP=()
|
|
||||||
declare -A MODULE_DESCRIPTION_MAP=()
|
|
||||||
declare -A MODULE_CATEGORY_MAP=()
|
|
||||||
declare -A MODULE_SPECIAL_MESSAGE_MAP=()
|
|
||||||
declare -A MODULE_REPO_MAP=()
|
|
||||||
declare -A MODULE_DEFAULT_VALUES=()
|
|
||||||
declare -A KNOWN_MODULE_LOOKUP=()
|
|
||||||
declare -A ENV_TEMPLATE_VALUES=()
|
|
||||||
MODULE_METADATA_INITIALIZED=0
|
|
||||||
|
|
||||||
load_env_template_values() {
|
|
||||||
local template_file="$ENV_TEMPLATE_FILE"
|
|
||||||
if [ ! -f "$template_file" ]; then
|
|
||||||
echo "ERROR: .env.template file not found at $template_file" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
while IFS= read -r raw_line || [ -n "$raw_line" ]; do
|
|
||||||
local line="${raw_line%%#*}"
|
|
||||||
line="${line%%$'\r'}"
|
|
||||||
line="$(echo "$line" | sed 's/[[:space:]]*$//')"
|
|
||||||
[ -n "$line" ] || continue
|
|
||||||
[[ "$line" == *=* ]] || continue
|
|
||||||
local key="${line%%=*}"
|
|
||||||
local value="${line#*=}"
|
|
||||||
key="$(echo "$key" | sed 's/[[:space:]]//g')"
|
|
||||||
value="$(echo "$value" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
|
||||||
[ -n "$key" ] || continue
|
|
||||||
ENV_TEMPLATE_VALUES["$key"]="$value"
|
|
||||||
done < "$template_file"
|
|
||||||
}
|
|
||||||
|
|
||||||
load_module_manifest_metadata() {
|
|
||||||
if [ ! -f "$MODULE_MANIFEST_PATH" ]; then
|
|
||||||
echo "ERROR: Module manifest not found at $MODULE_MANIFEST_PATH" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ ! -x "$MODULE_MANIFEST_HELPER" ]; then
|
|
||||||
echo "ERROR: Manifest helper not found or not executable at $MODULE_MANIFEST_HELPER" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
require_cmd python3
|
|
||||||
|
|
||||||
mapfile -t MODULE_KEYS < <(
|
|
||||||
python3 "$MODULE_MANIFEST_HELPER" keys "$MODULE_MANIFEST_PATH"
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ ${#MODULE_KEYS[@]} -eq 0 ]; then
|
|
||||||
echo "ERROR: No modules defined in manifest $MODULE_MANIFEST_PATH" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
while IFS=$'\t' read -r key name needs_build module_type status block_reason requires notes description category special_message repo; do
|
|
||||||
[ -n "$key" ] || continue
|
|
||||||
# Convert placeholder back to empty string
|
|
||||||
[ "$block_reason" = "-" ] && block_reason=""
|
|
||||||
[ "$requires" = "-" ] && requires=""
|
|
||||||
[ "$notes" = "-" ] && notes=""
|
|
||||||
[ "$description" = "-" ] && description=""
|
|
||||||
[ "$category" = "-" ] && category=""
|
|
||||||
[ "$special_message" = "-" ] && special_message=""
|
|
||||||
[ "$repo" = "-" ] && repo=""
|
|
||||||
MODULE_NAME_MAP["$key"]="$name"
|
|
||||||
MODULE_NEEDS_BUILD_MAP["$key"]="$needs_build"
|
|
||||||
MODULE_TYPE_MAP["$key"]="$module_type"
|
|
||||||
MODULE_STATUS_MAP["$key"]="$status"
|
|
||||||
MODULE_BLOCK_REASON_MAP["$key"]="$block_reason"
|
|
||||||
MODULE_REQUIRES_MAP["$key"]="$requires"
|
|
||||||
MODULE_NOTES_MAP["$key"]="$notes"
|
|
||||||
MODULE_DESCRIPTION_MAP["$key"]="$description"
|
|
||||||
MODULE_CATEGORY_MAP["$key"]="$category"
|
|
||||||
MODULE_SPECIAL_MESSAGE_MAP["$key"]="$special_message"
|
|
||||||
MODULE_REPO_MAP["$key"]="$repo"
|
|
||||||
KNOWN_MODULE_LOOKUP["$key"]=1
|
|
||||||
done < <(python3 "$MODULE_MANIFEST_HELPER" metadata "$MODULE_MANIFEST_PATH")
|
|
||||||
|
|
||||||
mapfile -t MODULE_KEYS_SORTED < <(
|
|
||||||
python3 "$MODULE_MANIFEST_HELPER" sorted-keys "$MODULE_MANIFEST_PATH"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize_module_defaults() {
|
|
||||||
if [ "$MODULE_METADATA_INITIALIZED" = "1" ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
load_env_template_values
|
|
||||||
load_module_manifest_metadata
|
|
||||||
|
|
||||||
for key in "${MODULE_KEYS[@]}"; do
|
|
||||||
if [ -z "${ENV_TEMPLATE_VALUES[$key]+_}" ]; then
|
|
||||||
echo "ERROR: .env.template missing default value for ${key}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
local default="${ENV_TEMPLATE_VALUES[$key]}"
|
|
||||||
MODULE_DEFAULT_VALUES["$key"]="$default"
|
|
||||||
printf -v "$key" '%s' "$default"
|
|
||||||
done
|
|
||||||
MODULE_METADATA_INITIALIZED=1
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_modules_to_defaults() {
|
|
||||||
for key in "${MODULE_KEYS[@]}"; do
|
|
||||||
printf -v "$key" '%s' "${MODULE_DEFAULT_VALUES[$key]}"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
module_display_name() {
|
|
||||||
local key="$1"
|
|
||||||
local name="${MODULE_NAME_MAP[$key]:-$key}"
|
|
||||||
local note="${MODULE_NOTES_MAP[$key]}"
|
|
||||||
if [ -n "$note" ]; then
|
|
||||||
echo "${name} - ${note}"
|
|
||||||
else
|
|
||||||
echo "$name"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
auto_enable_module_dependencies() {
|
|
||||||
local changed=1
|
|
||||||
while [ "$changed" -eq 1 ]; do
|
|
||||||
changed=0
|
|
||||||
for key in "${MODULE_KEYS[@]}"; do
|
|
||||||
local enabled
|
|
||||||
eval "enabled=\${$key:-0}"
|
|
||||||
[ "$enabled" = "1" ] || continue
|
|
||||||
local requires_csv="${MODULE_REQUIRES_MAP[$key]}"
|
|
||||||
IFS=',' read -r -a deps <<< "${requires_csv}"
|
|
||||||
for dep in "${deps[@]}"; do
|
|
||||||
dep="${dep//[[:space:]]/}"
|
|
||||||
[ -n "$dep" ] || continue
|
|
||||||
[ -n "${KNOWN_MODULE_LOOKUP[$dep]:-}" ] || continue
|
|
||||||
local dep_value
|
|
||||||
eval "dep_value=\${$dep:-0}"
|
|
||||||
if [ "$dep_value" != "1" ]; then
|
|
||||||
say INFO "Automatically enabling ${dep#MODULE_} (required by ${key#MODULE_})."
|
|
||||||
printf -v "$dep" '%s' "1"
|
|
||||||
MODULE_ENABLE_SET["$dep"]=1
|
|
||||||
changed=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_module_platforms() {
|
|
||||||
local needs_platform=0
|
|
||||||
local key
|
|
||||||
for key in "${MODULE_KEYS[@]}"; do
|
|
||||||
case "$key" in
|
|
||||||
MODULE_ELUNA|MODULE_AIO) continue ;;
|
|
||||||
esac
|
|
||||||
local value
|
|
||||||
eval "value=\${$key:-0}"
|
|
||||||
if [ "$value" = "1" ]; then
|
|
||||||
needs_platform=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "$needs_platform" != "1" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local platform
|
|
||||||
for platform in MODULE_ELUNA MODULE_AIO; do
|
|
||||||
[ -n "${KNOWN_MODULE_LOOKUP[$platform]:-}" ] || continue
|
|
||||||
local platform_value
|
|
||||||
eval "platform_value=\${$platform:-0}"
|
|
||||||
if [ "$platform_value" != "1" ]; then
|
|
||||||
local platform_name="${MODULE_NAME_MAP[$platform]:-${platform#MODULE_}}"
|
|
||||||
say INFO "Automatically enabling ${platform_name} to support selected modules."
|
|
||||||
printf -v "$platform" '%s' "1"
|
|
||||||
MODULE_ENABLE_SET["$platform"]=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
# Summary, path setup, and output helpers for setup.sh
|
|
||||||
|
|
||||||
print_summary() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say)
|
|
||||||
local SUMMARY_MODE_TEXT="$MODULE_MODE_LABEL"
|
|
||||||
if [ -z "$SUMMARY_MODE_TEXT" ]; then
|
|
||||||
SUMMARY_MODE_TEXT="${CLI_MODULE_MODE:-}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
say HEADER "SUMMARY"
|
|
||||||
printf " %-18s %s\n" "Server Address:" "$SERVER_ADDRESS"
|
|
||||||
printf " %-18s Realm:%s Auth:%s SOAP:%s MySQL:%s\n" "Ports:" "$REALM_PORT" "$AUTH_EXTERNAL_PORT" "$SOAP_EXTERNAL_PORT" "$MYSQL_EXTERNAL_PORT"
|
|
||||||
printf " %-18s %s\n" "Storage Path:" "$STORAGE_PATH"
|
|
||||||
printf " %-18s %s\n" "Container User:" "$CONTAINER_USER"
|
|
||||||
printf " %-18s Daily %s:00 UTC, keep %sd/%sh\n" "Backups:" "$BACKUP_DAILY_TIME" "$BACKUP_RETENTION_DAYS" "$BACKUP_RETENTION_HOURS"
|
|
||||||
printf " %-18s %s\n" "Modules images:" "$DEFAULT_AUTH_IMAGE_MODULES | $DEFAULT_WORLD_IMAGE_MODULES"
|
|
||||||
|
|
||||||
printf " %-18s %s\n" "Modules preset:" "$SUMMARY_MODE_TEXT"
|
|
||||||
printf " %-18s %s\n" "Playerbot Min Bots:" "$PLAYERBOT_MIN_BOTS"
|
|
||||||
printf " %-18s %s\n" "Playerbot Max Bots:" "$PLAYERBOT_MAX_BOTS"
|
|
||||||
printf " %-18s" "Enabled Modules:"
|
|
||||||
local enabled_modules=()
|
|
||||||
for module_var in "${MODULE_KEYS[@]}"; do
|
|
||||||
eval "value=\${$module_var:-0}"
|
|
||||||
if [ "$value" = "1" ]; then
|
|
||||||
enabled_modules+=("${module_var#MODULE_}")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ${#enabled_modules[@]} -eq 0 ]; then
|
|
||||||
printf " none\n"
|
|
||||||
else
|
|
||||||
printf "\n"
|
|
||||||
for module in "${enabled_modules[@]}"; do
|
|
||||||
printf " • %s\n" "$module"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
|
||||||
printf " %-18s detected (source rebuild required)\n" "C++ modules:"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_local_storage_paths() {
|
|
||||||
LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}"
|
|
||||||
LOCAL_STORAGE_ROOT="${LOCAL_STORAGE_ROOT%/}"
|
|
||||||
[ -z "$LOCAL_STORAGE_ROOT" ] && LOCAL_STORAGE_ROOT="."
|
|
||||||
LOCAL_STORAGE_ROOT_ABS="$LOCAL_STORAGE_ROOT"
|
|
||||||
if [[ "$LOCAL_STORAGE_ROOT_ABS" != /* ]]; then
|
|
||||||
LOCAL_STORAGE_ROOT_ABS="$SCRIPT_DIR/${LOCAL_STORAGE_ROOT_ABS#./}"
|
|
||||||
fi
|
|
||||||
LOCAL_STORAGE_ROOT_ABS="${LOCAL_STORAGE_ROOT_ABS%/}"
|
|
||||||
STORAGE_PATH_LOCAL="$LOCAL_STORAGE_ROOT"
|
|
||||||
|
|
||||||
export STORAGE_PATH STORAGE_PATH_LOCAL
|
|
||||||
local module_export_var
|
|
||||||
for module_export_var in "${MODULE_KEYS[@]}"; do
|
|
||||||
export "$module_export_var"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_rebuild_sentinel() {
|
|
||||||
# setup.sh -> scripts/bash/setup/ui.sh (say)
|
|
||||||
if [ "$NEEDS_CXX_REBUILD" != "1" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
say WARNING "These modules require compiling AzerothCore from source."
|
|
||||||
say INFO "Run './build.sh' to compile your custom modules before deployment."
|
|
||||||
|
|
||||||
local sentinel="$LOCAL_STORAGE_ROOT_ABS/modules/.requires_rebuild"
|
|
||||||
mkdir -p "$(dirname "$sentinel")"
|
|
||||||
if touch "$sentinel" 2>/dev/null; then
|
|
||||||
say INFO "Build sentinel created at $sentinel"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
say WARNING "Could not create build sentinel at $sentinel (permissions/ownership); forcing with sudo..."
|
|
||||||
if command -v sudo >/dev/null 2>&1; then
|
|
||||||
if sudo mkdir -p "$(dirname "$sentinel")" \
|
|
||||||
&& sudo chown -R "$(id -u):$(id -g)" "$(dirname "$sentinel")" \
|
|
||||||
&& sudo touch "$sentinel"; then
|
|
||||||
say INFO "Build sentinel created at $sentinel (after fixing ownership)"
|
|
||||||
else
|
|
||||||
say ERROR "Failed to force build sentinel creation at $sentinel. Fix permissions and rerun setup."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
say ERROR "Cannot force build sentinel creation (sudo unavailable). Fix permissions on $(dirname "$sentinel") and rerun setup."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
set_rebuild_source_path() {
|
|
||||||
local default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore"
|
|
||||||
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
|
|
||||||
default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore-playerbots"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Persist rebuild source path for downstream build scripts
|
|
||||||
MODULES_REBUILD_SOURCE_PATH="$default_source_rel"
|
|
||||||
}
|
|
||||||
|
|
||||||
print_final_next_steps() {
|
|
||||||
say INFO "Ready to bring your realm online:"
|
|
||||||
if [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
|
||||||
printf ' 🔨 First, build custom modules: ./build.sh\n'
|
|
||||||
printf ' 🚀 Then deploy your realm: ./deploy.sh\n'
|
|
||||||
else
|
|
||||||
printf ' 🚀 Quick deploy: ./deploy.sh\n'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
# Setup UI and prompting helpers for setup.sh
|
|
||||||
|
|
||||||
# setup.sh -> scripts/bash/lib/common.sh (shared colors/logging)
|
|
||||||
if [ -n "${SCRIPT_DIR:-}" ] && [ -f "$SCRIPT_DIR/scripts/bash/lib/common.sh" ]; then
|
|
||||||
source "$SCRIPT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extra UI colors not in common.sh
|
|
||||||
MAGENTA='\033[0;35m'
|
|
||||||
BOLD='\033[1m'
|
|
||||||
|
|
||||||
: "${RED:=\033[0;31m}"
|
|
||||||
: "${GREEN:=\033[0;32m}"
|
|
||||||
: "${YELLOW:=\033[1;33m}"
|
|
||||||
: "${BLUE:=\033[0;34m}"
|
|
||||||
: "${CYAN:=\033[0;36m}"
|
|
||||||
: "${NC:=\033[0m}"
|
|
||||||
|
|
||||||
say(){
|
|
||||||
local t=$1
|
|
||||||
shift
|
|
||||||
case "$t" in
|
|
||||||
INFO) echo -e "${BLUE}ℹ️ $*${NC}";;
|
|
||||||
SUCCESS) echo -e "${GREEN}✅ $*${NC}";;
|
|
||||||
WARNING) echo -e "${YELLOW}⚠️ $*${NC}";;
|
|
||||||
ERROR) echo -e "${RED}❌ $*${NC}";;
|
|
||||||
HEADER) echo -e "\n${MAGENTA}=== $* ===${NC}";;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_ip(){ [[ $1 =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; }
|
|
||||||
validate_port(){ [[ $1 =~ ^[0-9]+$ ]] && [ $1 -ge 1 ] && [ $1 -le 65535 ]; }
|
|
||||||
validate_number(){ [[ $1 =~ ^[0-9]+$ ]]; }
|
|
||||||
|
|
||||||
ask(){
|
|
||||||
local prompt="$1"; local def="$2"; local validator="$3"; local v
|
|
||||||
while true; do
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
v="$def"
|
|
||||||
else
|
|
||||||
if [ -n "$def" ]; then
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 ${prompt} [${def}]: ${NC}")" v; v=${v:-$def}
|
|
||||||
else
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 ${prompt}: ${NC}")" v
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if [ -z "$v" ] && [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
say ERROR "Non-interactive mode requires a value for '${prompt}'."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -z "$validator" ] || $validator "$v"; then
|
|
||||||
echo "$v"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
say ERROR "Invalid value '${v}' provided for '${prompt}' in non-interactive mode."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
say ERROR "Invalid input. Please try again."
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
ask_yn(){
|
|
||||||
local p="$1"; local d="$2"; local v
|
|
||||||
if [ "$NON_INTERACTIVE" = "1" ]; then
|
|
||||||
if [ "$d" = "y" ]; then
|
|
||||||
echo 1
|
|
||||||
else
|
|
||||||
echo 0
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
while true; do
|
|
||||||
if [ "$d" = "y" ]; then
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 ${p} [Y/n]: ${NC}")" v; v=${v:-y}
|
|
||||||
else
|
|
||||||
read -p "$(echo -e "${YELLOW}🔧 ${p} [y/N]: ${NC}")" v; v=${v:-n}
|
|
||||||
fi
|
|
||||||
case "$v" in
|
|
||||||
[Yy]*) echo 1; return 0;;
|
|
||||||
[Nn]*) echo 0; return 0;;
|
|
||||||
esac
|
|
||||||
say ERROR "Please answer y or n"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
show_wow_header() {
|
|
||||||
if [ -t 1 ] && command -v clear >/dev/null 2>&1; then
|
|
||||||
clear >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
echo -e "${RED}"
|
|
||||||
cat <<'ASCII'
|
|
||||||
|
|
||||||
##
|
|
||||||
### :*
|
|
||||||
##### .**#
|
|
||||||
###### ***##
|
|
||||||
****###* *****##.
|
|
||||||
******##- ******###.
|
|
||||||
.*********###= ********###
|
|
||||||
************##### #****###:+* ********####
|
|
||||||
***********+****##########**********##**# ********#####
|
|
||||||
********=+***********######**********######*#**+*******###+
|
|
||||||
-+*****=**************#######*******####**#####**##*****####-
|
|
||||||
++**++****************#########**####***####***#####****####:
|
|
||||||
:++*******************#*******####*****#****######***##*****#######
|
|
||||||
*= -++++++******************************###**********###******######
|
|
||||||
.+***. :++++++++***************************#+*#*-*******************#**+
|
|
||||||
++*****= =+++=+++***************************+**###**************++*#####*
|
|
||||||
-++*****+++- -=++++++++*********+++++**###**+++=+*###**+*********##+++*+++##
|
|
||||||
+++*********+++=-=+++++++++****+++***+++++*####***+++**=**#*==***#####*++***+*+
|
|
||||||
+++++***********++=-=++++++++*++****=++*++*#######**+=-=+****+*#########***==+*#*
|
|
||||||
=+++++++*****++++===-++++++++=+++++=++*+=-+#**#**=####****#**+-+**************##*
|
|
||||||
++++++++++++++======++++++++=====+++++=-+++*+##########*****==*######*****####
|
|
||||||
+++++++=++++++====++++++++++========---++++*****#######**==***#*******####*
|
|
||||||
++===++++++++=====+++++++=+++:::--:::.++++++*****####**+=**************#
|
|
||||||
=+++++=: =+=====-+++++++++++++++++++++==+++--==----:-++++++****####****+=+*+*******:
|
|
||||||
++++++++++++++++==+++++++++++++++++++++=+=-===-----:+++++++++**+++****####***+++
|
|
||||||
=++++++++++++++++++++++++++++++++++++=++++======----==+++++++=+************:
|
|
||||||
:++++++++++++++=+++++++++++++++++++======-------:-====+****************.
|
|
||||||
=----=+++-==++++++*******++++++++++++++===============****************=
|
|
||||||
-=---==-=====--+++++++++++++++++++++++++++===+++++++********++#***#++******
|
|
||||||
+++++========+=====----++++++++++++++++===+++++===--=**********+=++*++********
|
|
||||||
+++==========-=============-----:-=++=====+++++++++++++++=-=***********+*********
|
|
||||||
==----=+===+=================+++++++++++++++++++++++++=-********************
|
|
||||||
.======++++++===============---:::::==++++++++++++++++++++++=**********++*******:
|
|
||||||
+++==--::-=+++++++++++++========+===--=+- :::=-=++++++++++++++++++++++ +*****++**+***
|
|
||||||
.-----::::-=++++++++++++++++++==::-----++. :=+++++++++++++++++++*..-+*********=
|
|
||||||
:=+++++++++++++++++==.:--===-+++++++++++**++++++:::-********
|
|
||||||
++++++++++++++++++=+++++++++++++**+++++*****==******
|
|
||||||
.++++++++++++=-:.-+++++++++***++++************+
|
|
||||||
+++=========:.=+=-::++*****+*************
|
|
||||||
-++++++++==+: ..::=-. ..::::=********
|
|
||||||
.+========+==+++==========---::-+*-
|
|
||||||
++++++++++++=======-======
|
|
||||||
++++++++++++++======++
|
|
||||||
-=======++++++:
|
|
||||||
...
|
|
||||||
:::. :::::::::.,:::::: :::::::.. ... :::::::::::: :: .: .,-::::: ... :::::::.. .,::::::
|
|
||||||
;;`;; '`````;;;;;;;'''' ;;;;``;;;; .;;;;;;;.;;;;;;;;'''',;; ;;, ,;;;'````' .;;;;;;;. ;;;;``;;;; ;;;;''''
|
|
||||||
,[[ '[[, .n[[' [[cccc [[[,/[[[' ,[[ \[[, [[ ,[[[,,,[[[ [[[ ,[[ \[[,[[[,/[[[' [[cccc
|
|
||||||
c$$$cc$$$c ,$$P" $$"""" $$$$$$c $$$, $$$ $$ "$$$"""$$$ $$$ $$$, $$$$$$$$$c $$""""
|
|
||||||
888 888,,888bo,_ 888oo,__ 888b "88bo,"888,_ _,88P 88, 888 "88o`88bo,__,o,"888,_ _,88P888b "88bo,888oo,__
|
|
||||||
YMM ""` `""*UMM """"YUMMMMMMM "W" "YMMMMMP" MMM MMM YMM "YUMMMMMP" "YMMMMMP" MMMM "W" """"\MMM
|
|
||||||
ASCII
|
|
||||||
echo -e "${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
show_realm_configured(){
|
|
||||||
echo -e "\n${GREEN}⚔️ Your realm configuration has been forged! ⚔️${NC}"
|
|
||||||
echo -e "${GREEN}🏰 Ready to deploy your World of Warcraft server${NC}"
|
|
||||||
echo -e "${GREEN}🗡️ May your realm bring epic adventures!${NC}\n"
|
|
||||||
}
|
|
||||||
80
scripts/bash/update-realmlist.sh
Normal file
80
scripts/bash/update-realmlist.sh
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Updates the realmlist table in the database with current SERVER_ADDRESS and REALM_PORT from .env
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
# Source colors and functions
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
info() { printf '%b\n' "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
ok() { printf '%b\n' "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn() { printf '%b\n' "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
err() { printf '%b\n' "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
|
# Load environment variables from .env
|
||||||
|
if [ -f "$ROOT_DIR/.env" ]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
set -a
|
||||||
|
source "$ROOT_DIR/.env"
|
||||||
|
set +a
|
||||||
|
else
|
||||||
|
err "No .env file found at $ROOT_DIR/.env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check required variables
|
||||||
|
if [ -z "$SERVER_ADDRESS" ]; then
|
||||||
|
err "SERVER_ADDRESS not set in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$REALM_PORT" ]; then
|
||||||
|
err "REALM_PORT not set in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$MYSQL_HOST" ]; then
|
||||||
|
err "MYSQL_HOST not set in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$MYSQL_USER" ]; then
|
||||||
|
err "MYSQL_USER not set in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$MYSQL_ROOT_PASSWORD" ]; then
|
||||||
|
err "MYSQL_ROOT_PASSWORD not set in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$DB_AUTH_NAME" ]; then
|
||||||
|
err "DB_AUTH_NAME not set in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "Updating realmlist table..."
|
||||||
|
info " Address: $SERVER_ADDRESS"
|
||||||
|
info " Port: $REALM_PORT"
|
||||||
|
|
||||||
|
# Try to update the database
|
||||||
|
if mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify "${DB_AUTH_NAME}" \
|
||||||
|
-e "UPDATE realmlist SET address='${SERVER_ADDRESS}', port=${REALM_PORT} WHERE id=1;" 2>/dev/null; then
|
||||||
|
ok "Realmlist updated successfully"
|
||||||
|
|
||||||
|
# Show the current realmlist entry
|
||||||
|
mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify "${DB_AUTH_NAME}" \
|
||||||
|
-e "SELECT id, name, address, port FROM realmlist WHERE id=1;" 2>/dev/null || true
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
warn "Could not update realmlist table"
|
||||||
|
warn "This is normal if the database is not yet initialized or MySQL is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -4,13 +4,18 @@ set -e
|
|||||||
|
|
||||||
# Simple profile-aware deploy + health check for profiles-verify/docker-compose.yml
|
# Simple profile-aware deploy + health check for profiles-verify/docker-compose.yml
|
||||||
|
|
||||||
|
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
|
||||||
|
info(){ echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||||
|
ok(){ echo -e "${GREEN}✅ $*${NC}"; }
|
||||||
|
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||||
|
err(){ echo -e "${RED}❌ $*${NC}"; }
|
||||||
|
|
||||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
|
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
|
||||||
ENV_FILE=""
|
ENV_FILE=""
|
||||||
TEMPLATE_FILE="$PROJECT_DIR/.env.template"
|
TEMPLATE_FILE="$PROJECT_DIR/.env.template"
|
||||||
source "$PROJECT_DIR/scripts/bash/project_name.sh"
|
source "$PROJECT_DIR/scripts/bash/project_name.sh"
|
||||||
source "$PROJECT_DIR/scripts/bash/compose_overrides.sh"
|
source "$PROJECT_DIR/scripts/bash/compose_overrides.sh"
|
||||||
source "$PROJECT_DIR/scripts/bash/lib/common.sh"
|
|
||||||
PROFILES=(db services-standard client-data modules tools)
|
PROFILES=(db services-standard client-data modules tools)
|
||||||
SKIP_DEPLOY=false
|
SKIP_DEPLOY=false
|
||||||
QUICK=false
|
QUICK=false
|
||||||
|
|||||||
Reference in New Issue
Block a user