Registry and Analytics: run, subnet, direction and protocol filters, successes-by-target chart
Registry (/registry):
- filters by run (slice by the address's cycle in that run), subnet
(drop-down of configured subnets), direction (egress/ingress) and
protocol (icmp, tcp, ssh, https, tls); status in scope is computed over
the narrowed checks
- chart "successful checks per target (egress) / site (ingress)" when both
direction and protocol are chosen; a row opens the list of addresses
(dialog, CSV)
- API: direction/protocol parameters and run in GET /admin/registry,
GET /admin/registry/breakdown and /breakdown/list
- subnet filter passes ids as one JSON parameter (SQLite variable limit)
Analytics (/analytics):
- subnet filter recomputes the whole page over the addresses of the run
inside the subnet; only their checks are read; cache per run and subnet
- direction and protocol focus the page; with both set the registry chart
is shown
- subnet parameter in GET /admin/analytics/runs/{id} and lists (JSON, CSV)
Docs: plans and summaries in docs/changes, README, API, USAGE.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
068c10ea1c
commit
ded196ec8d
40 files changed
+2545
-188
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -632,6 +633,53 @@ func TestRegistryPageAndDetail(t *testing.T) {
|
||||
if !strings.Contains(notFound, "alert-warning") {
|
||||
t.Fatalf("expected client error banner for unknown registry address, got:\n%s", notFound)
|
||||
}
|
||||
|
||||
// The four filters: the run and subnet choices come from control-api, the
|
||||
// values reach it and the pager, unknown direction/protocol are dropped, and
|
||||
// with a direction/protocol only the levels that have checks are shown.
|
||||
fake.runs = []analyticsRun{fakeRun(2, "open", 120, 40), fakeRun(1, "finalized", 900, 300)}
|
||||
fake.subnets = subnetList{Subnets: []subnetEntry{{CIDR: "9.9.9.0/24", Label: "Офис"}}}
|
||||
fake.registry["9.9.9.8"] = registryItem{
|
||||
IPAddress: "9.9.9.8", FirstSeenAt: now, LastSeenAt: now, TotalCycles: 1, LastResult: "pass",
|
||||
LastCycleID: 1, Ingress: levelResult{Total: 1, OK: 1, ByType: []typeStat{{"tls", 1, 1}}},
|
||||
}
|
||||
for i := 0; i < 30; i++ { // a second page for the pager
|
||||
ip := fmt.Sprintf("9.9.9.%d", 100+i)
|
||||
fake.registry[ip] = registryItem{IPAddress: ip, FirstSeenAt: now, LastSeenAt: now, TotalCycles: 1, LastResult: "pass",
|
||||
LastCycleID: 1, Ingress: levelResult{Total: 1, OK: 1, ByType: []typeStat{{"tls", 1, 1}}}}
|
||||
}
|
||||
page = get(t, ts, "/registry?run=1&subnet=9.9.9.0/24&direction=ingress&protocol=tls&per_page=25")
|
||||
fake.mu.Lock()
|
||||
last := fake.registryQueries[len(fake.registryQueries)-1]
|
||||
fake.mu.Unlock()
|
||||
for _, want := range []string{"run=1", "subnet=9.9.9.0%2F24", "direction=ingress", "protocol=tls"} {
|
||||
if !strings.Contains(last, want) {
|
||||
t.Fatalf("control-api request %q lacks %s", last, want)
|
||||
}
|
||||
}
|
||||
for _, want := range []string{
|
||||
`<option value="1" selected>`, `<option value="2" >`, `<option value="9.9.9.0/24" selected>9.9.9.0/24 — Офис</option>`,
|
||||
`value="ingress" selected`, `value="tls" selected`, "Результат в запуске 1", `level-name">Ingress`,
|
||||
} {
|
||||
if !strings.Contains(page, want) {
|
||||
t.Fatalf("expected %q in the filtered registry page, got:\n%s", want, page)
|
||||
}
|
||||
}
|
||||
if strings.Contains(page, `level-name">Egress`) {
|
||||
t.Fatalf("the Egress level must be hidden when only ingress checks are selected, got:\n%s", page)
|
||||
}
|
||||
next := pagerLink(t, page, "next")
|
||||
if next == nil || next.Query().Get("run") != "1" || next.Query().Get("subnet") != "9.9.9.0/24" ||
|
||||
next.Query().Get("direction") != "ingress" || next.Query().Get("protocol") != "tls" {
|
||||
t.Fatalf("pager link lost the filters: %v", next)
|
||||
}
|
||||
get(t, ts, "/registry?direction=sideways&protocol=udp")
|
||||
fake.mu.Lock()
|
||||
last = fake.registryQueries[len(fake.registryQueries)-1]
|
||||
fake.mu.Unlock()
|
||||
if strings.Contains(last, "direction=") || strings.Contains(last, "protocol=") {
|
||||
t.Fatalf("unknown direction/protocol must be dropped: %q", last)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRegistryPageShowsEgressIngressLevels proves the list shows, under the
|
||||
|
||||
Reference in new issue
Block a user