package localapi import ( "net/http" "gitea.dooplex.hu/admin/felhom-agent/internal/hub" ) // Host metrics (slice 9, doc 03 §6). The de-privileged controller (slice 8C) can only see its own // cgroup, so it cannot read host health itself. This endpoint re-serves the slice-4 collector's // host + per-storage view to the customer so the controller can render the box's health. // // Host-wide, token-authed, fresh: the metrics are about the BOX (not per-guest), so any valid // per-guest token gets the host-wide view (assumption: one customer per host — the home-server // model). It is a live collect (fresh cpu%/temp), not the 15-min hub-report snapshot. // HostMetricsResponse is GET /host/metrics: the host block + per-storage capacity targets. type HostMetricsResponse struct { VMID int `json:"vmid"` Host hub.HostMetrics `json:"host"` // cpu%/mem/load/uptime/cpu_temp_c StorageTargets []hub.StorageTarget `json:"storage_targets"` // per-storage total/used/thin-pool/SMART temp+wear } // handleHostMetrics serves a fresh host-health snapshot. The host block comes from a live // collector read; the per-storage capacity comes from the observer (the same source the hub // report uses). Best-effort on storage: a storage-view error still returns the host block (the // CPU/mem/temp view is the headline) with an empty targets list. func (s *Server) handleHostMetrics(w http.ResponseWriter, r *http.Request, vmid int) { if s.hostMetrics == nil { writeErr(w, http.StatusServiceUnavailable, "host metrics not configured on this host") return } host, err := s.hostMetrics.HostMetricsNow(r.Context()) if err != nil { s.logger.Error("local-api: /host/metrics collect", "vmid", vmid, "err", err) writeErr(w, http.StatusBadGateway, "could not read host metrics") return } targets, err := s.storage.Observe(r.Context()) if err != nil { // Host health is the headline — don't sink it on a storage-view hiccup. s.logger.Warn("local-api: /host/metrics storage view unavailable", "vmid", vmid, "err", err) targets = []hub.StorageTarget{} } if targets == nil { targets = []hub.StorageTarget{} } writeOK(w, HostMetricsResponse{VMID: vmid, Host: host, StorageTargets: targets}) }