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
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:
@@ -21,6 +21,11 @@ type fakeReader struct {
|
||||
owners map[string]string // by path
|
||||
unread map[string]error
|
||||
ownerQs int
|
||||
// away is each account whose own manager is not running; noAccount each the machine lacks.
|
||||
away map[string]bool
|
||||
noAccount map[string]bool
|
||||
// read is every manager whose failed units were asked, in order.
|
||||
read []string
|
||||
}
|
||||
|
||||
func mgr(scope, user string) string {
|
||||
@@ -31,6 +36,7 @@ func mgr(scope, user string) string {
|
||||
}
|
||||
|
||||
func (f *fakeReader) Failed(_ context.Context, scope, user string) ([]Listed, error) {
|
||||
f.read = append(f.read, mgr(scope, user))
|
||||
if err := f.unread[mgr(scope, user)]; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -45,6 +51,13 @@ func (f *fakeReader) Show(_ context.Context, _, _ string, units []string) (map[s
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (f *fakeReader) UserManagerRunning(_ context.Context, account string) (bool, bool, error) {
|
||||
if f.noAccount[account] {
|
||||
return false, false, nil
|
||||
}
|
||||
return !f.away[account], true, nil
|
||||
}
|
||||
|
||||
func (f *fakeReader) PackageOwning(_ context.Context, path string) (string, bool, error) {
|
||||
f.ownerQs++
|
||||
p, ok := f.owners[path]
|
||||
@@ -75,6 +88,11 @@ func declared() *declaration.Declaration {
|
||||
&declaration.Package{ID: "openrazer.daemon", Type: declaration.TypePackage, Package: "openrazer-daemon"},
|
||||
&declaration.Package{ID: "clipmenu.greenclip", Type: declaration.TypePackage, Package: "rofi-greenclip", Absent: true},
|
||||
&declaration.User{ID: "zsh.account", Type: declaration.TypeUser, Name: "operator"},
|
||||
// The operator's own manager is read because a module places a unit in it (dunst, on a desktop).
|
||||
&declaration.Service{ID: "dunst.reload", Type: declaration.TypeService, Unit: "dunst.service",
|
||||
Scope: declaration.ScopeUser, User: "operator"},
|
||||
// A module account the declaration only creates: its manager is never asked (issue 764).
|
||||
&declaration.User{ID: "telegram.account", Type: declaration.TypeUser, Name: "telegram"},
|
||||
&declaration.Service{ID: "sshd.run", Type: declaration.TypeService, Unit: "sshd.service", State: "running"},
|
||||
&declaration.Service{ID: "power.after-boot", Type: declaration.TypeService, Unit: "mesh-power-after-boot.service"},
|
||||
&declaration.File{ID: "watcher.unit", Type: declaration.TypeFile, Path: "/home/operator/.config/systemd/user/watcher.service"},
|
||||
@@ -283,3 +301,102 @@ func TestNothingIsReadBeforeADeclaration(t *testing.T) {
|
||||
t.Fatalf("before a declaration every unit would read as the machine's: %+v", st)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 764: a look starts no account's manager. Only an account the declaration places a user-scoped
|
||||
// unit for is read at all, and its manager only while the machine's says it runs.
|
||||
|
||||
func TestAnAccountWithNoUserUnitsIsNeverRead(t *testing.T) {
|
||||
o := OwnedBy(declared(), nil)
|
||||
if strings.Join(o.Accounts, " ") != "operator" {
|
||||
t.Fatalf("only an account with a user-scoped unit is read: %v", o.Accounts)
|
||||
}
|
||||
r := shanks()
|
||||
j := New(r)
|
||||
j.Set(o)
|
||||
lookTwice(t, j)
|
||||
for _, m := range r.read {
|
||||
if m == "user:telegram" {
|
||||
t.Fatalf("a module account the declaration only creates had its manager read: %v", r.read)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAManagerNotRunningIsAwayAndNotRead(t *testing.T) {
|
||||
r := shanks()
|
||||
j := New(r)
|
||||
j.Set(OwnedBy(declared(), nil))
|
||||
lookTwice(t, j)
|
||||
if len(j.Last().Owned()) != 1 {
|
||||
t.Fatalf("logged in, the Razer daemon is said: %+v", j.Last().Failed)
|
||||
}
|
||||
// The operator logs out: the manager is not asked, nothing in it is failed, it is said away.
|
||||
r.away = map[string]bool{"operator": true}
|
||||
r.read = nil
|
||||
st, changed := j.Look(context.Background())
|
||||
if strings.Join(r.read, " ") != "system" {
|
||||
t.Fatalf("a manager not running is not read: %v", r.read)
|
||||
}
|
||||
if !changed || len(st.Away) != 1 || !strings.Contains(st.Away[0], "operator") || len(st.Unread) != 0 {
|
||||
t.Fatalf("away, said, and not unread: %+v", st)
|
||||
}
|
||||
for _, f := range st.Failed {
|
||||
if f.Scope == ScopeUser {
|
||||
t.Fatalf("a manager not running has no failed units: %+v", f)
|
||||
}
|
||||
}
|
||||
if st.State != Degraded {
|
||||
t.Fatalf("the machine's own failed mounts still say degraded: %q", st.State)
|
||||
}
|
||||
// Back in: read as before, and a failure is new again (two looks).
|
||||
r.away = nil
|
||||
st, _ = j.Look(context.Background())
|
||||
if len(st.Away) != 0 || len(st.Owned()) != 0 {
|
||||
t.Fatalf("a manager running again is read, its failure on its first look not yet said: %+v", st)
|
||||
}
|
||||
st, _ = j.Look(context.Background())
|
||||
if len(st.Owned()) != 1 {
|
||||
t.Fatalf("and said on the second: %+v", st.Failed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnAccountTheMachineLacksIsUnread(t *testing.T) {
|
||||
r := shanks()
|
||||
r.noAccount = map[string]bool{"operator": true}
|
||||
j := New(r)
|
||||
j.Set(OwnedBy(declared(), nil))
|
||||
st, _ := j.Look(context.Background())
|
||||
if strings.Join(r.read, " ") != "system" || len(st.Unread) != 1 {
|
||||
t.Fatalf("an account the machine lacks is unread and its manager never asked: %v %+v", r.read, st)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhetherAManagerRunsIsAskedOfTheMachines(t *testing.T) {
|
||||
var asked []string
|
||||
state := "inactive"
|
||||
run := func(_ context.Context, name string, args ...string) (string, error) {
|
||||
asked = append(asked, name+" "+strings.Join(args, " "))
|
||||
switch name {
|
||||
case "getent":
|
||||
return "telegram:x:10007:10007::/var/lib/telegram:/usr/bin/nologin\n", nil
|
||||
case "systemctl":
|
||||
if state != "active" {
|
||||
return state + "\n", errors.New("systemctl exited 3")
|
||||
}
|
||||
return state + "\n", nil
|
||||
}
|
||||
return "", errors.New("unexpected")
|
||||
}
|
||||
e := Exec{Run: run, System: "arch"}
|
||||
if running, exists, err := e.UserManagerRunning(context.Background(), "telegram"); running || !exists || err != nil {
|
||||
t.Fatalf("an inactive manager is not running: %v %v %v", running, exists, err)
|
||||
}
|
||||
state = "active"
|
||||
if running, _, err := e.UserManagerRunning(context.Background(), "telegram"); !running || err != nil {
|
||||
t.Fatalf("an active manager runs: %v %v", running, err)
|
||||
}
|
||||
for _, a := range asked {
|
||||
if a != "getent passwd telegram" && a != "systemctl is-active user@10007.service" {
|
||||
t.Errorf("asked something but the user database and the machine's manager: %q", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user