SPA (cmd/frontend/web):
- New "lb buckets" column backed by a 1s-debounced GetVPPLBState
fetch loop with leading+trailing edge coalesce.
- Per-frontend health icon (✅/⚠️/❗/‼️/❓) in the Zippy header,
gated by a settling flag that suppresses ‼️ until the next lb-state
reconciliation after a backend transition or weight change.
- In-place leaf merge on lb-state so stable bucket values (e.g. "0")
don't retrigger the Flash animation on every refresh.
- Zippy cards remember open state in a cookie, default closed on
fresh load; fixed-width frontend-title-name + reserved icon slot
so headers line up across all cards.
- Clock-drift watchdog in sse.ts that forces a fresh EventSource on
laptop-wake so the broker emits a resync instead of hanging on a
dead half-open socket.
Frontend service (cmd/frontend):
- maglevClient.lbStateLoop, trigger on backend transitions +
vpp-connect, best-effort fetch on refreshAll.
- Admin handlers explicitly wake the lb-state loop after lifecycle
ops and set-weight (the latter emits no transition event on the
maglevd side, so the WatchEvents path wouldn't have caught it).
- /favicon.ico served from embedded web/public IPng logo.
VPP integration:
- internal/vpp/lbstate.go: dumpASesForVIP drops Pfx from the dump
request (setting it silently wipes IPv4 replies in the LB plugin)
and filters results by prefix on the response side instead, which
also demuxes multi-VIP-on-same-port cases correctly.
maglevc:
- Walk now returns the unconsumed token tail; dispatch and the
question listener reject unknown commands with a targeted error
instead of dumping the full command tree prefixed with garbage.
- On '?', echo the current line (including the '?') before the help
list so the output reads like birdc.
Checker / prober:
- internal/checker: ±10% jitter on NextInterval so probes across
restart don't all fire on the same tick.
- internal/prober: HTTP User-Agent now carries the build version
and project URL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replaced flat `backends: [...]` list on frontends with an ordered `pools:`
list; each pool has a name and a map of backends with per-pool weights (0–100,
default 100). Pools express priority: first pool with a healthy backend wins.
- Removed global backend weight (was on the backend, now lives in the pool).
- Config validation enforces non-empty pools, non-empty pool names, weight
range, and consistent address families across all pools of a frontend.
- Added `PoolBackendInfo { name, weight }` and changed `PoolInfo.backends` from
`repeated string` to `repeated PoolBackendInfo` so weights are visible over
the API.
- Full interactive shell with readline, tab completion, and `?` inline help.
- Command tree parser (Walk) handles fixed keywords and dynamic slot nodes;
prefix matching with exact-match priority.
- Commands: `show version/frontends/frontend/backends/backend/healthchecks/
healthcheck`, `set backend <name> pause|resume`, `quit`/`exit`.
- `show frontend` output is hierarchical (pools → backends) with per-backend
weights and `[disabled]` notation; pool section uses fixed-width formatting
so ANSI color codes don't corrupt tabwriter alignment.
- `-color` flag (default true) wraps static field labels in dark-blue ANSI;
works correctly with tabwriter because all labels carry identical-length
escape sequences.
- `cmd/version.go` package holds `version`, `commit`, `date` vars set at build
time via `-ldflags -X`.
- `make build` / `make build-amd64` / `make build-arm64` all inject
`VERSION=0.1.1`, `COMMIT_HASH` (from `git rev-parse --short HEAD`), and
`DATE` (UTC ISO-8601).
- `maglevc` prints version on interactive startup and exposes `show version`.
- `maglevd` logs version/commit/date at startup; `-version` flag prints and exits.
- `doHTTPProbe` was building a `https://` target URL even though TLS was already
applied to the connection inside `inNetns`. `http.Transport` then wrapped the
connection in a second TLS layer, producing "http: server gave HTTP response
to HTTPS client". Fixed by always using `http://` in the target URL.
- Added `TestHTTPSProbe` using `httptest.NewTLSServer` to cover the full path.
- New `docs/user-guide.md`: maglevd flags/signals, maglevc commands, shell
completion, and command-tree parser walkthrough.
- New `docs/healthchecks.md`: state machine, rise/fall model, probe intervals,
all transition events with log examples.
- Updated `docs/config-guide.md`: pools design, removed global weight from
backends, updated all examples.
- Updated `README.md`: packaging table, build paths, corrected binary locations
(`/usr/sbin/maglevd`), config filename (`.yaml`).
- `debian/` directory contains `control.in`, `maglevd.service`, `default.maglev`,
`maglev.yaml` (example config), `conffiles`, `postinst`, `prerm`.
- `debian/build-deb.sh` stages a package tree and calls `dpkg-deb`; emits
`build/vpp-maglev_<version>~<commit>_<arch>.deb`.
- Cross-compiles for amd64 and arm64 in one `make pkg-deb` invocation.
- `maglevd` installed to `/usr/sbin/`, `maglevc` to `/usr/bin/`.
- Service reads `MAGLEV_CONFIG` from `/etc/default/maglev`
(default: `/etc/maglev/maglev.yaml`).
- Man pages `maglevd(8)` and `maglevc(1)` live in `docs/` and are gzip'd into
the package.
- All build output goes to `build/<arch>/`; `build/` is gitignored.