carlos / platform Public

host: scan carlos.slice too so the edge's metrics row survives its move

carlos-edge.service moved into carlos.slice (isolated-exec design §4.3),
so its cgroup is now under /sys/fs/cgroup/carlos.slice/carlos-edge.service
rather than system.slice. realUnitReadings only scanned system.slice, so
the edge's per-unit metrics row silently stopped being discovered once the
unit landed there.

Add cgroupCarlosSliceDir as a second scan root beside cgroupSliceDir, and
have realUnitReadings scan both: system.slice for every platform unit that
has not moved (litestream, adopt, relay, ...), and carlos.slice for the
edge. The unit-name key stays carlos-edge.service either way, so the
reading published under it is unchanged for anything consuming the
metrics.

Pin the discovery with a fixture-tree test.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ1ZvWj7naf73GjTX8MBv5
Paul Campbell pushed by paul@keymail.dev be9bd4c3f34354630fabc696e50fabc657164ff2 parent a0c0520
3 files changed, +74 −0
  • internal/host/metrics_loop.go +6 −0
  • internal/host/metrics_probes.go +13 −0
  • internal/host/metrics_probes_test.go +55 −0
diff --git a/internal/host/metrics_loop.go b/internal/host/metrics_loop.go
index 58a88aadf..fa4d9e44b 100644
--- a/internal/host/metrics_loop.go
+++ b/internal/host/metrics_loop.go
@@ -657,6 +657,12 @@ func realSampleProbes(execRoot string, stampedUnits func() []string) sampleProbe
// second read is redundant, never contradictory.
func realUnitReadings(execRoot string, stamped []string) map[string]unitRaw {
units := listCarlosUnits(cgroupSliceDir)
+ // carlos-edge.service moved to carlos.slice (isolated-exec design §4.3;
+ // see cgroupCarlosSliceDir's doc comment), so it is found only by also
+ // scanning that second root. system.slice is still scanned above for
+ // every other platform unit — litestream, adopt, relay and the rest —
+ // which have not moved.
+ units = append(units, listCarlosUnits(cgroupCarlosSliceDir)...)
units = append(units, listStampedUnits(cgroupSliceDir, stamped)...)
units = append(units, listExecCgroups(execRoot)...)
if len(units) == 0 {
diff --git a/internal/host/metrics_probes.go b/internal/host/metrics_probes.go
index 4a43dfcc8..255e33d9c 100644
--- a/internal/host/metrics_probes.go
+++ b/internal/host/metrics_probes.go
@@ -48,6 +48,19 @@ func readLoadAvg() (l1, l5, l15 *float64) {
// a temp-dir fixture instead of the live kernel.
const cgroupSliceDir = "/sys/fs/cgroup/system.slice"
+// cgroupCarlosSliceDir is the second root listCarlosUnits and
+// listStampedUnits must scan: carlos-edge.service now lives in carlos.slice,
+// not system.slice, because the isolated-exec design (§4.3) moved the edge
+// there to share its memory wall with the exec-child instances it supervises
+// (see internal/host/units/carlos-edge.service's Slice=carlos.slice). On a
+// flat fleet — no tenant instances yet delegated their own cgroups — the
+// edge's own leaf is still the hierarchical total of everything under it,
+// delegated exec children included, so publishing that same
+// memory.current/cpu.stat/io.stat reading under the unchanged unit-name key
+// "carlos-edge.service" preserves the number operators already look at; only
+// the directory that number is read from has moved.
+const cgroupCarlosSliceDir = "/sys/fs/cgroup/carlos.slice"
+
// unitCgroup is one discovered CARLOS unit: its systemd unit name (the key
// everything downstream — sample maps, the console's activator.UnitName
// match — uses) and the cgroup directory that unit's files actually live in.
diff --git a/internal/host/metrics_probes_test.go b/internal/host/metrics_probes_test.go
index ee1eaa02f..adae5520e 100644
--- a/internal/host/metrics_probes_test.go
+++ b/internal/host/metrics_probes_test.go
@@ -182,3 +182,58 @@ func TestListExecCgroupsFindsPerHostDirs(t *testing.T) {
t.Fatalf("empty root must scan nothing, got %+v", out)
}
}
+
+// TestListCarlosUnitsFindsUnitsUnderCarlosSlice pins the review fix: once
+// carlos-edge.service moved into carlos.slice (isolated-exec design §4.3),
+// realUnitReadings must scan cgroupCarlosSliceDir as a second root or the
+// edge's metrics row silently vanishes. listCarlosUnits itself is root-
+// agnostic (it takes root as an argument precisely so callers can point it
+// at either slice), so this pins that a fixture shaped like the real
+// carlos.slice — a flat carlos-edge.service leaf holding memory.current, the
+// same file readUnitRaw actually reads — is discovered from that second
+// root, and that scanning it does not also resurface anything from a
+// system.slice-shaped root scanned separately.
+func TestListCarlosUnitsFindsUnitsUnderCarlosSlice(t *testing.T) {
+ root := t.TempDir()
+ carlosSlice := filepath.Join(root, "carlos.slice")
+ edgeDir := filepath.Join(carlosSlice, "carlos-edge.service")
+ if err := os.MkdirAll(edgeDir, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(edgeDir, "memory.current"), []byte("12345\n"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ got := listCarlosUnits(carlosSlice)
+ if len(got) != 1 {
+ t.Fatalf("discovered %d units under carlos.slice, want 1: %+v", len(got), got)
+ }
+ if got[0].name != "carlos-edge.service" || got[0].dir != edgeDir {
+ t.Fatalf("got %+v, want name carlos-edge.service dir %s", got[0], edgeDir)
+ }
+
+ // A system.slice-shaped root scanned on its own must not also produce
+ // the edge: the two roots are independent, so an edge found only under
+ // carlos.slice must not be double-reported when both scans are combined
+ // the way realUnitReadings combines them.
+ systemSlice := filepath.Join(root, "system.slice")
+ if err := os.MkdirAll(systemSlice, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ systemGot := listCarlosUnits(systemSlice)
+ if len(systemGot) != 0 {
+ t.Fatalf("system.slice root found %+v, want none: the edge only lives under carlos.slice now", systemGot)
+ }
+
+ combined := append(append([]unitCgroup{}, systemGot...), got...)
+ seen := map[string]bool{}
+ for _, u := range combined {
+ if seen[u.name] {
+ t.Fatalf("unit %q double-reported when combining both scan roots: %+v", u.name, combined)
+ }
+ seen[u.name] = true
+ }
+ if !seen["carlos-edge.service"] {
+ t.Fatalf("carlos-edge.service missing from the combined scan: %+v", combined)
+ }
+}