vpp-maglevd ships maglevd, maglevd-frontend, both systemd units, and
the config conffiles. vpp-maglev ships maglevc and maglevt as pure
client tools so jump hosts and workstations can install them without
pulling in the daemon. pkg-deb now emits four .debs per release
(2 packages x 2 archs); build-deb.sh takes a package-name argument
and dispatches accordingly.
Rename the web dashboard binary to maglevd-frontend and move it to
/usr/sbin (it's a daemon and belongs with maglevd). The systemd unit
name stays vpp-maglev-frontend.service since that prefix is the
package name. Manpage, README, user-guide, and debian packaging all
updated in lockstep; bump to 0.9.1 for the first real release.
All frontend env vars are now prefixed MAGLEV_FRONTEND_ so a single
/etc/default/vpp-maglev can be shared with maglevd without collisions.
Every flag has an env equivalent for Docker use. MAGLEV_FRONTEND_USER
and MAGLEV_FRONTEND_PASSWORD still gate the /admin surface.
VPPInfoPanel now pulses "API: ↑↓" indicators in the zippy title
whenever a vpp-api-send / vpp-api-recv log event arrives on the SSE
stream for the scoped maglevd — 250ms blue flash, re-triggerable,
with the two arrows tightly kerned via negative letter-spacing.
Builds on the maglev-frontend component introduced in 284b4cc with
quality-of-life improvements, an authenticated /admin surface, a
live-action control plane, and Debian packaging cleanup.
- Backend state now renders live: maglevd's FrontendEvent synthetic
from==to replay hydrates FrontendSnapshot.State on WatchEvents
subscribe, and live transitions update both the in-process cache
and every connected browser via a new applyFrontendTransition
reducer. Shown as a StatusBadge next to the frontend name.
- VPP connection state surfaces in the VPP zippy title as a
green/red badge. Driven by vpp-connect / vpp-disconnect and by
the steady stream of vpp-api-send/recv debug heartbeats so a
silent VPP drop is caught within one debug-log tick.
- Probe heartbeat dot becomes ❤️ while a probe is in flight and
reverts to · on probe-done. Fixed-size wrapper so the emoji swap
doesn't jiggle the row; both states share the same font-size.
- Flash component replaced its subtle background-only fade with a
scale-pop + yellow halo box-shadow + longer duration so
weight/effective/state changes are unmissable on tiny numeric
cells. Initial mount still skipped via defer so no flash on load.
- Last-transition age is now a live countdown driven by a global
1-second ticker signal (one timer, many subscribers). Two most
significant units: 10m30s / 1h12m / 1d16h. Sub-second ages
render as "now" to absorb clock skew between maglevd and the
browser.
- Event stream is now chronological (oldest at top) with tail-
style auto-scroll, pause/resume, and the toolbar moved below the
list. Row separators removed. Also shown only in /admin (see
below) so /view stays a focused read-only surface.
- Table nowrap so backend names like nginx0-frggh0 and the
"last transition" header don't wrap. Frontends render in the
order returned by ListFrontends instead of Go map iteration
order so reload doesn't shuffle VIP order.
- IPng logo in the header, clickable, links to the git repo.
Header padding reduced so the logo can fill the bar up to the
separator. Version + commit + build date shown in the brand area
(fetched once from /view/api/version).
- "view" / "admin" mode tag moved to sit just left of the admin
toggle button so it reads as a pair.
- Prettier wired in as the web-side fixstyle via a new
fixstyle-web Make target that also runs from `make fixstyle`.
Added .prettierrc.json and .prettierignore; 8 existing files
were normalized in place.
- Fixed a "20555d ago" rendering bug: maglevd's synthetic
backend-replay events (from==to, at_unix_ns=0) were corrupting
the local cache's LastTransition via applyBackendTransition.
Backend synthetic events are now skipped entirely (refreshAll
covers initial hydration for backends), while frontend synthetic
events are still applied because FrontendInfo doesn't carry
state — the event is the only source.
- New MAGLEV_FRONTEND_USER / MAGLEV_FRONTEND_PASSWORD env vars.
When both are set and non-empty, /admin/ becomes a basic-auth-
protected SPA shell backed by the same embedded index.html as
/view/. The SPA detects its base path via a new stores/mode.ts
isAdmin constant and conditionally renders admin-only sections
(currently: the Event Stream / DebugPanel). When disabled,
/admin/ returns 404 (not 501) so operators who didn't configure
it see no teasing affordance, and the SPA's admin-toggle button
is hidden entirely via the admin_enabled flag on
/view/api/version.
- basicAuth uses crypto/subtle.ConstantTimeCompare for both user
and password so timing can't distinguish a wrong username from
a wrong password.
- New POST /admin/api/{maglevd}/backend/{name}/{pause|resume|
enable|disable} endpoint, gated by the same basic-auth
middleware as the SPA shell. maglevClient.BackendAction wraps
the four matching gRPC RPCs and returns a fresh BackendSnapshot;
the same transition lands via WatchEvents so every connected
browser converges through the normal reducer path.
- BackendActionsMenu Solid component: kebab (⋮) button in a new
trailing column rendered only in /admin. Click-outside and
Escape close the popover (document listeners installed only
while open). Actions are state-aware: up/down/unknown → pause,
disable; paused → resume, disable; disabled → enable;
removed → menu suppressed entirely. Busy indicator per action;
errors render inline under the item list.
- Structured audit log: every mutation logs an
admin-backend-action record with maglevd / backend / action /
resulting state.
- Renamed debian/vpp-maglevd.service → debian/vpp-maglev.service
to align naming with the new vpp-maglev-frontend.service
sibling. postinst handles upgrades by stopping + disabling any
lingering vpp-maglevd.service before enabling the renamed unit;
prerm stops both (the frontend unit is installed but not
enabled by default — operators opt in with systemctl enable).
- New debian/vpp-maglev-frontend.service (hardened:
NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp,
no capabilities). Reads the same /etc/default/vpp-maglev
conffile and expands MAGLEV_FRONTEND_ARGS via
`ExecStart=/usr/bin/maglev-frontend $MAGLEV_FRONTEND_ARGS` so
word-splitting works.
- docs/maglev-frontend.8 manpage documenting flags, endpoints,
and SSE reverse-proxy requirements.
- build-deb.sh: drops the commit hash from the .deb filename
(now vpp-maglev_<version>_<arch>.deb) and no longer takes the
commit as a CLI arg. Binaries continue to carry the commit via
-ldflags so `maglevd --version` et al are the authoritative
"which build is running" answer.
gRPC / proto
- Rename WatchBackendEvents → WatchEvents; return a stream of Event
oneof (LogEvent, BackendEvent, FrontendEvent) with optional filter
flags (log, log_level, backend, frontend)
- Add EnableBackend, DisableBackend, SetFrontendPoolBackendWeight RPCs
- Rename PauseResumeRequest → BackendRequest
- Add CheckConfig RPC returning ok/parse_error/semantic_error
maglevd
- Route slog through a LogBroadcaster (slog.Handler) so WatchEvents
subscribers can receive structured log records independently of the
daemon's own --log-level
- Add --reflection flag (default true) to toggle gRPC server reflection
- Add --check flag: validates config file and exits 0/1/2
- SIGHUP: use config.Check before applying reload; log parse vs semantic
error separately; refuse reload on any error
- Rename default config path /etc/maglev → /etc/vpp-maglev
maglevc
- Add 'watch events [num <n>] [log [level <level>]] [backend] [frontend]'
command; prints compact protojson, stops on any keypress or Ctrl-C;
uses cbreak mode (not raw) so output post-processing is preserved
- Add 'set backend <name> enable|disable'
- Add 'set frontend <name> pool <pool> backend <name> weight <0-100>'
- Add 'config check' command
Debian packaging
- Rename service unit to vpp-maglevd.service
- Rename conffiles to /etc/default/vpp-maglev and /etc/vpp-maglev/
- Create maglevd system user/group in postinst; add to vpp group if present
- Add postrm; add adduser to Depends
- 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.