Files
nmon/internal/api/retire.go
jleung bf6dbd4923 Add device management UI: add, edit, rediscover, retire
The UI had no way to add a device. Adds an admin-only Add device dialog
(IPv6/IPv4 addresses, SNMP v1/v2c/v3, synchronous discovery, reattach 409
flow) and a device-page Actions menu (Edit with parents and SNMP
replacement, Rediscover now, Retire). Purge now requires typing the name.

API: POST /api/v1/devices/{slug}/retire (admin, audited, 409 if already
retired). OpenAPI change is additive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx9FNLG2CqeBbVGGd9bFsP
2026-10-23 03:36:10 +00:00

42 lines
1.3 KiB
Go

package api
import (
"context"
"net/http"
"github.com/danielgtaylor/huma/v2"
)
func (s *server) registerRetire(api huma.API) {
huma.Register(api, huma.Operation{
OperationID: "retire-device", Method: http.MethodPost, Path: "/api/v1/devices/{slug}/retire", Tags: []string{"devices"},
Summary: "Retire a device",
Description: "Admin only. Soft-deletes the device and its interfaces: polling stops, history is kept, and adding the " +
"same address again offers to restore it. Retiring a retired device is a 409.",
Errors: []int{http.StatusNotFound, http.StatusConflict},
}, s.retireDevice)
}
func (s *server) retireDevice(ctx context.Context, in *struct {
Slug string `path:"slug" doc:"Device slug."`
}) (*deviceOut, error) {
d, err := s.Store.GetDeviceBySlug(ctx, in.Slug)
if err != nil {
return nil, s.storeErr(err)
}
if d.PurgedAt != nil {
return nil, huma.Error404NotFound("not found")
}
if d.RetiredAt != nil {
return nil, huma.Error409Conflict("device is already retired")
}
if err := s.Store.RetireDevice(ctx, d.ID); err != nil {
return nil, s.storeErr(err)
}
if err := s.Store.AppendAudit(ctx, actorOf(ctx), "device.retire", d.Slug, nil, map[string]any{"name": d.Name}); err != nil {
s.Logger.Warn("audit device.retire", "err", err)
}
s.inventoryChanged(ctx)
return s.view(ctx, d.Slug)
}