feat(deploy): onboard-node.sh — one-command cluster node provisioning
This commit is contained in:
parent
0b255e063f
commit
0b49f28a80
1 changed files with 161 additions and 0 deletions
161
deploy/onboard-node.sh
Normal file
161
deploy/onboard-node.sh
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Wild Dragon MAM — Cluster Node Onboarding
|
||||
# =============================================================================
|
||||
#
|
||||
# Provisions a Linux machine as a cluster worker node in one command.
|
||||
#
|
||||
# Quick-start (pipe to bash):
|
||||
# export MAM_API_URL=http://10.0.0.25:47432
|
||||
# export NODE_TOKEN=wd_xxxx # create via Z-AMPP → Admin → Tokens
|
||||
# curl -sL https://forge.wilddragon.net/zgaetano/wild-dragon/raw/branch/main/deploy/onboard-node.sh | bash
|
||||
#
|
||||
# Or run from a cloned repo:
|
||||
# MAM_API_URL=http://10.0.0.25:47432 NODE_TOKEN=wd_xxxx ./deploy/onboard-node.sh
|
||||
#
|
||||
# Environment variables:
|
||||
# MAM_API_URL REQUIRED Primary MAM API base URL
|
||||
# NODE_TOKEN API bearer token (required if AUTH_ENABLED=true)
|
||||
# NODE_ROLE Role tag reported to the cluster (default: worker)
|
||||
# AGENT_PORT Host port for the node agent (default: 7436)
|
||||
# INSTALL_DIR Where to clone/find the repo (default: /opt/wild-dragon)
|
||||
# PROFILES Extra compose profiles, space-separated e.g. "worker"
|
||||
# REPO_URL Override the Forgejo clone URL
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Config ───────────────────────────────────────────────────────────────────
|
||||
REPO_URL="${REPO_URL:-https://forge.wilddragon.net/zgaetano/wild-dragon.git}"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/wild-dragon}"
|
||||
MAM_API_URL="${MAM_API_URL:-}"
|
||||
NODE_TOKEN="${NODE_TOKEN:-}"
|
||||
NODE_ROLE="${NODE_ROLE:-worker}"
|
||||
AGENT_PORT="${AGENT_PORT:-7436}"
|
||||
PROFILES="${PROFILES:-}"
|
||||
PROJECT_NAME="wild-dragon-worker"
|
||||
|
||||
# ── Colours ──────────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; YEL='\033[1;33m'; GRN='\033[0;32m'; CYN='\033[0;36m'
|
||||
BLD='\033[1m'; NC='\033[0m'
|
||||
log() { echo -e "${GRN} ✓${NC} $*"; }
|
||||
info() { echo -e "${CYN} ▶${NC} $*"; }
|
||||
warn() { echo -e "${YEL} ⚠${NC} $*"; }
|
||||
header() { echo -e "\n${BLD}${CYN}── $* ──────────────────────────────────────${NC}"; }
|
||||
die() { echo -e "${RED} ✗ ERROR:${NC} $*" >&2; exit 1; }
|
||||
|
||||
# ── Preflight ────────────────────────────────────────────────────────────────
|
||||
echo -e "\n${BLD}${CYN}Wild Dragon MAM — Cluster Node Onboarding${NC}\n"
|
||||
|
||||
[[ -z "$MAM_API_URL" ]] && die "MAM_API_URL is required.\n\n Example:\n export MAM_API_URL=http://10.0.0.25:47432\n export NODE_TOKEN=wd_xxxx\n ./deploy/onboard-node.sh"
|
||||
|
||||
info "Primary API : $MAM_API_URL"
|
||||
info "Role : $NODE_ROLE"
|
||||
info "Agent port : $AGENT_PORT"
|
||||
info "Install dir : $INSTALL_DIR"
|
||||
[[ -n "$PROFILES" ]] && info "Profiles : $PROFILES"
|
||||
|
||||
if [[ -z "$NODE_TOKEN" ]]; then
|
||||
warn "NODE_TOKEN is not set."
|
||||
warn "If AUTH_ENABLED=true on the primary, heartbeats will be rejected."
|
||||
warn "Create a token: Z-AMPP web UI → Admin → Tokens → New Token"
|
||||
fi
|
||||
|
||||
# ── Step 1: Docker ───────────────────────────────────────────────────────────
|
||||
header "1/4 Docker"
|
||||
|
||||
if ! command -v docker &>/dev/null; then
|
||||
warn "Docker not found — installing via get.docker.com"
|
||||
curl -fsSL https://get.docker.com | bash
|
||||
systemctl enable --now docker 2>/dev/null || true
|
||||
# Add current user to docker group (effective on next login)
|
||||
usermod -aG docker "${SUDO_USER:-$USER}" 2>/dev/null || true
|
||||
log "Docker installed"
|
||||
else
|
||||
log "Docker $(docker --version | grep -oP '\d+\.\d+\.\d+' | head -1) already installed"
|
||||
fi
|
||||
|
||||
if ! docker info &>/dev/null; then
|
||||
die "Docker daemon not accessible.\n Try: sudo systemctl start docker\n Or add your user to the docker group and re-login."
|
||||
fi
|
||||
|
||||
# ── Step 2: Repository ───────────────────────────────────────────────────────
|
||||
header "2/4 Repository"
|
||||
|
||||
if [[ -d "$INSTALL_DIR/.git" ]]; then
|
||||
info "Updating $INSTALL_DIR"
|
||||
git -C "$INSTALL_DIR" pull --ff-only
|
||||
log "Repository up to date ($(git -C "$INSTALL_DIR" rev-parse --short HEAD))"
|
||||
else
|
||||
info "Cloning $REPO_URL → $INSTALL_DIR"
|
||||
mkdir -p "$(dirname "$INSTALL_DIR")"
|
||||
git clone "$REPO_URL" "$INSTALL_DIR"
|
||||
log "Repository cloned"
|
||||
fi
|
||||
|
||||
# ── Step 3: Environment ──────────────────────────────────────────────────────
|
||||
header "3/4 Configuration"
|
||||
|
||||
ENV_FILE="$INSTALL_DIR/.env.worker"
|
||||
info "Writing $ENV_FILE"
|
||||
|
||||
{
|
||||
echo "# Wild Dragon worker node — generated $(date -u +%Y-%m-%dT%H:%M:%SZ) by onboard-node.sh"
|
||||
echo "MAM_API_URL=$MAM_API_URL"
|
||||
echo "NODE_TOKEN=$NODE_TOKEN"
|
||||
echo "NODE_ROLE=$NODE_ROLE"
|
||||
echo "AGENT_PORT=$AGENT_PORT"
|
||||
echo "HEARTBEAT_MS=30000"
|
||||
for v in REDIS_URL DATABASE_URL S3_ENDPOINT S3_BUCKET S3_ACCESS_KEY S3_SECRET_KEY S3_REGION; do
|
||||
val="${!v:-}"
|
||||
[[ -n "$val" ]] && echo "$v=$val"
|
||||
done
|
||||
} > "$ENV_FILE"
|
||||
|
||||
log "Env file written"
|
||||
|
||||
# ── Step 4: Start services ───────────────────────────────────────────────────
|
||||
header "4/4 Starting services"
|
||||
|
||||
COMPOSE="docker compose -f $INSTALL_DIR/docker-compose.worker.yml --env-file $ENV_FILE --project-name $PROJECT_NAME"
|
||||
|
||||
PROFILE_FLAGS=""
|
||||
for p in $PROFILES; do
|
||||
PROFILE_FLAGS="$PROFILE_FLAGS --profile $p"
|
||||
done
|
||||
|
||||
info "Building images (this may take a minute on first run)…"
|
||||
$COMPOSE build
|
||||
|
||||
info "Starting containers…"
|
||||
# shellcheck disable=SC2086
|
||||
$COMPOSE $PROFILE_FLAGS up -d
|
||||
|
||||
# ── Verify ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
info "Waiting 6 seconds for agent to initialise…"
|
||||
sleep 6
|
||||
|
||||
HEALTH_URL="http://localhost:$AGENT_PORT/health"
|
||||
if curl -sf "$HEALTH_URL" > /dev/null 2>&1; then
|
||||
log "Node agent healthy at $HEALTH_URL"
|
||||
else
|
||||
warn "Could not reach $HEALTH_URL — check logs:"
|
||||
warn " $COMPOSE logs node-agent"
|
||||
fi
|
||||
|
||||
# ── Done ─────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e "${BLD}${GRN}Onboarding complete!${NC}"
|
||||
echo ""
|
||||
echo -e " Node agent ${BLD}:$AGENT_PORT${NC} (heartbeating every 30s)"
|
||||
echo -e " Primary API ${BLD}$MAM_API_URL${NC}"
|
||||
echo -e " Role ${BLD}$NODE_ROLE${NC}"
|
||||
echo ""
|
||||
echo -e " ${CYN}Useful commands:${NC}"
|
||||
echo -e " Status : $COMPOSE ps"
|
||||
echo -e " Logs : $COMPOSE logs -f"
|
||||
echo -e " Stop : $COMPOSE down"
|
||||
echo -e " Update : git -C $INSTALL_DIR pull && $COMPOSE build && $COMPOSE up -d"
|
||||
echo ""
|
||||
echo -e " Open the Z-AMPP web UI → ${BLD}Admin → Cluster${NC} to see this node."
|
||||
Loading…
Reference in a new issue