Files
nmon/internal/rollup/devices.go
Vibe Coder f31fb3712a
Some checks failed
ci / lint (push) Successful in 4m19s
ci / openapi (push) Successful in 29s
ci / postgres (push) Successful in 4m55s
ci / test (push) Failing after 19m48s
Add settings forms, first-install wizard, webhook presets, help and poll tools
Make nmon easier to install and run without editing YAML by hand:

- Settings: point-and-click forms over config.yaml (GET/PUT
  /api/v1/settings/form); the YAML editor moves to /settings/yaml.
- First install: with no sign-in configured nmon starts in install
  mode, serves only the setup wizard (sign-in, basics, devices,
  alerting) and closes it for good once sign-in is saved. A
  self-signed certificate is generated when no TLS source is given.
  poller.interval becomes a config setting.
- Reverse proxies: opt-in --http-listen plain-HTTP listener beside
  HTTPS; sign-in stays required.
- Webhooks: Generic, Teams Adaptive Card, Slack and Discord presets,
  template preview and test send.
- Help: the operations, coverage and profile docs served at /help.
- Polling: per-device "Poll now", a dry-run test poll returning an
  SNMP trace, and time-limited in-memory SNMP debug recording, in the
  UI and as `nmon device poll`.
- Ansible: deploys into install mode when no sign-in is set, and no
  longer overwrites the config.yaml the wizard wrote.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TuKgyKve2XLFtrrXWMi2w
2026-10-25 06:31:12 +00:00

52 lines
1.8 KiB
Go

package rollup
import (
"context"
"fmt"
"time"
"github.com/v10networks/nmon/internal/store"
)
// deviceTarget is one device and the interfaces worth rolling up.
type deviceTarget struct {
slug string
every time.Duration // the device's effective SNMP poll interval
ifaces map[string]store.Interface // by interface ID
}
// devices lists the unretired devices with their rollup-eligible interfaces.
//
// Excluded interfaces (operator said ignore) and unreliable ones (32-bit
// counters that wrap more than once between polls; spec: excluded from p95
// and group sums) are not rolled up at all. Rolling them up would put a
// number in the long store that every consumer must then remember to ignore,
// and nothing graphed from a wrapping counter is trustworthy (build-detail,
// "Must not"). Series written before an interface was flagged stay until
// they age out; consumers filter on the inventory flag.
func (j *Job) devices(ctx context.Context) ([]deviceTarget, error) {
var out []deviceTarget
for off := int64(0); ; off += store.MaxLimit {
page, total, err := j.o.Inventory.ListDevices(ctx, store.DeviceFilter{}, store.Page{Offset: off, Limit: store.MaxLimit})
if err != nil {
return nil, fmt.Errorf("rollup: list devices: %w", err)
}
for _, d := range page {
ifs, err := j.o.Inventory.ListInterfaces(ctx, d.ID, false)
if err != nil {
return nil, fmt.Errorf("rollup: list interfaces of %s: %w", d.Slug, err)
}
t := deviceTarget{slug: d.Slug, every: d.PollInterval(j.o.Cadence.Or(j.o.PollInterval)), ifaces: map[string]store.Interface{}}
for _, i := range ifs {
if !i.Excluded && !i.Unreliable {
t.ifaces[i.ID] = i
}
}
out = append(out, t)
}
if len(page) == 0 || off+int64(len(page)) >= total {
return out, nil
}
}
}