ui+server: P2-18d pending hosts dashboard panel + expiry sweeper

Dashboard handler loads ListPendingHosts(now); template renders a
warn-bordered panel above the host table with hostname, OS/arch,
fingerprint (selectable / copyable), source IP, age, expiry. Each
row carries an inline accept form (repo URL/user/password) plus a
Reject button. cmd/server adds a 60s ticker calling
DeleteExpiredPendingHosts so 1h-stale rows drop off.
This commit is contained in:
2026-05-04 11:11:32 +01:00
parent a46d906d27
commit 4c81ff3e7b
3 changed files with 75 additions and 6 deletions
+8
View File
@@ -156,6 +156,10 @@ func run() error {
// shouldn't, but the queue exists either way).
pendingDrainTick := time.NewTicker(30 * time.Second)
defer pendingDrainTick.Stop()
// Pending-hosts expiry sweeper: drops announce rows past their 1h
// ceiling so the dashboard panel doesn't accumulate stale entries.
pendingExpiryTick := time.NewTicker(60 * time.Second)
defer pendingExpiryTick.Stop()
mt := maintenance.New(st)
go func() {
for {
@@ -176,6 +180,10 @@ func run() error {
}
case <-pendingDrainTick.C:
srv.DrainAllDue(ctx)
case <-pendingExpiryTick.C:
if n, err := st.DeleteExpiredPendingHosts(ctx, time.Now().UTC()); err == nil && n > 0 {
slog.Info("expired pending hosts swept", "n", n)
}
case <-maintenanceTick.C:
decisions, err := mt.Decide(ctx, time.Now().UTC())
if err != nil {