Dashboard: Processes module (top by CPU/memory, PID, user, threads, SIGTERM), sampled at most every 2 s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-18 05:58:11 -07:00
co-authored by Claude Fable 5.1
parent 4986af5ac9
commit ff922bda74
5 changed files with 219 additions and 1 deletions
+26
View File
@@ -16,6 +16,7 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"github.com/coder/websocket"
@@ -125,6 +126,7 @@ func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, col *me
m.HandleFunc("GET /api/storage/zfs/snapshots", s.auth(s.zfsSnapshots))
m.HandleFunc("POST /api/storage/zfs/scrub/{pool}/{action}", s.auth(s.zfsScrub))
m.HandleFunc("POST /api/storage/zfs/snapshot", s.auth(s.zfsSnapshot))
m.HandleFunc("POST /api/procs/{pid}/signal", s.auth(s.procSignal))
m.HandleFunc("GET /api/prefs/dashboard", s.auth(s.getDashPrefs))
m.HandleFunc("PUT /api/prefs/dashboard", s.auth(s.putDashPrefs))
m.HandleFunc("/api/", func(w http.ResponseWriter, _ *http.Request) { jsonErr(w, 404, "not found") })
@@ -922,6 +924,30 @@ func (s *Server) zfsSnapshot(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(204)
}
// ---- processes ----
func (s *Server) procSignal(w http.ResponseWriter, r *http.Request) {
pid, err := strconv.Atoi(r.PathValue("pid"))
if err != nil {
jsonErr(w, 400, "bad pid")
return
}
var body struct {
Signal string `json:"signal"`
}
_ = json.NewDecoder(io.LimitReader(r.Body, 1024)).Decode(&body)
sig := syscall.SIGTERM
if body.Signal == "KILL" {
sig = syscall.SIGKILL
}
if err := metrics.Signal(pid, sig); err != nil {
jsonErr(w, 400, err.Error())
return
}
log.Printf("procs: sent %s to pid %d (from %s)", sig, pid, clientIP(r))
w.WriteHeader(204)
}
// ---- dashboard layout prefs (opaque JSON object, owned by the UI) ----
func (s *Server) getDashPrefs(w http.ResponseWriter, _ *http.Request) {