Files
nmon/internal/api/setup_policies.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

64 lines
2.0 KiB
Go

package api
import (
"context"
"github.com/v10networks/nmon/internal/alertpolicy"
"github.com/v10networks/nmon/internal/store"
)
// recommendedRules is the starter alert set: reachability, port errors and the three resource limits. Interface
// down stays out on purpose (it is opt-in per port or group).
var recommendedRules = []string{"device_down", "device_warning", "interface_errors", "cpu_high", "memory_high", "disk_full"}
// recommendedName is the policy name for a rule.
func recommendedName(rule string) string { return "recommended: " + rule }
func (s *server) setupPolicies(ctx context.Context, _ *struct{ Body SetupPoliciesBody }) (*struct{ Body SetupPolicies }, error) {
a, err := s.setupAdmin()
if err != nil {
return nil, err
}
if !a.InstallMode() {
return nil, s.setupErr(ErrSetupClosed)
}
existing, err := s.Store.ListAlertPolicies(ctx)
if err != nil {
return nil, s.storeErr(err)
}
out := SetupPolicies{Created: []string{}, Existing: []string{}}
for _, rule := range recommendedRules {
name := recommendedName(rule)
if policyExists(existing, name, rule) {
out.Existing = append(out.Existing, name)
continue
}
row, err := s.policyRow(AlertPolicyBody{Name: name, Rule: rule, Action: alertpolicy.ActionAlert,
Scope: alertpolicy.Scope{All: true}}, true)
if err != nil {
return nil, err
}
if err := s.Store.CreateAlertPolicy(ctx, &row); err != nil {
return nil, s.storeErr(err)
}
out.Created = append(out.Created, name)
}
if len(out.Created) > 0 {
s.AlertPolicy.Changed()
if err := s.Store.AppendAudit(ctx, actorOf(ctx), "setup.recommended-policies", "alert-policies", nil, out.Created); err != nil {
s.Logger.Warn("audit setup.recommended-policies", "err", err)
}
}
return &struct{ Body SetupPolicies }{out}, nil
}
// policyExists reports whether a policy has this name or already binds the rule.
func policyExists(all []store.AlertPolicy, name, rule string) bool {
for _, p := range all {
if p.Name == name || p.Rule == rule {
return true
}
}
return false
}