#!/usr/bin/env bash # Orchestrates the Phase 4.1 two-host routing simulation end-to-end: generates a real TLS # bundle, computes the sim-platform-net gateway IP, renders the lab_hosts seed with it, brings # the stack up, runs test-remote-routing.js, tears everything down. See README.md in this # directory and docs/PHASE4_1_PREPRODUCTION_HARDENING.md ยง6. # # Usage: ./run-simulation.sh [--keep-up] (--keep-up skips teardown, for debugging) set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" KEEP_UP=false [ "${1:-}" = "--keep-up" ] && KEEP_UP=true WORK_DIR="$(mktemp -d)" trap 'rm -rf "$WORK_DIR"' EXIT export PROVISIONER_SHARED_SECRET="${PROVISIONER_SHARED_SECRET:-sim-shared-secret-not-for-real-use}" export LAB_IMAGE_REF="${LAB_IMAGE_REF:-rootnode-academy:test}" export SIM_TLS_DIR="$WORK_DIR/tls" export SIM_LAB_HOSTS_SEED="$WORK_DIR/lab-hosts.seed.yaml" echo "==> [1/6] Creating sim-platform-net so we know its real gateway IP before generating certs" NET_NAME="rootnode-sim-platform-net" docker network inspect "$NET_NAME" >/dev/null 2>&1 || docker network create "$NET_NAME" >/dev/null GW_IP="$(docker network inspect "$NET_NAME" --format '{{(index .IPAM.Config 0).Gateway}}')" echo " sim-platform-net gateway IP: $GW_IP (lab-router and provisioner/api, all host-networked, are reachable from Gateway's isolated network through this address)" echo "==> [2/6] Generating a real mTLS bundle for this simulation run (SAN covers the real gateway IP above)" ../docker-tls/generate-docker-tls.sh --out-dir "$SIM_TLS_DIR" --lab-host-ip "$GW_IP" --lab-host-dns lab-router-sim >/dev/null # Rewrite the compose file's network name to match what we just created/inspected, and point # the sim gateway/router services at the shared network by that exact name. export COMPOSE_NET_NAME="$NET_NAME" echo "==> [3/6] Rendering lab-hosts.seed.yaml with routing_mode: router at the real gateway IP" cat > "$SIM_LAB_HOSTS_SEED" < [4/6] Building and starting the simulated two-host stack" docker compose -f docker-compose.simulate.yml -p rootnode-sim up -d --build cleanup() { if [ "$KEEP_UP" = true ]; then echo "==> --keep-up set, leaving the stack running (docker compose -f docker-compose.simulate.yml -p rootnode-sim down to clean up)" return fi echo "==> [6/6] Tearing down the simulation stack" docker compose -f docker-compose.simulate.yml -p rootnode-sim down -v >/dev/null 2>&1 || true docker network rm "$NET_NAME" >/dev/null 2>&1 || true } trap cleanup EXIT echo "==> Waiting for services to become healthy" for i in $(seq 1 60); do if curl -sf http://localhost:4301/healthz >/dev/null 2>&1 && curl -sf http://localhost:4210/healthz >/dev/null 2>&1; then break fi sleep 2 done echo "==> [5/6] Running the routing test" GATEWAY_URL=http://localhost:4210 \ PROVISIONER_URL=http://localhost:4101 \ PROVISIONER_SHARED_SECRET="$PROVISIONER_SHARED_SECRET" \ GATEWAY_CONTAINER=rootnode-sim-gateway-1 \ node test-remote-routing.js