Parameterize HOST_IP everywhere -- portable to another lab host
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>
This commit is contained in:
parent
2a82bd9a94
commit
2634aada24
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
gobgp/gobgpd.conf
|
||||
gobgp-evpn/gobgpd.conf
|
||||
|
||||
@ -33,14 +33,32 @@ policy from the cores. To stop the feed instantly without touching router
|
||||
config, `docker compose stop gobgp` -- the eBGP sessions drop and the full
|
||||
table is withdrawn fleet-wide within seconds. See gobgp/README.md.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import paramiko
|
||||
|
||||
|
||||
def _env_default(key, default, dotenv=".env"):
|
||||
"""Resolve a value from os.environ or the repo-root .env, else default."""
|
||||
v = os.environ.get(key)
|
||||
if v:
|
||||
return v
|
||||
try:
|
||||
with open(dotenv) as fh:
|
||||
for line in fh:
|
||||
s = line.strip()
|
||||
if s and not s.startswith("#") and s.startswith(f"{key}="):
|
||||
return s.split("=", 1)[1].strip().strip('"').strip("'")
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return default
|
||||
|
||||
|
||||
# GoBGP runs network_mode: host, so it sources BGP TCP from the host's real
|
||||
# interface IP (10.40.40.202) -- NOT its router-id 10.40.40.250. The cores
|
||||
# must peer with the host IP.
|
||||
GOBGP_IP = "10.40.40.202"
|
||||
# interface IP -- NOT its router-id. The cores must peer with the host IP.
|
||||
# Resolved from $HOST_IP or the HOST_IP= line in repo-root .env.
|
||||
GOBGP_IP = _env_default("HOST_IP", "10.40.40.202")
|
||||
GOBGP_AS = "65001"
|
||||
|
||||
# Additive config, built per core (asn = that core's local BGP AS:
|
||||
|
||||
@ -18,12 +18,31 @@ Verify afterwards in OpenBMP:
|
||||
-c "SELECT name, ip_address, bgp_id, isconnected FROM routers ORDER BY name;"
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import paramiko
|
||||
|
||||
|
||||
def _env_default(key, default, dotenv=".env"):
|
||||
"""Resolve a value from os.environ or the repo-root .env, else default."""
|
||||
v = os.environ.get(key)
|
||||
if v:
|
||||
return v
|
||||
try:
|
||||
with open(dotenv) as fh:
|
||||
for line in fh:
|
||||
s = line.strip()
|
||||
if s and not s.startswith("#") and s.startswith(f"{key}="):
|
||||
return s.split("=", 1)[1].strip().strip('"').strip("'")
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return default
|
||||
|
||||
|
||||
# --- BMP collector ---------------------------------------------------------
|
||||
COLLECTOR_HOST = "10.40.40.202"
|
||||
# Resolved from $HOST_IP or the HOST_IP= line in repo-root .env.
|
||||
COLLECTOR_HOST = _env_default("HOST_IP", "10.40.40.202")
|
||||
COLLECTOR_PORT = "5000"
|
||||
|
||||
# `bmp server 1` block — flat formal form, identical to the ESXi lab.
|
||||
|
||||
@ -476,12 +476,16 @@ services:
|
||||
# Host networking: the daemon uses the host's real IPv4 + IPv6 stack, so
|
||||
# both the v4 and v6 eBGP sessions to AS57355 source from the host's
|
||||
# public addresses (no Docker IPv6/NAT plumbing). BMP still reaches the
|
||||
# collector on 10.40.40.202:5000 (its published port).
|
||||
# collector on $HOST_IP:5000 (its published port).
|
||||
network_mode: host
|
||||
depends_on:
|
||||
- collector
|
||||
# gobgpd reads /config/gobgpd.conf; the same mount carries mrt-refresh.sh
|
||||
# and the cached MRT dumps it downloads.
|
||||
# gobgpd.conf.tmpl (in git, with __HOST_IP__ placeholders) is rendered to
|
||||
# gobgpd.conf (gitignored) by setup.sh using $HOST_IP from .env. The
|
||||
# gobgp image is distroless (no shell), so we cannot render at container
|
||||
# start -- the rendered .conf must exist on the host before `docker
|
||||
# compose up`. The same /config mount also carries mrt-refresh.sh and
|
||||
# cached MRT dumps.
|
||||
volumes:
|
||||
- ./gobgp:/config
|
||||
command: ["gobgpd", "-f", "/config/gobgpd.conf", "-t", "toml"]
|
||||
@ -498,6 +502,8 @@ services:
|
||||
image: jauderho/gobgp:v4.5.0
|
||||
depends_on:
|
||||
- collector
|
||||
# gobgpd.conf is rendered by setup.sh from gobgpd.conf.tmpl. See gobgp/
|
||||
# service notes above.
|
||||
volumes:
|
||||
- ./gobgp-evpn:/config
|
||||
command: ["gobgpd", "-f", "/config/gobgpd.conf", "-t", "toml"]
|
||||
@ -534,7 +540,7 @@ services:
|
||||
depends_on:
|
||||
- psql
|
||||
environment:
|
||||
- PG_DSN=host=10.40.40.202 port=5432 dbname=openbmp user=openbmp password=${POSTGRES_PASSWORD:-openbmp}
|
||||
- PG_DSN=host=${HOST_IP:-10.40.40.202} port=5432 dbname=openbmp user=openbmp password=${POSTGRES_PASSWORD:-openbmp}
|
||||
- POLL_INTERVAL=900
|
||||
- ROUTER_USER=webui
|
||||
- ROUTER_PASS=cisco
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
# --- BMP export to the OpenBMP collector ------------------------------------
|
||||
[[bmp-servers]]
|
||||
[bmp-servers.config]
|
||||
address = "10.40.40.202"
|
||||
address = "__HOST_IP__"
|
||||
port = 5000
|
||||
# local-rib: the injected EVPN routes live in the loc-rib (there are no
|
||||
# BGP peers / no adj-rib-in), so export the local RIB.
|
||||
@ -77,7 +77,7 @@
|
||||
# --- Neighbor: CML CORE-01 (AS65020) ----------------------------------------
|
||||
# GoBGP initiates outbound to the core's mgmt IP (reachable from the docker
|
||||
# host -- the cores already reach the host for BMP). GoBGP sources the session
|
||||
# from the host IP 10.40.40.202. eBGP multihop: the host is several hops from
|
||||
# from the host IP __HOST_IP__. eBGP multihop: the host is several hops from
|
||||
# the core. Default export policy (accept) re-advertises the full Bromirski
|
||||
# table to the core. prefix-limit is a safety cap on what the core can send
|
||||
# back (its lab routes only -- small).
|
||||
@ -164,7 +164,7 @@
|
||||
# routes, pre import-policy) -- consistent with the rest of the OpenBMP fleet.
|
||||
[[bmp-servers]]
|
||||
[bmp-servers.config]
|
||||
address = "10.40.40.202"
|
||||
address = "__HOST_IP__"
|
||||
port = 5000
|
||||
route-monitoring-policy = "pre-policy"
|
||||
statistics-timeout = 3600
|
||||
@ -36,7 +36,8 @@ from ncclient import manager
|
||||
|
||||
PG_DSN = os.environ.get(
|
||||
"PG_DSN",
|
||||
"host=10.40.40.202 port=5432 dbname=openbmp user=openbmp password=openbmp",
|
||||
f"host={os.environ.get('HOST_IP', 'localhost')} port=5432 "
|
||||
"dbname=openbmp user=openbmp password=openbmp",
|
||||
)
|
||||
POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL", "900"))
|
||||
R_USER = os.environ.get("ROUTER_USER", "webui")
|
||||
|
||||
10
setup.sh
10
setup.sh
@ -111,6 +111,16 @@ 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user