Issues found during P5-01 acceptance testing on WSL2: configure.sh: sync MySQL/Redis host/port into config/xuqm.env (was only writing to .env, leaving xuqm.env with hardcoded 127.0.0.1). install.sh: add docker login step before compose up; reads REGISTRY_USER/REGISTRY_PASSWORD from .env; --skip-registry-login flag for offline bundles or pre-authenticated environments. healthcheck.sh: move docs-site from required to optional container list (image may not exist in all ACR namespaces); add localhost fallback URL for actuator/health when CONSOLE_DOMAIN is not set; add PRIVATE mode verification via /api/private/deployment/status. scripts/migrate-tenant.sh (new): migrates a single tenant from the public platform MySQL to the private deployment. Exports t_tenant, t_app, t_feature_service with explicit column names to survive schema-order differences; supports --dry-run, --reset-password, managed/external destination MySQL, and restarts tenant-service after applying. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
172 行
8.4 KiB
Bash
可执行文件
172 行
8.4 KiB
Bash
可执行文件
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
. "$ROOT_DIR/scripts/lib.sh"
|
|
|
|
# Non-interactive mode: skip prompts if all required vars are already set
|
|
NON_INTERACTIVE="${NON_INTERACTIVE:-false}"
|
|
[ -t 0 ] || NON_INTERACTIVE=true
|
|
|
|
audit "configure" "STARTED" "rendering initial config"
|
|
progress "configure" "STARTED" "rendering initial config"
|
|
|
|
# Initialize from template if missing
|
|
if [ ! -f "$ROOT_DIR/.env" ]; then
|
|
cp "$ROOT_DIR/.env.example" "$ROOT_DIR/.env"
|
|
fi
|
|
ensure_secret_file
|
|
load_env
|
|
|
|
ask() {
|
|
local prompt="$1"
|
|
local current="${2:-}"
|
|
local default="${3:-}"
|
|
[ "$NON_INTERACTIVE" = "true" ] && { printf '%s' "${current:-$default}"; return; }
|
|
local display_default=""
|
|
[ -n "$current" ] && display_default=" [current: $current]"
|
|
[ -z "$current" ] && [ -n "$default" ] && display_default=" [default: $default]"
|
|
printf '%s%s: ' "$prompt" "$display_default" >&2
|
|
read -r value
|
|
printf '%s' "${value:-${current:-$default}}"
|
|
}
|
|
|
|
ask_secret() {
|
|
local prompt="$1"
|
|
[ "$NON_INTERACTIVE" = "true" ] && { printf 'change-me'; return; }
|
|
printf '%s (leave blank to generate): ' "$prompt" >&2
|
|
read -rs value
|
|
printf '\n' >&2
|
|
if [ -z "$value" ]; then
|
|
value="$(random_secret)"
|
|
printf ' → generated strong password\n' >&2
|
|
fi
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
printf '\n=== XuqmGroup Private Deployment Configuration ===\n\n'
|
|
|
|
# Domains
|
|
CONSOLE_DOMAIN="$(ask "Console domain (e.g. https://console.customer.com)" "${CONSOLE_DOMAIN:-}" "")"
|
|
OPS_DOMAIN="$(ask "Ops domain (e.g. https://ops.customer.com)" "${OPS_DOMAIN:-}" "")"
|
|
DOCS_DOMAIN="$(ask "Docs domain (e.g. https://docs.customer.com)" "${DOCS_DOMAIN:-}" "")"
|
|
FILE_DOMAIN="$(ask "File domain (e.g. https://file.customer.com)" "${FILE_DOMAIN:-}" "")"
|
|
|
|
# Optional service domains (only ask if enabling)
|
|
ENABLE_IM="${ENABLE_IM:-false}"
|
|
ENABLE_PUSH="${ENABLE_PUSH:-false}"
|
|
ENABLE_UPDATE="${ENABLE_UPDATE:-false}"
|
|
ENABLE_LICENSE="${ENABLE_LICENSE:-false}"
|
|
|
|
if [ "$NON_INTERACTIVE" != "true" ]; then
|
|
printf '\nWhich optional services to enable now? (space-separated, e.g. "im update")\n'
|
|
printf 'Available: im push update license\nCurrent: %s\n' "$COMPOSE_PROFILES"
|
|
printf 'Enter services (blank to keep current): '
|
|
read -r OPT_SVCS
|
|
fi
|
|
|
|
if printf '%s' "${OPT_SVCS:-}" | grep -q 'im'; then ENABLE_IM=true; IM_DOMAIN="$(ask "IM domain (e.g. https://im.customer.com)" "${IM_DOMAIN:-}" "")"; fi
|
|
if printf '%s' "${OPT_SVCS:-}" | grep -q 'push'; then ENABLE_PUSH=true; PUSH_DOMAIN="$(ask "Push domain" "${PUSH_DOMAIN:-}" "")"; fi
|
|
if printf '%s' "${OPT_SVCS:-}" | grep -q 'update'; then ENABLE_UPDATE=true; UPDATE_DOMAIN="$(ask "Update domain" "${UPDATE_DOMAIN:-}" "")"; fi
|
|
if printf '%s' "${OPT_SVCS:-}" | grep -q 'license'; then ENABLE_LICENSE=true; LICENSE_DOMAIN="$(ask "License domain" "${LICENSE_DOMAIN:-}" "")"; fi
|
|
|
|
# MySQL mode
|
|
printf '\nMySQL mode (external=you provide connection / managed=deploy script installs MySQL)\n'
|
|
MYSQL_MODE="$(ask "MySQL mode" "${MYSQL_MODE:-external}" "external")"
|
|
if [ "$MYSQL_MODE" = "external" ]; then
|
|
MYSQL_HOST="$(ask "MySQL host" "${MYSQL_HOST:-127.0.0.1}" "127.0.0.1")"
|
|
MYSQL_PORT="$(ask "MySQL port" "${MYSQL_PORT:-3306}" "3306")"
|
|
MYSQL_DATABASE="$(ask "MySQL database" "${MYSQL_DATABASE:-xuqm_private}" "xuqm_private")"
|
|
MYSQL_USERNAME="$(ask "MySQL username" "${MYSQL_USERNAME:-xuqm}" "xuqm")"
|
|
MYSQL_PASSWORD="$(ask_secret "MySQL password")"
|
|
else
|
|
MYSQL_HOST="mysql"
|
|
MYSQL_PORT="3306"
|
|
MYSQL_DATABASE="$(ask "MySQL database" "${MYSQL_DATABASE:-xuqm_private}" "xuqm_private")"
|
|
MYSQL_USERNAME="$(ask "MySQL username" "${MYSQL_USERNAME:-xuqm}" "xuqm")"
|
|
MYSQL_PASSWORD="$(ensure_env_value "$ROOT_DIR/config/secrets.env" "MYSQL_PASSWORD" "${MYSQL_PASSWORD:-}" "$(random_secret)")"
|
|
MYSQL_ROOT_PASSWORD="$(ensure_env_value "$ROOT_DIR/config/secrets.env" "MYSQL_ROOT_PASSWORD" "${MYSQL_ROOT_PASSWORD:-}" "$(random_secret)")"
|
|
fi
|
|
|
|
# Redis mode
|
|
printf '\nRedis mode (external=you provide connection / managed=deploy script installs Redis)\n'
|
|
REDIS_MODE="$(ask "Redis mode" "${REDIS_MODE:-external}" "external")"
|
|
if [ "$REDIS_MODE" = "external" ]; then
|
|
REDIS_HOST="$(ask "Redis host" "${REDIS_HOST:-127.0.0.1}" "127.0.0.1")"
|
|
REDIS_PORT="$(ask "Redis port" "${REDIS_PORT:-6379}" "6379")"
|
|
REDIS_PASSWORD="$(ask_secret "Redis password")"
|
|
else
|
|
REDIS_HOST="redis"
|
|
REDIS_PORT="6379"
|
|
REDIS_PASSWORD="$(ensure_env_value "$ROOT_DIR/config/secrets.env" "REDIS_PASSWORD" "${REDIS_PASSWORD:-}" "$(random_secret)")"
|
|
fi
|
|
|
|
# Bootstrap tenant
|
|
printf '\nBootstrap admin account:\n'
|
|
TENANT_BOOTSTRAP_EMAIL="$(ask "Admin email" "${TENANT_BOOTSTRAP_EMAIL:-admin@customer.com}" "admin@customer.com")"
|
|
TENANT_BOOTSTRAP_APP_KEY="$(ask "App key" "${TENANT_BOOTSTRAP_APP_KEY:-ak_private_default}" "ak_private_default")"
|
|
|
|
# Registry
|
|
REGISTRY="$(ask "Docker registry" "${REGISTRY:-registry.example.com/xuqm}" "registry.example.com/xuqm")"
|
|
IMAGE_TAG="$(ask "Image tag" "${IMAGE_TAG:-$(cat "$ROOT_DIR/VERSION" | tr -d '[:space:]')}" "")"
|
|
|
|
# Write .env (compose variable substitution — used by ${VAR} in docker-compose.yml)
|
|
set_env_value "$ROOT_DIR/.env" "CONSOLE_DOMAIN" "$CONSOLE_DOMAIN"
|
|
set_env_value "$ROOT_DIR/.env" "OPS_DOMAIN" "$OPS_DOMAIN"
|
|
set_env_value "$ROOT_DIR/.env" "DOCS_DOMAIN" "$DOCS_DOMAIN"
|
|
set_env_value "$ROOT_DIR/.env" "FILE_DOMAIN" "$FILE_DOMAIN"
|
|
[ -n "${IM_DOMAIN:-}" ] && set_env_value "$ROOT_DIR/.env" "IM_DOMAIN" "$IM_DOMAIN"
|
|
[ -n "${PUSH_DOMAIN:-}" ] && set_env_value "$ROOT_DIR/.env" "PUSH_DOMAIN" "$PUSH_DOMAIN"
|
|
[ -n "${UPDATE_DOMAIN:-}" ] && set_env_value "$ROOT_DIR/.env" "UPDATE_DOMAIN" "$UPDATE_DOMAIN"
|
|
[ -n "${LICENSE_DOMAIN:-}" ] && set_env_value "$ROOT_DIR/.env" "LICENSE_DOMAIN" "$LICENSE_DOMAIN"
|
|
|
|
set_env_value "$ROOT_DIR/.env" "ENABLE_IM" "$ENABLE_IM"
|
|
set_env_value "$ROOT_DIR/.env" "ENABLE_PUSH" "$ENABLE_PUSH"
|
|
set_env_value "$ROOT_DIR/.env" "ENABLE_UPDATE" "$ENABLE_UPDATE"
|
|
set_env_value "$ROOT_DIR/.env" "ENABLE_LICENSE" "$ENABLE_LICENSE"
|
|
|
|
set_env_value "$ROOT_DIR/.env" "MYSQL_MODE" "$MYSQL_MODE"
|
|
set_env_value "$ROOT_DIR/.env" "MYSQL_HOST" "$MYSQL_HOST"
|
|
set_env_value "$ROOT_DIR/.env" "MYSQL_PORT" "$MYSQL_PORT"
|
|
set_env_value "$ROOT_DIR/.env" "MYSQL_DATABASE" "$MYSQL_DATABASE"
|
|
set_env_value "$ROOT_DIR/.env" "MYSQL_USERNAME" "$MYSQL_USERNAME"
|
|
set_env_value "$ROOT_DIR/.env" "REDIS_MODE" "$REDIS_MODE"
|
|
set_env_value "$ROOT_DIR/.env" "REDIS_HOST" "$REDIS_HOST"
|
|
set_env_value "$ROOT_DIR/.env" "REDIS_PORT" "$REDIS_PORT"
|
|
set_env_value "$ROOT_DIR/.env" "REGISTRY" "$REGISTRY"
|
|
set_env_value "$ROOT_DIR/.env" "IMAGE_TAG" "$IMAGE_TAG"
|
|
set_env_value "$ROOT_DIR/.env" "TENANT_BOOTSTRAP_EMAIL" "$TENANT_BOOTSTRAP_EMAIL"
|
|
set_env_value "$ROOT_DIR/.env" "TENANT_BOOTSTRAP_APP_KEY" "$TENANT_BOOTSTRAP_APP_KEY"
|
|
|
|
# Sync infra settings into xuqm.env so containers receive correct host/port values
|
|
# via env_file:, consistent with the SPRING_DATASOURCE_* overrides in docker-compose.yml.
|
|
XUQM_ENV="$ROOT_DIR/config/xuqm.env"
|
|
set_env_value "$XUQM_ENV" "MYSQL_HOST" "$MYSQL_HOST"
|
|
set_env_value "$XUQM_ENV" "MYSQL_PORT" "$MYSQL_PORT"
|
|
set_env_value "$XUQM_ENV" "MYSQL_DATABASE" "$MYSQL_DATABASE"
|
|
set_env_value "$XUQM_ENV" "MYSQL_USERNAME" "$MYSQL_USERNAME"
|
|
set_env_value "$XUQM_ENV" "REDIS_HOST" "$REDIS_HOST"
|
|
set_env_value "$XUQM_ENV" "REDIS_PORT" "$REDIS_PORT"
|
|
set_env_value "$XUQM_ENV" "CONSOLE_DOMAIN" "$CONSOLE_DOMAIN"
|
|
[ -n "${FILE_DOMAIN:-}" ] && set_env_value "$XUQM_ENV" "FILE_DOMAIN" "$FILE_DOMAIN"
|
|
[ -n "${IM_DOMAIN:-}" ] && set_env_value "$XUQM_ENV" "IM_DOMAIN" "$IM_DOMAIN"
|
|
[ -n "${PUSH_DOMAIN:-}" ] && set_env_value "$XUQM_ENV" "PUSH_DOMAIN" "$PUSH_DOMAIN"
|
|
[ -n "${UPDATE_DOMAIN:-}" ] && set_env_value "$XUQM_ENV" "UPDATE_DOMAIN" "$UPDATE_DOMAIN"
|
|
[ -n "${LICENSE_DOMAIN:-}" ] && set_env_value "$XUQM_ENV" "LICENSE_DOMAIN" "$LICENSE_DOMAIN"
|
|
set_env_value "$XUQM_ENV" "ENABLE_IM" "$ENABLE_IM"
|
|
set_env_value "$XUQM_ENV" "ENABLE_PUSH" "$ENABLE_PUSH"
|
|
set_env_value "$XUQM_ENV" "ENABLE_UPDATE" "$ENABLE_UPDATE"
|
|
set_env_value "$XUQM_ENV" "ENABLE_LICENSE" "$ENABLE_LICENSE"
|
|
|
|
# Write secrets.env
|
|
set_env_value "$ROOT_DIR/config/secrets.env" "MYSQL_PASSWORD" "$MYSQL_PASSWORD"
|
|
[ -n "${MYSQL_ROOT_PASSWORD:-}" ] && \
|
|
set_env_value "$ROOT_DIR/config/secrets.env" "MYSQL_ROOT_PASSWORD" "$MYSQL_ROOT_PASSWORD"
|
|
set_env_value "$ROOT_DIR/config/secrets.env" "REDIS_PASSWORD" "$REDIS_PASSWORD"
|
|
|
|
"$ROOT_DIR/scripts/render-config.sh"
|
|
|
|
audit "configure" "DONE" "config ready"
|
|
progress "configure" "DONE" "config ready"
|
|
printf '\nConfiguration complete. Review .env and config/secrets.env before deployment.\n'
|