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.
136 lines
4.6 KiB
Go
136 lines
4.6 KiB
Go
// Copyright (c) 2026, Pim van Pelt <pim@ipng.ch>
|
|
|
|
package main
|
|
|
|
import "encoding/json"
|
|
|
|
// StateSnapshot is the full JSON snapshot served for a single maglevd.
|
|
type StateSnapshot struct {
|
|
Maglevd MaglevdInfo `json:"maglevd"`
|
|
Frontends []*FrontendSnapshot `json:"frontends"`
|
|
Backends []*BackendSnapshot `json:"backends"`
|
|
HealthChecks []*HealthCheckSnapshot `json:"healthchecks"`
|
|
VPPInfo *VPPInfoSnapshot `json:"vpp_info,omitempty"`
|
|
// VPPState is "connected", "disconnected", or "" (unknown). Updated
|
|
// from vpp-connect / vpp-disconnect / vpp-api-{send,recv} log
|
|
// events and re-seeded on every refreshAll tick.
|
|
VPPState string `json:"vpp_state,omitempty"`
|
|
}
|
|
|
|
// MaglevdInfo is the per-maglevd connection status record.
|
|
type MaglevdInfo struct {
|
|
Name string `json:"name"`
|
|
Address string `json:"address"`
|
|
Connected bool `json:"connected"`
|
|
LastError string `json:"last_error,omitempty"`
|
|
}
|
|
|
|
// VersionInfo is the build metadata of this maglevd-frontend binary
|
|
// plus runtime capability flags the SPA needs to know at mount time.
|
|
type VersionInfo struct {
|
|
Version string `json:"version"`
|
|
Commit string `json:"commit"`
|
|
Date string `json:"date"`
|
|
AdminEnabled bool `json:"admin_enabled"`
|
|
}
|
|
|
|
type FrontendSnapshot struct {
|
|
Name string `json:"name"`
|
|
Address string `json:"address"`
|
|
Protocol string `json:"protocol"`
|
|
Port uint32 `json:"port"`
|
|
Description string `json:"description,omitempty"`
|
|
SrcIPSticky bool `json:"src_ip_sticky"`
|
|
Pools []*PoolSnapshot `json:"pools"`
|
|
// State is the aggregated frontend state ("up" | "down" | "unknown")
|
|
// populated from FrontendEvent messages, including the synthetic
|
|
// from==to replay that maglevd sends on WatchEvents subscribe.
|
|
State string `json:"state,omitempty"`
|
|
}
|
|
|
|
type PoolSnapshot struct {
|
|
Name string `json:"name"`
|
|
Backends []*PoolBackendSnapshot `json:"backends"`
|
|
}
|
|
|
|
type PoolBackendSnapshot struct {
|
|
Name string `json:"name"`
|
|
Weight int32 `json:"weight"`
|
|
EffectiveWeight int32 `json:"effective_weight"`
|
|
}
|
|
|
|
type BackendSnapshot struct {
|
|
Name string `json:"name"`
|
|
Address string `json:"address"`
|
|
State string `json:"state"`
|
|
Enabled bool `json:"enabled"`
|
|
HealthCheck string `json:"healthcheck"`
|
|
LastTransition *TransitionRecord `json:"last_transition,omitempty"`
|
|
Transitions []*TransitionRecord `json:"transitions,omitempty"`
|
|
}
|
|
|
|
type TransitionRecord struct {
|
|
From string `json:"from"`
|
|
To string `json:"to"`
|
|
AtUnixNs int64 `json:"at_unix_ns"`
|
|
}
|
|
|
|
type HealthCheckSnapshot struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Port uint32 `json:"port"`
|
|
IntervalNs int64 `json:"interval_ns"`
|
|
FastIntervalNs int64 `json:"fast_interval_ns"`
|
|
DownIntervalNs int64 `json:"down_interval_ns"`
|
|
TimeoutNs int64 `json:"timeout_ns"`
|
|
Rise int32 `json:"rise"`
|
|
Fall int32 `json:"fall"`
|
|
}
|
|
|
|
type VPPInfoSnapshot struct {
|
|
Version string `json:"version"`
|
|
BuildDate string `json:"build_date"`
|
|
PID uint32 `json:"pid"`
|
|
BoottimeNs int64 `json:"boottime_ns"`
|
|
ConnecttimeNs int64 `json:"connecttime_ns"`
|
|
}
|
|
|
|
// BrowserEvent is the wire shape sent over SSE to the browser.
|
|
type BrowserEvent struct {
|
|
Maglevd string `json:"maglevd"`
|
|
Type string `json:"type"` // log|backend|frontend|maglevd-status|resync
|
|
AtUnixNs int64 `json:"at_unix_ns"`
|
|
Payload json.RawMessage `json:"payload"`
|
|
}
|
|
|
|
// BackendEventPayload is what we ship inside BrowserEvent.Payload for
|
|
// type == "backend".
|
|
type BackendEventPayload struct {
|
|
Backend string `json:"backend"`
|
|
Transition TransitionRecord `json:"transition"`
|
|
}
|
|
|
|
type FrontendEventPayload struct {
|
|
Frontend string `json:"frontend"`
|
|
Transition TransitionRecord `json:"transition"`
|
|
}
|
|
|
|
type LogEventPayload struct {
|
|
Level string `json:"level"`
|
|
Msg string `json:"msg"`
|
|
Attrs map[string]string `json:"attrs,omitempty"`
|
|
}
|
|
|
|
type MaglevdStatusPayload struct {
|
|
Connected bool `json:"connected"`
|
|
LastError string `json:"last_error,omitempty"`
|
|
}
|
|
|
|
// VPPStatusPayload rides on a "vpp-status" BrowserEvent and tells the
|
|
// SPA when the maglevd↔VPP connection flips. Emitted by the frontend's
|
|
// log-event handler on vpp-connect / vpp-disconnect, and on the first
|
|
// sighting of vpp-api-send/recv (which implies VPP is up).
|
|
type VPPStatusPayload struct {
|
|
State string `json:"state"` // "connected" | "disconnected"
|
|
}
|