Start no account's manager to look at its units (hq issue 764)
mesh/merge-gate head 62af89f85d0d merged into trunk 1a2677882380 — pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes wi…
mesh/repo-check head 62af89f85d0d merged into trunk 1a2677882380 — pass: its merge-check.sh passed
mesh/delivery delivered

Every 15 s the failed-units look read the own manager of every account
the declaration creates, and reading one is a login that starts it: six
module accounts' managers on the control node started and stopped all
day, most of its journal. A look only reads (ADR 0240 rule 6) and never
asks an account's manager (ADR 0177).

An account's manager is read now only when the declaration places a
user-scoped unit in it, and only after the machine's own manager says
user@<uid>.service is active, as the apply asks before it. A manager not
running is said away in the units statement, with no failed units; in
liveness its units read unknown with the apply's words, never down. The
operator's account on a desktop is still read while logged in, since a
module places a user unit there (issue 315's Razer daemon stays said).
This commit is contained in:
2026-10-15 00:33:34 +02:00
parent 1a26778823
commit 62af89f85d
8 changed files with 276 additions and 17 deletions
+53
View File
@@ -330,3 +330,56 @@ func TestOneLookIsOneReadOfEveryContainer(t *testing.T) {
t.Fatalf("a container the inspect found, beside one it did not: %+v", s)
}
}
// **A look starts no account's manager** (novox/hq issue 764, ADR 0177): a user-scoped unit's manager is
// asked of the machine's first; one not running is not read, nothing is started, and its unit is said
// unknown with why — away, never down; one running is read as before.
func TestAUserUnitsManagerNotRunningIsNotReadAndNotDown(t *testing.T) {
var asked []string
manager := "inactive"
run := func(_ context.Context, name string, args ...string) (string, error) {
asked = append(asked, name+" "+strings.Join(args, " "))
switch {
case name == "getent":
return "operator:x:1000:1000::/home/operator:/bin/zsh\n", nil
case name == "systemctl" && len(args) > 0 && args[0] == "is-active":
if manager != "active" {
return manager + "\n", errors.New("systemctl exited 3")
}
return "active\n", nil
case name == "systemctl":
return "Id=dunst.service\nLoadState=loaded\nActiveState=active\nSubState=running\nNRestarts=0\nInvocationID=i1\n", nil
}
return "", errors.New("not a command the judge may run")
}
c := &clock{now: t0}
j := aJudge(t, &Exec{Run: run, System: "arch"}, c, "")
j.Set([]Resource{{Module: "dunst", ID: "dunst.daemon", Kind: KindService, Target: "dunst.service",
Scope: "user", User: "operator"}})
var st Statement
for i := 0; i < 4; i++ {
c.now = t0.Add(time.Duration(i) * time.Minute)
st, _ = j.Look(t.Context())
}
if s := stateOf(t, st, "dunst.daemon"); s.State != Unknown || !strings.Contains(s.Reason, "not logged in") {
t.Fatalf("a unit in a manager not running is away, not down: %+v", s)
}
for _, a := range asked {
if strings.Contains(a, "--machine=") {
t.Fatalf("the account's own manager was asked while it was not running: %q", a)
}
if a != "getent passwd operator" && a != "systemctl is-active user@1000.service" {
t.Errorf("asked something but whether the manager runs: %q", a)
}
}
// Logged in: read in the account's own manager, as before.
manager, asked = "active", nil
c.now = t0.Add(5 * time.Minute)
st, _ = j.Look(t.Context())
if s := stateOf(t, st, "dunst.daemon"); s.State == Unknown || s.State == Unhealthy {
t.Fatalf("a unit in a running manager is read: %+v", s)
}
if last := asked[len(asked)-1]; !strings.HasPrefix(last, "systemctl --user --machine=operator@ show ") {
t.Fatalf("the running manager is read in the account's own: %q", last)
}
}