sam d30ec2074a initial commit: two-VM Proxmox portability test for obmp-docker
Terraform (bpg/proxmox) provisions two Ubuntu 24.04 cloud-init VMs on a
Proxmox host, one running obmp-docker's `deploy.sh --scope full-stack`
and the other running GoBGP as a BMP-source stand-in. `scripts/run-test.sh`
runs the six assertions from docs/design.md (containers healthy, BMP
peer up, ip_rib/bgp_peers non-zero, Grafana healthcheck).

Layout:
  terraform/            provider + VM + cloud-init snippet resources
  terraform/cloud-init/ user-data templates (store + bmpgen)
  scripts/              run-test.sh, teardown.sh
  docs/design.md        topology, assertion set, and rationale

Cred handling:
  terraform.tfvars is gitignored; endpoint + api_token can also come
  from PROXMOX_VE_ENDPOINT / PROXMOX_VE_API_TOKEN env vars.

Not validated locally: `terraform init && terraform validate` -- the
terraform binary is not on the authoring host. YAML + shell + HCL brace
balance verified.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-20 18:19:45 -07:00

5.8 KiB

Design: Two-VM Portability Test

Goal

Prove that obmp-docker deploys and ingests on a fresh host with only the inputs a new operator would have (repo URL, a hypervisor, an SSH key). The existing deploy.sh claims portability; this test is what turns the claim into evidence.

Topology

   +------------------------+           BMP TCP :ROUTER_FACING_PORT
   |     store VM (VM-A)    |  <----------------------------------+
   |  ubuntu 24.04 cloud    |                                     |
   |  docker + deploy.sh    |                                     |
   |  full-stack profile    |                                     |
   |                        |                                     |
   |  ROUTER_FACING_IP =    |                                     |
   |    <VM-A ip>           |                                     |
   |  ROUTER_FACING_PORT =  |                          +----------+---------+
   |    1790 (IANA BMP)     |                          |  bmpgen VM (VM-B) |
   |                        |                          |  ubuntu 24.04     |
   +------------------------+                          |  docker           |
                                                       |  gobgp container  |
                                                       |  (BMP client)     |
                                                       +-------------------+

           |                                                     |
           +---- shared L2 (Proxmox bridge) or routed subnet ----+

Two VMs, both stock Ubuntu 24.04 cloud images, both provisioned entirely by cloud-init. No manual step between terraform apply and the assertions running.

Why two VMs, not one

The deploy.sh --scope full-stack --profile test option already spins up GoBGP inside the same compose network as the collector. That proves the compose is internally consistent, but it doesn't exercise the actual router-integration surface (ROUTER_FACING_IP/ROUTER_FACING_PORT, compose's ${ROUTER_FACING_PORT:-1790}:5000 publish, cross-host TCP, management-plane reachability). A second VM is the smallest topology that makes those things real.

If the two-VM test passes, "deploy.sh works AND routers can reach it" holds. If it fails, we know exactly which of the two.

What VM-A runs

Cloud-init on VM-A does:

  1. Install docker.io, docker-compose-plugin, git.
  2. git clone the obmp-docker repo at a pinned branch/commit.
  3. Write a minimal .env from .env.example with:
    • HOST_IP = VM-A's own primary IP
    • ROUTER_FACING_IP = same
    • ROUTER_FACING_PORT = 1790 (test uses IANA port, not the lab transitional 5000)
    • OBMP_AUTH_MODE=local (no reverse proxy in this topology)
  4. Run ./deploy.sh --scope full-stack --auth local --yes.
  5. Write a completion marker to /var/lib/cloud/portability-test.done with exit status so the test harness can poll it.

What VM-B runs

Cloud-init on VM-B does:

  1. Install docker.io.
  2. docker run a GoBGP container with a config file that:
    • Sets local AS to a private test ASN (65099).
    • Establishes a BMP session to <VM-A ip>:1790.
    • Injects a small synthetic route set so ip_rib gets non-zero rows.
  3. Write a completion marker.

GoBGP is minimal on purpose — a real router would test more, but each extra dial-in path (BGP-LS, gNMI, NETCONF) needs a real IOS-XR environment or an emulator like XRd. The minimum route-monitoring path is enough to catch the portability failure modes.

Assertion set (run by scripts/run-test.sh)

Once cloud-init on both VMs is done (poll the completion markers, or 15 min timeout), SSH into VM-A and run:

# Assertion Query / check
1 All obmp containers healthy docker ps --format '{{.Names}} {{.Status}}' grep unhealthy = 0
2 Collector accepted a BMP session from VM-B docker logs obmp-collector contains "peer up" for VM-B's IP
3 routers table has 1 row SELECT count(*) FROM routers = 1
4 bgp_peers has ≥ 1 UP session SELECT count(*) FROM bgp_peers WHERE state='UP' ≥ 1
5 ip_rib has ≥ 1 row (GoBGP injected some routes) SELECT count(*) FROM ip_rib ≥ 1
6 Grafana healthcheck returns 200 curl -sf http://<VM-A>:3000/api/health

Pass = all six green. Failure emits the first failing assertion + a tarball of docker logs, .env, deploy.sh output for diagnosis.

Why bpg/proxmox

Two candidate providers exist for Proxmox: Telmate/proxmox (original, slower moving) and bpg/proxmox (fork, active, modern cloud-init handling). We pick bpg because:

  • Cloud-init user_data_file_id is first-class — we can hand-craft the cloud-init YAML and reference it by snippet ID rather than shoving it through the provider's per-field API.
  • proxmox_virtual_environment_download_file handles the cloud-image download idempotently.
  • The type system + docs are noticeably better on 0.60+.

Why cloud-init and not Ansible

Adding Ansible would double the surface. Cloud-init is enough for "install a few packages, drop a repo, run a script" — anything more complex is a smell that we're testing the wrong thing.

Why a separate repo

Test infra should not gate product commits. If the two-VM test suite grows (multi-vendor router VMs, prod-like tuning tests, longer-running soak variants), it earns its own release cadence. Keeping the code separate keeps that door open.