Removes hardcoded 10.40.40.202 references so a fresh clone + .env-only
edit can stand the stack up on a new compute node.
* docker-compose.yml: rib-poller PG_DSN now uses ${HOST_IP:-...}.
* obmp-rib-poller/poller.py: default PG_DSN host falls back to
${HOST_IP} env (compose passes it; manual runs honour $HOST_IP too).
* cml/gobgp_peering_config.py: GOBGP_IP read from $HOST_IP or the
HOST_IP= line in repo-root .env, with a small _env_default helper.
* cml/proxmox_bmp_config.py: COLLECTOR_HOST resolved the same way.
For gobgp/gobgpd.conf and gobgp-evpn/gobgpd.conf -- jauderho/gobgp is
distroless (no shell), so we can't sed-substitute at container start.
Pattern instead:
* gobgpd.conf is now gobgpd.conf.tmpl with __HOST_IP__ placeholders
(committed). The rendered gobgpd.conf is gitignored.
* setup.sh renders the .tmpl(s) to .conf using $HOST_IP from .env.
* compose `command` stays the simple `gobgpd -f /config/gobgpd.conf`.
After cloning on a new host: cp .env.example .env -> edit HOST_IP ->
./setup.sh -> docker compose up -d. Verified locally by force-recreating
gobgp; all 6 sessions (4 cores + 2 Bromirski) re-established in <60s.
Known portability gaps still to address (separate work):
* Hardcoded lab-router inventories in cml/*.py and
obmp-rib-poller/poller.py.
* The /etc/cron.d/openbmp */5 -> */15 edit inside obmp-psql-app is
not persistent (regenerated by config_cron on every container start).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
138 lines
5.3 KiB
Bash
Executable File
138 lines
5.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# OpenBMP stack bootstrap — idempotent. Safe to run against an existing
|
|
# deployment: every step is guarded and never overwrites live config.
|
|
#
|
|
# cp .env.example .env # first run only
|
|
# $EDITOR .env # fill in HOST_IP, OBMP_DOMAIN, ...
|
|
# ./setup.sh
|
|
# docker compose up -d # collector core
|
|
# docker compose --profile test --profile auth up -d # full stack
|
|
#
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
|
|
AUTHELIA_IMAGE="authelia/authelia:4.38"
|
|
|
|
# --- .env -------------------------------------------------------------------
|
|
if [ ! -f .env ]; then
|
|
cp .env.example .env
|
|
echo "Created .env from .env.example."
|
|
echo "Edit it (HOST_IP, OBMP_DOMAIN, OBMP_COOKIE_DOMAIN, credentials), then re-run ./setup.sh"
|
|
exit 1
|
|
fi
|
|
|
|
# Read a single KEY=value from .env without sourcing it — .env contains keys
|
|
# with hyphens (PROX-CML_*) that a shell `source` would choke on.
|
|
get_env() { grep -E "^$1=" .env | head -1 | cut -d= -f2- || true; }
|
|
|
|
# Set KEY=value in .env: replace the line if present, else append.
|
|
set_env() {
|
|
local key="$1" val="$2"
|
|
if grep -qE "^${key}=" .env; then
|
|
# `|` delimiter — values are hex, no `|`.
|
|
sed -i "s|^${key}=.*|${key}=${val}|" .env
|
|
else
|
|
printf '%s=%s\n' "$key" "$val" >> .env
|
|
fi
|
|
}
|
|
|
|
OBMP_DATA_ROOT="$(get_env OBMP_DATA_ROOT)"
|
|
OBMP_DATA_ROOT="${OBMP_DATA_ROOT:-/var/openbmp}"
|
|
OBMP_DOMAIN="$(get_env OBMP_DOMAIN)"
|
|
OBMP_COOKIE_DOMAIN="$(get_env OBMP_COOKIE_DOMAIN)"
|
|
HOST_IP="$(get_env HOST_IP)"
|
|
|
|
# --- validate ---------------------------------------------------------------
|
|
fail=0
|
|
for var in HOST_IP OBMP_DOMAIN OBMP_COOKIE_DOMAIN; do
|
|
val="$(get_env "$var")"
|
|
if [ -z "$val" ] || [[ "$val" == changeme* ]]; then
|
|
echo "ERROR: $var is unset or still 'changeme' in .env" >&2
|
|
fail=1
|
|
fi
|
|
done
|
|
[ "$fail" -eq 0 ] || { echo "Fix .env and re-run." >&2; exit 1; }
|
|
|
|
# --- privilege helper -------------------------------------------------------
|
|
# $OBMP_DATA_ROOT is often root-owned (e.g. /var/openbmp). Use sudo only if the
|
|
# current user cannot write the parent directory.
|
|
parent="$(dirname "$OBMP_DATA_ROOT")"
|
|
SUDO=""
|
|
if [ ! -w "$parent" ] || { [ -d "$OBMP_DATA_ROOT" ] && [ ! -w "$OBMP_DATA_ROOT" ]; }; then
|
|
SUDO="sudo"
|
|
echo "Note: using sudo for filesystem setup under $OBMP_DATA_ROOT"
|
|
fi
|
|
|
|
# --- data-root directory tree -----------------------------------------------
|
|
echo "Creating data tree under $OBMP_DATA_ROOT ..."
|
|
for d in config grafana grafana/provisioning kafka-data zk-data zk-log \
|
|
postgres/data postgres/ts influxdb authelia; do
|
|
$SUDO mkdir -p "$OBMP_DATA_ROOT/$d"
|
|
done
|
|
# Container processes run as assorted UIDs; lab-permissive perms.
|
|
$SUDO chmod -R 777 "$OBMP_DATA_ROOT" 2>/dev/null || true
|
|
|
|
# --- Grafana provisioning ---------------------------------------------------
|
|
echo "Syncing Grafana provisioning ..."
|
|
$SUDO cp -r obmp-grafana/provisioning/. "$OBMP_DATA_ROOT/grafana/provisioning/"
|
|
|
|
# --- Authelia secrets -------------------------------------------------------
|
|
# Generate only if blank/absent; never overwrite an existing value.
|
|
for key in AUTHELIA_SESSION_SECRET AUTHELIA_JWT_SECRET AUTHELIA_STORAGE_ENCRYPTION_KEY; do
|
|
cur="$(get_env "$key")"
|
|
if [ -z "$cur" ]; then
|
|
set_env "$key" "$(openssl rand -hex 32)"
|
|
echo "Generated $key"
|
|
fi
|
|
done
|
|
AUTHELIA_SESSION_SECRET="$(get_env AUTHELIA_SESSION_SECRET)"
|
|
AUTHELIA_JWT_SECRET="$(get_env AUTHELIA_JWT_SECRET)"
|
|
AUTHELIA_STORAGE_ENCRYPTION_KEY="$(get_env AUTHELIA_STORAGE_ENCRYPTION_KEY)"
|
|
|
|
# --- Authelia config (fresh-deploy only — never clobber a live config) ------
|
|
export AUTHELIA_SESSION_SECRET AUTHELIA_JWT_SECRET AUTHELIA_STORAGE_ENCRYPTION_KEY \
|
|
OBMP_DOMAIN OBMP_COOKIE_DOMAIN
|
|
SUBST='${AUTHELIA_SESSION_SECRET} ${AUTHELIA_JWT_SECRET} ${AUTHELIA_STORAGE_ENCRYPTION_KEY} ${OBMP_DOMAIN} ${OBMP_COOKIE_DOMAIN}'
|
|
|
|
if [ ! -f "$OBMP_DATA_ROOT/authelia/configuration.yml" ]; then
|
|
envsubst "$SUBST" < authelia/configuration.yml.template \
|
|
| $SUDO tee "$OBMP_DATA_ROOT/authelia/configuration.yml" > /dev/null
|
|
echo "Rendered authelia/configuration.yml"
|
|
else
|
|
echo "authelia/configuration.yml exists — left untouched"
|
|
fi
|
|
|
|
if [ ! -f "$OBMP_DATA_ROOT/authelia/users_database.yml" ]; then
|
|
$SUDO cp authelia/users_database.yml.template \
|
|
"$OBMP_DATA_ROOT/authelia/users_database.yml"
|
|
echo "Rendered authelia/users_database.yml (demo user: openbmp)"
|
|
else
|
|
echo "authelia/users_database.yml exists — left untouched"
|
|
fi
|
|
|
|
# --- gobgpd.conf rendering (host-side -- gobgp image is distroless) ---------
|
|
# Render gobgp{,-evpn}/gobgpd.conf from gobgpd.conf.tmpl, substituting
|
|
# __HOST_IP__ with $HOST_IP. The rendered .conf is gitignored.
|
|
for d in gobgp gobgp-evpn; do
|
|
if [ -f "$d/gobgpd.conf.tmpl" ]; then
|
|
sed -e "s/__HOST_IP__/$HOST_IP/g" "$d/gobgpd.conf.tmpl" > "$d/gobgpd.conf"
|
|
echo "Rendered $d/gobgpd.conf (HOST_IP=$HOST_IP)"
|
|
fi
|
|
done
|
|
|
|
# --- images -----------------------------------------------------------------
|
|
echo "Pulling and building images ..."
|
|
docker compose pull --quiet
|
|
docker compose --profile test --profile auth build
|
|
|
|
# --- done -------------------------------------------------------------------
|
|
cat <<EOF
|
|
|
|
Setup complete.
|
|
|
|
docker compose up -d # BMP collector core
|
|
docker compose --profile test --profile auth up -d # full stack (lab + auth)
|
|
|
|
EOF
|