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
52 lines
1.8 KiB
Go
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
|
|
}
|
|
}
|
|
}
|