deploy.sh: teardown subcommand, fresh-host preflight, guided interactive flow
Implements the one-shot goal from the greenfield audit: tear down fully and/or deploy cleanly on a pristine WSL instance with nothing but the interactive script. - './deploy.sh teardown': leave-it-down removal across ALL compose profiles (core/test/auth/evpn-test/scale-out -- the old reset missed the last two), networks, named volumes, rendered gobgpd.confs. Data wipe is opt-in (--wipe-data, guarded on native hosts) and preserves backups/ unless --purge-backups; --purge-images reclaims images. Prints the Windows-side cleanup (wsl-portproxy.ps1 -Remove, new switch). - fresh-host preflight: verifies the docker DAEMON (not just the client), offers to install docker-ce from the official repo (--install-prereqs for unattended), and handles the classic pristine-WSL trap: systemd off -> writes /etc/wsl.conf [boot] systemd=true and stops with exact restart instructions instead of dying cryptically. - sudo authenticates ONCE up front (no more password prompt buried mid-provision); --reset now covers all profiles and preserves backups/ - guided flow: banner, Step N/6 headers, context lines explaining HOST_IP-vs-router-facing before the address prompts, router-facing IP validated as a dotted quad (a failed Windows-LAN autodetect can no longer write a <WINDOWS_LAN_IP> placeholder into .env), stage completions print green checkmarks, loud abort note on the plan confirm, post-deploy Verify + teardown hints. - shared helpers moved to scripts/deploy-lib.sh; setup.sh sources it too (duplicate get_env/set_env/ask/confirm definitions deleted), keeping setup.sh as a standalone provisioning primitive. Verified live on this host: teardown left zero obmp containers and removed rendered configs; unattended redeploy brought the stack back. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
da975d7375
commit
5b5593b6cc
264
deploy.sh
264
deploy.sh
@ -17,14 +17,22 @@
|
||||
# ./deploy.sh # interactive; auto-detect + prompts
|
||||
# ./deploy.sh --wsl | --prod # force host type (still prompts rest)
|
||||
# ./deploy.sh --host-ip 10.0.0.50 # preset HOST_IP (internal stack IP)
|
||||
# ./deploy.sh --router-ip 10.0.0.9 --router-port 5000 # BMP-facing target
|
||||
# ./deploy.sh --router-ip 10.0.0.9 --router-port 1790 # BMP-facing target
|
||||
# ./deploy.sh --auth local|authelia
|
||||
# ./deploy.sh --scope full-stack|remote|central-store
|
||||
# ./deploy.sh --central-kafka 10.0.0.50:9092 # for --scope remote
|
||||
# ./deploy.sh --reset # wipe data tree first (guarded on prod)
|
||||
# ./deploy.sh --install-prereqs # allow installing docker-ce unattended
|
||||
# ./deploy.sh --prod --yes # unattended (needs enough presets)
|
||||
# REPO_DIR=/opt/obmp-docker ./deploy.sh
|
||||
#
|
||||
# ./deploy.sh teardown # stop + remove EVERYTHING, leave it down
|
||||
# --wipe-data # also wipe $OBMP_DATA_ROOT (guarded;
|
||||
# # backups/ preserved by default)
|
||||
# --purge-images # also remove stack images
|
||||
# --purge-backups # do not preserve backups/ on wipe
|
||||
# --yes # unattended (requires explicit flags)
|
||||
#
|
||||
# SCOPE / DEPLOYMENT LEVELS (what each includes, excludes, ballpark sysreqs):
|
||||
#
|
||||
# core Collector core: zookeeper, kafka, psql, collector, psql-app,
|
||||
@ -119,9 +127,19 @@ ARG_ROUTER_IP=""
|
||||
ARG_ROUTER_PORT=""
|
||||
ARG_AUTH="" # local | authelia
|
||||
ARG_SCOPE="" # full-stack | remote | central-store (aliases accepted)
|
||||
ARG_CENTRAL_KAFKA="" # host:port for --scope standalone
|
||||
ARG_CENTRAL_KAFKA="" # host:port for --scope remote
|
||||
ARG_RESET=0
|
||||
ARG_YES=0
|
||||
ARG_INSTALL_PREREQS=0
|
||||
COMMAND="deploy" # deploy (default) | teardown
|
||||
ARG_WIPE_DATA=0 # teardown: also wipe $OBMP_DATA_ROOT
|
||||
ARG_PURGE_IMAGES=0 # teardown: also remove stack images
|
||||
ARG_PURGE_BACKUPS=0 # teardown: do NOT preserve $OBMP_DATA_ROOT/backups
|
||||
|
||||
# First positional arg may be a subcommand.
|
||||
case "${1:-}" in
|
||||
teardown) COMMAND="teardown"; shift ;;
|
||||
esac
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
@ -140,6 +158,10 @@ while [ $# -gt 0 ]; do
|
||||
--central-kafka) ARG_CENTRAL_KAFKA="${2:?--central-kafka needs host:port}"; shift ;;
|
||||
--central-kafka=*) ARG_CENTRAL_KAFKA="${1#*=}" ;;
|
||||
--reset) ARG_RESET=1 ;;
|
||||
--install-prereqs) ARG_INSTALL_PREREQS=1 ;;
|
||||
--wipe-data) ARG_WIPE_DATA=1 ;;
|
||||
--purge-images) ARG_PURGE_IMAGES=1 ;;
|
||||
--purge-backups) ARG_PURGE_BACKUPS=1 ;;
|
||||
--yes|-y) ARG_YES=1 ;;
|
||||
-h|--help) grep '^#' "$0" | sed 's/^#//'; exit 0 ;;
|
||||
*) echo "Unknown arg: $1" >&2; exit 1 ;;
|
||||
@ -147,10 +169,9 @@ while [ $# -gt 0 ]; do
|
||||
shift
|
||||
done
|
||||
|
||||
log() { printf '\033[1;36m[deploy]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[deploy][warn]\033[0m %s\n' "$*" >&2; }
|
||||
die() { printf '\033[1;31m[deploy][err]\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
hr() { printf '\033[2m%s\033[0m\n' "----------------------------------------------------------------"; }
|
||||
# Shared output/prompt/.env helpers (log ok warn die hr banner step ask
|
||||
# confirm get_env set_env is_ipv4) -- single definition for all deploy tooling.
|
||||
. "$REPO_DIR/scripts/deploy-lib.sh"
|
||||
|
||||
# Return the host-published TCP ports this deployment type will bind, so we can
|
||||
# check them for collisions BEFORE bring-up. Ports come from docker-compose.yml
|
||||
@ -225,32 +246,71 @@ preflight_ports() {
|
||||
return $conflict
|
||||
}
|
||||
|
||||
# Prompt with an editable default. Honors --yes (accepts default silently).
|
||||
ask() {
|
||||
local __var="$1" __prompt="$2" __default="${3:-}" __reply=""
|
||||
if [ "$ARG_YES" -eq 1 ]; then
|
||||
printf -v "$__var" '%s' "$__default"; return
|
||||
fi
|
||||
if [ -n "$__default" ]; then
|
||||
read -r -p "$__prompt [$__default]: " __reply
|
||||
__reply="${__reply:-$__default}"
|
||||
else
|
||||
read -r -p "$__prompt: " __reply
|
||||
fi
|
||||
printf -v "$__var" '%s' "$__reply"
|
||||
}
|
||||
|
||||
confirm() {
|
||||
local __prompt="$1" __reply=""
|
||||
[ "$ARG_YES" -eq 1 ] && return 0
|
||||
read -r -p "$__prompt [y/N]: " __reply
|
||||
[ "$__reply" = "y" ] || [ "$__reply" = "Y" ]
|
||||
}
|
||||
|
||||
cd "$REPO_DIR" || die "REPO_DIR '$REPO_DIR' not found"
|
||||
[ -f docker-compose.yml ] || die "no docker-compose.yml in $REPO_DIR - set REPO_DIR"
|
||||
command -v docker >/dev/null || die "docker not found"
|
||||
docker compose version >/dev/null 2>&1 || die "docker compose v2 not available"
|
||||
|
||||
# --- host prerequisites (fresh-WSL friendly) --------------------------------
|
||||
# A pristine WSL2 Ubuntu has neither docker-ce nor systemd enabled; check the
|
||||
# whole chain and either remediate (--install-prereqs / interactive offer) or
|
||||
# print the exact fix instead of dying with a bare message mid-run.
|
||||
install_docker_ce() {
|
||||
log "Installing docker-ce from the official Docker apt repo ..."
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq ca-certificates curl
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
||||
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
ok "docker-ce installed"
|
||||
}
|
||||
|
||||
ensure_systemd_wsl() {
|
||||
# Native docker in WSL2 needs systemd (the docker service). Pristine
|
||||
# distros ship with it off; flipping it requires a WSL restart, which we
|
||||
# cannot do from inside -- set it up and stop with clear instructions.
|
||||
[ -d /run/systemd/system ] && return 0
|
||||
grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null || return 0
|
||||
warn "systemd is not running -- native docker cannot start without it."
|
||||
if confirm "Enable systemd in /etc/wsl.conf now (needs a WSL restart afterwards)?"; then
|
||||
if ! grep -q '^\[boot\]' /etc/wsl.conf 2>/dev/null; then
|
||||
printf '\n[boot]\nsystemd=true\n' | sudo tee -a /etc/wsl.conf > /dev/null
|
||||
elif ! grep -q '^systemd=true' /etc/wsl.conf; then
|
||||
sudo sed -i '/^\[boot\]/a systemd=true' /etc/wsl.conf
|
||||
fi
|
||||
ok "systemd enabled in /etc/wsl.conf"
|
||||
die "now run 'wsl --shutdown' from Windows, reopen this distro, and re-run ./deploy.sh"
|
||||
fi
|
||||
die "cannot continue without systemd on WSL (docker service will not start)"
|
||||
}
|
||||
|
||||
preflight_host() {
|
||||
if ! command -v docker >/dev/null; then
|
||||
warn "docker is not installed on this host."
|
||||
if [ "$ARG_INSTALL_PREREQS" -eq 1 ] || confirm "Install docker-ce now (official Docker apt repo)?"; then
|
||||
ensure_systemd_wsl
|
||||
install_docker_ce
|
||||
sudo systemctl enable --now docker 2>/dev/null || true
|
||||
else
|
||||
die "install docker-ce first (https://docs.docker.com/engine/install/ubuntu/) or re-run with --install-prereqs"
|
||||
fi
|
||||
fi
|
||||
docker compose version >/dev/null 2>&1 \
|
||||
|| die "docker compose v2 missing - install the docker-compose-plugin package"
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
# client exists but daemon unreachable: systemd off (WSL) or service down
|
||||
ensure_systemd_wsl
|
||||
warn "docker daemon is not running - trying to start it ..."
|
||||
sudo systemctl enable --now docker 2>/dev/null || true
|
||||
sleep 2
|
||||
docker info >/dev/null 2>&1 \
|
||||
|| die "docker daemon still unreachable - check: systemctl status docker"
|
||||
ok "docker daemon started"
|
||||
fi
|
||||
}
|
||||
preflight_host
|
||||
|
||||
# --- Docker Desktop vs native-daemon guard ----------------------------------
|
||||
# On WSL, Docker Desktop runs the daemon in its OWN separate distro
|
||||
@ -285,23 +345,97 @@ if detect_docker_desktop; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- .env helpers -----------------------------------------------------------
|
||||
# --- teardown subcommand -----------------------------------------------------
|
||||
# Leave-it-down teardown: removes every container across ALL compose profiles,
|
||||
# the named volumes, and the rendered gitignored configs. Data-tree wipe is
|
||||
# opt-in (--wipe-data or interactive), preserving backups/ unless
|
||||
# --purge-backups. Images are kept unless --purge-images. Prints the
|
||||
# Windows-side cleanup it cannot reach from inside WSL.
|
||||
ALL_PROFILES=(--profile test --profile auth --profile evpn-test --profile scale-out)
|
||||
cmd_teardown() {
|
||||
banner "OpenBMP stack teardown"
|
||||
local dr; dr="$( [ -f .env ] && get_env OBMP_DATA_ROOT || true )"; dr="${dr:-/var/openbmp}"
|
||||
echo
|
||||
log "This will remove:"
|
||||
echo " - all obmp containers (every profile: core, test, auth, evpn-test, scale-out)"
|
||||
echo " - docker networks + named volumes (obmp_data-volume, obmp_ts-volume)"
|
||||
echo " - rendered configs (gobgp/gobgpd.conf, gobgp-evpn/gobgpd.conf)"
|
||||
[ "$ARG_PURGE_IMAGES" -eq 1 ] && echo " - stack images (--purge-images)"
|
||||
if [ "$ARG_WIPE_DATA" -eq 1 ]; then
|
||||
echo " - DATA TREE $dr (--wipe-data)$( [ "$ARG_PURGE_BACKUPS" -eq 1 ] && echo ' INCLUDING backups/' || echo ', preserving backups/')"
|
||||
else
|
||||
echo " - (data tree $dr is KEPT; add --wipe-data for a full wipe)"
|
||||
fi
|
||||
echo " - .env is always kept"
|
||||
echo
|
||||
confirm "Tear the stack down?" || die "aborted - nothing was removed"
|
||||
|
||||
log "Stopping and removing containers (all profiles) ..."
|
||||
if [ "$ARG_PURGE_IMAGES" -eq 1 ]; then
|
||||
docker compose "${ALL_PROFILES[@]}" down -v --remove-orphans --rmi all 2>&1 | tail -3 || true
|
||||
else
|
||||
docker compose "${ALL_PROFILES[@]}" down -v --remove-orphans 2>&1 | tail -3 || true
|
||||
fi
|
||||
docker volume rm obmp_data-volume obmp_ts-volume 2>/dev/null || true
|
||||
ok "containers, networks, volumes removed"
|
||||
|
||||
rm -f gobgp/gobgpd.conf gobgp-evpn/gobgpd.conf 2>/dev/null || true
|
||||
ok "rendered configs removed"
|
||||
|
||||
if [ "$ARG_WIPE_DATA" -eq 1 ] || { [ "$ARG_YES" -eq 0 ] && confirm "ALSO wipe the data tree $dr (Postgres history, Kafka spool)?"; }; then
|
||||
if [ -d "$dr" ]; then
|
||||
if grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null; then :; else
|
||||
warn "Native host data wipe - this destroys all BMP history under $dr."
|
||||
[ "$ARG_YES" -eq 1 ] && [ "$ARG_WIPE_DATA" -eq 0 ] && die "refusing implicit data wipe under --yes; pass --wipe-data explicitly"
|
||||
if [ "$ARG_YES" -eq 0 ]; then
|
||||
read -r -p "Type the data root path to confirm deletion: " __c
|
||||
[ "$__c" = "$dr" ] || die "confirmation did not match - data tree untouched"
|
||||
fi
|
||||
fi
|
||||
if [ "$ARG_PURGE_BACKUPS" -eq 1 ]; then
|
||||
sudo rm -rf "${dr:?}"/* 2>/dev/null || true
|
||||
ok "data tree wiped (including backups)"
|
||||
else
|
||||
sudo find "$dr" -mindepth 1 -maxdepth 1 ! -name backups -exec rm -rf {} + 2>/dev/null || true
|
||||
ok "data tree wiped (backups/ preserved)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
hr
|
||||
log "Linux-side teardown complete. Windows-side leftovers (if this was a"
|
||||
log "WSL deployment) need an ELEVATED PowerShell:"
|
||||
echo
|
||||
echo " powershell -ExecutionPolicy Bypass -File scripts\\wsl-portproxy.ps1 -Remove"
|
||||
echo
|
||||
log "Verify clean: docker ps -a | grep obmp (expect nothing)"
|
||||
hr
|
||||
exit 0
|
||||
}
|
||||
[ "$COMMAND" = "teardown" ] && cmd_teardown
|
||||
|
||||
banner "OpenBMP stack deploy"
|
||||
|
||||
# --- .env bootstrap ----------------------------------------------------------
|
||||
if [ ! -f .env ]; then
|
||||
[ -f .env.example ] || die "no .env or .env.example present"
|
||||
cp .env.example .env
|
||||
log "Created .env from .env.example"
|
||||
fi
|
||||
get_env() { grep -E "^$1=" .env | head -1 | cut -d= -f2- || true; }
|
||||
set_env() {
|
||||
local key="$1" val="$2"
|
||||
if grep -qE "^${key}=" .env; then
|
||||
sed -i "s|^${key}=.*|${key}=${val}|" .env
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$val" >> .env
|
||||
|
||||
# Prime sudo early if filesystem setup will need it, so the password prompt
|
||||
# happens HERE (visible, at the start) instead of blocking mid-provision.
|
||||
_dr_probe="$(get_env OBMP_DATA_ROOT)"; _dr_probe="${_dr_probe:-/var/openbmp}"
|
||||
if [ ! -w "$(dirname "$_dr_probe")" ] || { [ -d "$_dr_probe" ] && [ ! -w "$_dr_probe" ]; }; then
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
log "Filesystem setup under $_dr_probe needs sudo - authenticating now."
|
||||
sudo -v || die "sudo authentication failed"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 1. host type: auto-detect, then override -------------------------------
|
||||
step 1 6 "Host type"
|
||||
detected="prod"
|
||||
if grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null; then detected="wsl"; fi
|
||||
if [ -n "$ARG_HOSTTYPE" ]; then
|
||||
@ -309,6 +443,8 @@ if [ -n "$ARG_HOSTTYPE" ]; then
|
||||
log "Host type: $HOSTTYPE (from flag; auto-detect said '$detected')"
|
||||
else
|
||||
log "Auto-detected host type: $detected"
|
||||
echo " wsl = this distro runs under WSL2 (routers reach the stack via the Windows portproxy)"
|
||||
echo " prod = native Linux host (routers reach the stack directly)"
|
||||
ask HOSTTYPE "Host type (wsl/prod)" "$detected"
|
||||
fi
|
||||
case "$HOSTTYPE" in wsl|prod) ;; *) die "host type must be 'wsl' or 'prod' (got '$HOSTTYPE')";; esac
|
||||
@ -355,6 +491,7 @@ normalize_type() {
|
||||
*) echo "" ;;
|
||||
esac
|
||||
}
|
||||
step 2 6 "Deployment type"
|
||||
if [ -n "$ARG_SCOPE" ]; then
|
||||
DTYPE="$(normalize_type "$ARG_SCOPE")"
|
||||
[ -n "$DTYPE" ] || die "unknown --scope '$ARG_SCOPE' (use full-stack|remote|central-store)"
|
||||
@ -371,6 +508,12 @@ log "Deployment type: $DTYPE"
|
||||
# --- 3. HOST_IP: smart default, editable, validated -------------------------
|
||||
# HOST_IP is the address the INTERNAL stack advertises/binds (Kafka listener,
|
||||
# gobgp->collector). On a remote collector it is also this node's own address.
|
||||
step 3 6 "Addresses (internal bind + what routers target)"
|
||||
echo " Two different addresses are about to be asked for:"
|
||||
echo " HOST_IP = where the stack binds INTERNALLY (Kafka, gobgp). On WSL"
|
||||
echo " this is the WSL VM address."
|
||||
echo " Router-facing = what routers put in 'bmp server host ...'. On WSL this"
|
||||
echo " is the WINDOWS LAN IP (portproxy forwards it inward)."
|
||||
primary_ip="$(ip -o -4 addr show scope global 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -1 || true)"
|
||||
wsl_ip="$(hostname -I 2>/dev/null | awk '{print $1}' || true)"
|
||||
current_ip="$(get_env HOST_IP)"
|
||||
@ -461,6 +604,13 @@ BMP_STD_PORT=1790
|
||||
default_router_port="${ARG_ROUTER_PORT:-$BMP_STD_PORT}"
|
||||
if [ -n "$ARG_ROUTER_IP" ]; then ROUTER_IP="$ARG_ROUTER_IP"; else
|
||||
ask ROUTER_IP "Router-facing IP (what 'bmp server' on the routers targets)" "$default_router_ip"
|
||||
# A failed Windows-LAN-IP autodetect leaves a <WINDOWS_LAN_IP> placeholder
|
||||
# as the default; don't let a non-address sail into .env silently.
|
||||
while ! is_ipv4 "$ROUTER_IP"; do
|
||||
[ "$ARG_YES" -eq 1 ] && die "router-facing IP '$ROUTER_IP' is not an IPv4 address (autodetect failed?) - pass --router-ip"
|
||||
warn "'$ROUTER_IP' is not an IPv4 address."
|
||||
ask ROUTER_IP "Router-facing IP (dotted quad)" ""
|
||||
done
|
||||
fi
|
||||
if [ -n "$ARG_ROUTER_PORT" ]; then ROUTER_PORT="$ARG_ROUTER_PORT"; else
|
||||
ask ROUTER_PORT "Router-facing BMP port" "$default_router_port"
|
||||
@ -480,6 +630,7 @@ if [ "$DTYPE" = "remote" ]; then
|
||||
fi
|
||||
|
||||
# --- 6. Authelia toggle (independent axis; N/A for remote - no local UI) -----
|
||||
step 4 6 "Grafana authentication"
|
||||
AUTH_MODE="local"
|
||||
OBMP_DOMAIN="$(get_env OBMP_DOMAIN)"
|
||||
OBMP_COOKIE_DOMAIN="$(get_env OBMP_COOKIE_DOMAIN)"
|
||||
@ -526,6 +677,7 @@ type_resources() {
|
||||
central-store) echo "~16 vCPU / 48-64 GB / NVMe >=250 GB (carries all remotes' data)" ;;
|
||||
esac
|
||||
}
|
||||
step 5 6 "Plan review"
|
||||
echo; hr; log "Deployment plan"; hr
|
||||
# Record what is being deployed - a greenfield deploy is only reproducible if
|
||||
# the checkout is pinned (branch + commit go in the plan and the terminal log).
|
||||
@ -568,9 +720,11 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! confirm "Proceed with this plan?"; then
|
||||
die "aborted before making changes - nothing was modified"
|
||||
# NOTE: default answer is No -- hitting Enter here ABORTS (safe default).
|
||||
if ! confirm "Proceed with this plan? (y = deploy, Enter/n = abort)"; then
|
||||
die "aborted before making changes - nothing was modified (answer 'y' to deploy)"
|
||||
fi
|
||||
step 6 6 "Provision + staged bring-up"
|
||||
|
||||
# --- 8. write .env ----------------------------------------------------------
|
||||
set_env HOST_IP "$HOST_IP"
|
||||
@ -598,10 +752,13 @@ if [ "$ARG_RESET" -eq 1 ]; then
|
||||
else
|
||||
warn "Resetting data tree under $OBMP_DATA_ROOT (WSL test host)"
|
||||
fi
|
||||
docker compose --profile test --profile auth down -v 2>/dev/null || true
|
||||
docker compose "${ALL_PROFILES[@]}" down -v --remove-orphans 2>/dev/null || true
|
||||
docker volume rm obmp_data-volume obmp_ts-volume 2>/dev/null || true
|
||||
sudo rm -rf "${OBMP_DATA_ROOT:?}/"* 2>/dev/null || true
|
||||
log "Reset complete"
|
||||
# Wipe the tree but keep backups/ -- pg-backup.sh dumps live there and a
|
||||
# reset should not silently destroy them (use 'teardown --purge-backups'
|
||||
# for that).
|
||||
sudo find "${OBMP_DATA_ROOT:?}" -mindepth 1 -maxdepth 1 ! -name backups -exec rm -rf {} + 2>/dev/null || true
|
||||
log "Reset complete (backups/ preserved if present)"
|
||||
fi
|
||||
|
||||
# --- 10. run setup.sh -------------------------------------------------------
|
||||
@ -642,7 +799,7 @@ wait_kafka() {
|
||||
done
|
||||
[ "$(docker inspect obmp-kafka --format '{{.State.Status}}' 2>/dev/null)" = running ] \
|
||||
|| die "kafka did not stabilise - check: docker logs obmp-kafka"
|
||||
log " kafka up"
|
||||
ok "kafka up"
|
||||
}
|
||||
wait_postgres() {
|
||||
log " waiting for postgres ..."
|
||||
@ -658,7 +815,7 @@ if [ "$DTYPE" = "remote" ]; then
|
||||
wait_kafka
|
||||
log "Stage 2/2 - collector (forwarding to $CENTRAL_KAFKA) ..."
|
||||
docker compose up -d collector
|
||||
log " collector up"
|
||||
ok "collector up"
|
||||
|
||||
elif [ "$DTYPE" = "central-store" ]; then
|
||||
# Store only: Postgres/psql-app/Grafana/feeders, NO local collector.
|
||||
@ -668,12 +825,12 @@ elif [ "$DTYPE" = "central-store" ]; then
|
||||
docker compose up -d psql
|
||||
wait_postgres
|
||||
docker compose up -d psql-app grafana whois
|
||||
log " store up"
|
||||
ok "store up"
|
||||
log "Stage 3/3 - feeders/consumers (--profile test) ..."
|
||||
docker compose --profile test up -d
|
||||
# ensure no local collector is running on a central-store node
|
||||
docker compose stop collector 2>/dev/null || true
|
||||
log " feeders up (no local collector)"
|
||||
ok "feeders up (no local collector)"
|
||||
|
||||
else
|
||||
# full-stack: collector + store + feeders on one host.
|
||||
@ -686,10 +843,10 @@ else
|
||||
docker compose up -d psql
|
||||
wait_postgres
|
||||
docker compose up -d collector psql-app grafana whois
|
||||
log " core up"
|
||||
ok "core up"
|
||||
log "Stage 3/3 - feeders${AUTH_MODE:+ + auth if authelia} (${profiles[*]}) ..."
|
||||
docker compose "${profiles[@]}" up -d
|
||||
log " feeders up"
|
||||
ok "feeders up"
|
||||
fi
|
||||
|
||||
# --- 12. verify -------------------------------------------------------------
|
||||
@ -701,6 +858,13 @@ docker logs obmp-collector --tail 8 2>&1 | sed 's/^/ /' || true
|
||||
# --- 13. post-deploy notes --------------------------------------------------
|
||||
echo
|
||||
printf '\033[1;32m[deploy] done\033[0m\n'
|
||||
hr
|
||||
log "Verify (any time):"
|
||||
echo " docker compose ps # every service Up / healthy"
|
||||
echo " docker exec -i obmp-psql psql -U openbmp -d openbmp -c 'SELECT name, state FROM routers;'"
|
||||
echo " (DB schema is created automatically by psql-app on its first run)"
|
||||
log "Tear down later: ./deploy.sh teardown (add --wipe-data for a full wipe)"
|
||||
hr
|
||||
if [ "$DTYPE" = "remote" ]; then
|
||||
cat <<EOF
|
||||
Remote collector active. BMP ingest -> $CENTRAL_KAFKA (central store).
|
||||
|
||||
@ -20,14 +20,19 @@
|
||||
.PARAMETER WslIp
|
||||
WSL address to forward to. Default: auto-detected via 'wsl hostname -I'.
|
||||
|
||||
.PARAMETER Remove
|
||||
Teardown mode: delete the portproxy + firewall rules this script creates
|
||||
(pair with './deploy.sh teardown' on the Linux side).
|
||||
|
||||
.EXAMPLE
|
||||
powershell -ExecutionPolicy Bypass -File scripts\wsl-portproxy.ps1
|
||||
powershell -ExecutionPolicy Bypass -File scripts\wsl-portproxy.ps1 -RouterPort 5000
|
||||
powershell -ExecutionPolicy Bypass -File scripts\wsl-portproxy.ps1 -Remove
|
||||
#>
|
||||
param(
|
||||
[int]$RouterPort = 1790,
|
||||
[int]$KafkaPort = 9092,
|
||||
[string]$WslIp = ""
|
||||
[string]$WslIp = "",
|
||||
[switch]$Remove
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
@ -39,6 +44,24 @@ if (-not (New-Object System.Security.Principal.WindowsPrincipal($id)).IsInRole(
|
||||
exit 1
|
||||
}
|
||||
|
||||
# -Remove: teardown mode. Deletes the portproxy + firewall rules this script
|
||||
# creates (used by './deploy.sh teardown' guidance). No WSL IP needed.
|
||||
if ($Remove) {
|
||||
foreach ($listen in @($RouterPort, $KafkaPort)) {
|
||||
netsh interface portproxy delete v4tov4 listenport=$listen listenaddress=0.0.0.0 2>$null | Out-Null
|
||||
Write-Host "portproxy rule removed: 0.0.0.0:$listen"
|
||||
$ruleName = "OpenBMP $listen"
|
||||
if (Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue) {
|
||||
Remove-NetFirewallRule -DisplayName $ruleName
|
||||
Write-Host "firewall rule removed: $ruleName"
|
||||
}
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Remaining portproxy rules:"
|
||||
netsh interface portproxy show v4tov4
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (-not $WslIp) {
|
||||
$WslIp = (wsl hostname -I).Trim().Split(" ")[0]
|
||||
if (-not $WslIp) { Write-Error "Could not auto-detect the WSL IP; pass -WslIp."; exit 1 }
|
||||
|
||||
18
setup.sh
18
setup.sh
@ -27,20 +27,10 @@ if [ ! -f .env ]; then
|
||||
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
|
||||
}
|
||||
# Shared helpers (log ok warn die hr get_env set_env ...) — same styling as
|
||||
# deploy.sh, defined once in scripts/deploy-lib.sh.
|
||||
TAG=setup
|
||||
. "$(dirname "$0")/scripts/deploy-lib.sh"
|
||||
|
||||
OBMP_DATA_ROOT="$(get_env OBMP_DATA_ROOT)"
|
||||
OBMP_DATA_ROOT="${OBMP_DATA_ROOT:-/var/openbmp}"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user