223 lines
7.5 KiB
Bash
Executable File
223 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/demo.sh — bring the whole stack up: certs → build → VM+Grafana →
|
|
# substrate → simulator. Tails simulator progress in the foreground. Ctrl-C
|
|
# cleans everything up.
|
|
#
|
|
# Overridable via env vars:
|
|
# PROFILE single | industrial (default: industrial)
|
|
# RATE_HZ T1 datagram rate (default: 500)
|
|
# T2_RATE_HZ T2 uni stream rate (default: 5)
|
|
# T3_RATE_HZ T3 bi stream rate (default: 2)
|
|
# DEVICES number of devices (default: 5)
|
|
# BUILD release | debug (default: release)
|
|
# KEEP_MONITORING if 1, don't `docker compose down` on exit (default: 0)
|
|
#
|
|
# Example:
|
|
# ./scripts/demo.sh
|
|
# PROFILE=single RATE_HZ=100 DEVICES=20 ./scripts/demo.sh
|
|
# KEEP_MONITORING=1 ./scripts/demo.sh
|
|
|
|
set -euo pipefail
|
|
|
|
# --- locate repo root ---
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
# --- defaults ---
|
|
PROFILE="${PROFILE:-industrial}"
|
|
RATE_HZ="${RATE_HZ:-500}"
|
|
T2_RATE_HZ="${T2_RATE_HZ:-5}"
|
|
T3_RATE_HZ="${T3_RATE_HZ:-2}"
|
|
DEVICES="${DEVICES:-5}"
|
|
BUILD="${BUILD:-release}"
|
|
KEEP_MONITORING="${KEEP_MONITORING:-0}"
|
|
LOG_DIR="${LOG_DIR:-/tmp/quic_ecs_dt}"
|
|
|
|
# --- pretty logging ---
|
|
if [[ -t 1 ]]; then
|
|
BOLD=$'\033[1m'; DIM=$'\033[2m'; GREEN=$'\033[32m'
|
|
YELLOW=$'\033[33m'; RED=$'\033[31m'; CYAN=$'\033[36m'; RESET=$'\033[0m'
|
|
else
|
|
BOLD=; DIM=; GREEN=; YELLOW=; RED=; CYAN=; RESET=
|
|
fi
|
|
step() { printf '%s» %s%s\n' "$BOLD" "$1" "$RESET"; }
|
|
ok() { printf '%s ✓ %s%s\n' "$GREEN" "$1" "$RESET"; }
|
|
warn() { printf '%s ! %s%s\n' "$YELLOW" "$1" "$RESET"; }
|
|
fail() { printf '%s ✗ %s%s\n' "$RED" "$1" "$RESET"; }
|
|
|
|
# --- prereq check ---
|
|
step "Checking prerequisites"
|
|
for cmd in cargo docker openssl curl lsof; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
fail "missing required command: $cmd"
|
|
exit 1
|
|
fi
|
|
done
|
|
if ! docker compose version >/dev/null 2>&1; then
|
|
fail "docker compose plugin not available (try 'docker compose version')"
|
|
exit 1
|
|
fi
|
|
ok "cargo, docker, openssl, curl, lsof present"
|
|
|
|
# --- port collision check (substrate runs on 9000 udp + 9100 tcp) ---
|
|
for port in 9000 9100; do
|
|
if lsof -nP -iUDP:$port -iTCP:$port -sTCP:LISTEN 2>/dev/null | grep -q LISTEN; then
|
|
fail "port $port appears to be in use — another substrate or process is running"
|
|
lsof -nP -iUDP:$port -iTCP:$port -sTCP:LISTEN 2>/dev/null | head -5
|
|
exit 1
|
|
fi
|
|
done
|
|
ok "ports 9000 (QUIC) and 9100 (/metrics) are free"
|
|
|
|
# --- certs ---
|
|
step "Ensuring dev TLS cert exists"
|
|
if [[ ! -f certs/server.crt || ! -f certs/server.key ]]; then
|
|
make certs >/dev/null
|
|
ok "generated certs/server.{crt,key}"
|
|
else
|
|
ok "certs/server.{crt,key} already present"
|
|
fi
|
|
|
|
# --- build ---
|
|
step "Building substrate + simulator ($BUILD profile)"
|
|
if [[ "$BUILD" == "release" ]]; then
|
|
cargo build --release -p substrate -p simulator
|
|
SUBSTRATE_BIN="$ROOT/target/release/substrate"
|
|
SIMULATOR_BIN="$ROOT/target/release/simulator"
|
|
else
|
|
cargo build -p substrate -p simulator
|
|
SUBSTRATE_BIN="$ROOT/target/debug/substrate"
|
|
SIMULATOR_BIN="$ROOT/target/debug/simulator"
|
|
fi
|
|
ok "binaries: $SUBSTRATE_BIN, $SIMULATOR_BIN"
|
|
|
|
# --- monitoring ---
|
|
step "Bringing up VictoriaMetrics + Grafana (docker compose)"
|
|
docker compose -f monitoring/docker-compose.yml up -d >/dev/null
|
|
ok "containers started"
|
|
|
|
printf '%s ⏳ waiting for VictoriaMetrics on :8428' "$DIM"
|
|
for i in $(seq 1 40); do
|
|
if curl -sf http://localhost:8428/health >/dev/null 2>&1; then
|
|
printf ' ready%s\n' "$RESET"; break
|
|
fi
|
|
printf '.'; sleep 0.5
|
|
if [[ $i -eq 40 ]]; then printf ' TIMEOUT%s\n' "$RESET"; exit 1; fi
|
|
done
|
|
|
|
printf '%s ⏳ waiting for Grafana on :3000' "$DIM"
|
|
for i in $(seq 1 40); do
|
|
if curl -sf http://localhost:3000/api/health >/dev/null 2>&1; then
|
|
printf ' ready%s\n' "$RESET"; break
|
|
fi
|
|
printf '.'; sleep 0.5
|
|
if [[ $i -eq 40 ]]; then printf ' TIMEOUT%s\n' "$RESET"; exit 1; fi
|
|
done
|
|
|
|
# --- substrate ---
|
|
mkdir -p "$LOG_DIR"
|
|
SUB_LOG="$LOG_DIR/substrate.log"
|
|
SIM_LOG="$LOG_DIR/simulator.log"
|
|
: >"$SUB_LOG"
|
|
: >"$SIM_LOG"
|
|
|
|
step "Starting substrate (log: $SUB_LOG)"
|
|
RUST_LOG=info "$SUBSTRATE_BIN" >"$SUB_LOG" 2>&1 &
|
|
SUBSTRATE_PID=$!
|
|
|
|
printf '%s ⏳ waiting for /metrics on :9100' "$DIM"
|
|
for i in $(seq 1 40); do
|
|
if curl -sf http://localhost:9100/metrics >/dev/null 2>&1; then
|
|
printf ' ready%s\n' "$RESET"; break
|
|
fi
|
|
printf '.'; sleep 0.25
|
|
if [[ $i -eq 40 ]]; then
|
|
printf ' TIMEOUT%s\n' "$RESET"
|
|
warn "substrate failed to start; tail of $SUB_LOG:"
|
|
tail -30 "$SUB_LOG"
|
|
kill "$SUBSTRATE_PID" 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# --- simulator ---
|
|
TOTAL_SLOTS=$DEVICES
|
|
if [[ "$PROFILE" == "industrial" ]]; then
|
|
TOTAL_SLOTS=$((DEVICES * 5))
|
|
fi
|
|
|
|
step "Starting simulator (log: $SIM_LOG)"
|
|
RUST_LOG=info "$SIMULATOR_BIN" \
|
|
--profile "$PROFILE" \
|
|
--rate-hz "$RATE_HZ" \
|
|
--t2-rate-hz "$T2_RATE_HZ" \
|
|
--t3-rate-hz "$T3_RATE_HZ" \
|
|
--count 0 \
|
|
--devices "$DEVICES" \
|
|
>"$SIM_LOG" 2>&1 &
|
|
SIMULATOR_PID=$!
|
|
sleep 0.5
|
|
if ! kill -0 "$SIMULATOR_PID" 2>/dev/null; then
|
|
fail "simulator exited immediately; tail of $SIM_LOG:"
|
|
tail -20 "$SIM_LOG"
|
|
kill "$SUBSTRATE_PID" 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
ok "simulator PID $SIMULATOR_PID"
|
|
|
|
# --- cleanup trap ---
|
|
cleanup() {
|
|
printf '\n%s» Cleaning up%s\n' "$BOLD" "$RESET"
|
|
if [[ -n "${SIMULATOR_PID:-}" ]]; then
|
|
kill -TERM "$SIMULATOR_PID" 2>/dev/null || true
|
|
wait "$SIMULATOR_PID" 2>/dev/null || true
|
|
ok "simulator stopped"
|
|
fi
|
|
if [[ -n "${SUBSTRATE_PID:-}" ]]; then
|
|
kill -TERM "$SUBSTRATE_PID" 2>/dev/null || true
|
|
wait "$SUBSTRATE_PID" 2>/dev/null || true
|
|
ok "substrate stopped"
|
|
fi
|
|
if [[ "$KEEP_MONITORING" == "1" ]]; then
|
|
warn "leaving monitoring stack up (KEEP_MONITORING=1) — 'make monitoring-down' to stop"
|
|
else
|
|
docker compose -f monitoring/docker-compose.yml down >/dev/null 2>&1 || true
|
|
ok "monitoring stack stopped"
|
|
fi
|
|
printf '%sLogs preserved at:%s %s\n' "$DIM" "$RESET" "$LOG_DIR"
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# --- summary ---
|
|
cat <<EOF
|
|
|
|
${BOLD}════════════════════════════════════════════════════════════${RESET}
|
|
${BOLD} Demo is live${RESET}
|
|
${BOLD}════════════════════════════════════════════════════════════${RESET}
|
|
|
|
${CYAN}Grafana${RESET} http://localhost:3000 (admin / admin)
|
|
sensors dash http://localhost:3000/d/quic-ecs-dt-sensors
|
|
runtime dash http://localhost:3000/d/quic-ecs-dt-runtime
|
|
${CYAN}VictoriaMetrics${RESET} http://localhost:8428
|
|
${CYAN}substrate /metrics${RESET} http://localhost:9100/metrics
|
|
|
|
${DIM}Logs${RESET}
|
|
substrate $SUB_LOG
|
|
simulator $SIM_LOG
|
|
|
|
${DIM}Config${RESET}
|
|
profile $PROFILE
|
|
rates T1=$RATE_HZ Hz · T2=$T2_RATE_HZ Hz · T3=$T3_RATE_HZ Hz
|
|
devices $DEVICES → $TOTAL_SLOTS sensor entities expected
|
|
build $BUILD
|
|
|
|
${DIM}Below: live tail of simulator progress (Ctrl-C to stop everything).${RESET}
|
|
|
|
EOF
|
|
|
|
# --- foreground tail of simulator progress ---
|
|
# Filter for the per-second `progress` / `simulator done` lines so the user
|
|
# sees the rates the simulator is observing without noise.
|
|
tail -F "$SIM_LOG" | grep --line-buffered -E 'progress|simulator (done|launching|client connected)'
|