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:
+48
-12
@@ -9,8 +9,8 @@
|
||||
// own mount table, and a unit a removed package left behind, failed beside it, said by nobody.
|
||||
//
|
||||
// On every look the engine asks each service manager the mesh places units in — the machine's, and the
|
||||
// account manager of every account the declaration names — which units failed, and says each one's
|
||||
// owner:
|
||||
// account manager of every account the declaration places a user-scoped unit for — which units failed,
|
||||
// and says each one's owner:
|
||||
//
|
||||
// 1. a service or process the declaration states, by its unit and manager;
|
||||
// 2. a file the declaration writes, when the unit's file is that file;
|
||||
@@ -23,6 +23,12 @@
|
||||
//
|
||||
// **It reads; it never acts** (ADR 0240 rule 6): `list-units`, `show` and the package manager's owner
|
||||
// query are the whole of what it asks. It neither resets nor restarts anything.
|
||||
//
|
||||
// **A look starts no account's manager** (novox/hq issue 764, ADR 0177). Reading an account's manager is
|
||||
// a login, and a login starts the manager when none runs; so the machine's own manager is asked first
|
||||
// whether user@<uid>.service is active, and the account's is read only then. A manager that is not
|
||||
// running is away: no unit in it is failed, none is read, and the statement says it away — the apply's
|
||||
// word for the same absence ("waiting" for its manager).
|
||||
package units
|
||||
|
||||
import (
|
||||
@@ -72,7 +78,9 @@ type Owned struct {
|
||||
// Files is keyed by path; Packages by package name, only those declared present.
|
||||
Files map[string]owner
|
||||
Packages map[string]owner
|
||||
// Accounts are the accounts whose own managers are read, sorted.
|
||||
// Accounts are the accounts whose own managers are read, sorted: each one the declaration places a
|
||||
// user-scoped unit for, and no other (novox/hq issue 764). An account the declaration only creates
|
||||
// has no unit of the mesh's in its manager to fail, and asking that manager starts it.
|
||||
Accounts []string
|
||||
}
|
||||
|
||||
@@ -123,8 +131,6 @@ func OwnedBy(d *declaration.Declaration, held map[string]bool) Owned {
|
||||
if !v.Absent {
|
||||
o.Packages[v.Package] = own
|
||||
}
|
||||
case *declaration.User:
|
||||
accounts[v.Name] = true
|
||||
}
|
||||
}
|
||||
for a := range accounts {
|
||||
@@ -169,6 +175,10 @@ type Reader interface {
|
||||
Show(ctx context.Context, scope, user string, units []string) (map[string]Shown, error)
|
||||
// PackageOwning is the package a file belongs to; false when none does or the machine cannot say.
|
||||
PackageOwning(ctx context.Context, path string) (string, bool, error)
|
||||
// UserManagerRunning is whether an account's own manager runs now, asked of the machine's manager
|
||||
// and never of the account's, which a question would start (novox/hq issue 764); exists is false
|
||||
// for an account the machine does not have.
|
||||
UserManagerRunning(ctx context.Context, account string) (running, exists bool, err error)
|
||||
}
|
||||
|
||||
// Failed is one failed unit as the statement says it.
|
||||
@@ -198,6 +208,9 @@ type Statement struct {
|
||||
Failed []Failed
|
||||
// Unread names each manager that could not be read, with why.
|
||||
Unread []string
|
||||
// Away names each account manager not running, so not read: its account is not logged in and does
|
||||
// not linger. Nothing in it is failed (novox/hq issue 764).
|
||||
Away []string
|
||||
}
|
||||
|
||||
// Owned answers the failures a module owns; Unowned those no module does.
|
||||
@@ -290,16 +303,39 @@ func (j *Judge) Look(ctx context.Context) (Statement, bool) {
|
||||
st := Statement{At: now, State: Unknown}
|
||||
read := 0
|
||||
failedNow := map[string]bool{}
|
||||
keep := func(m manager) {
|
||||
// What it held is neither cleared nor counted while it cannot be read.
|
||||
for k := range j.seen {
|
||||
if strings.HasPrefix(k, key(m.scope, m.user, "")) {
|
||||
failedNow[k] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, m := range managers {
|
||||
if m.scope == ScopeUser {
|
||||
// Asked of the machine's manager first: reading the account's own would start it.
|
||||
running, exists, err := j.reader.UserManagerRunning(ctx, m.user)
|
||||
switch {
|
||||
case err != nil:
|
||||
st.Unread = append(st.Unread, fmt.Sprintf("%s could not be read: %s", m, firstLine(err.Error())))
|
||||
keep(m)
|
||||
continue
|
||||
case !exists:
|
||||
st.Unread = append(st.Unread, fmt.Sprintf("%s could not be read: the machine has no account %q",
|
||||
m, m.user))
|
||||
keep(m)
|
||||
continue
|
||||
case !running:
|
||||
// Away: nothing in it runs, so nothing in it is failed; what it held is cleared.
|
||||
st.Away = append(st.Away, m.user+"'s own service manager is not running: the account is not "+
|
||||
"logged in and does not linger, so its units are not read")
|
||||
continue
|
||||
}
|
||||
}
|
||||
listed, err := j.reader.Failed(ctx, m.scope, m.user)
|
||||
if err != nil {
|
||||
st.Unread = append(st.Unread, fmt.Sprintf("%s could not be read: %s", m, firstLine(err.Error())))
|
||||
// What it held is neither cleared nor counted while it cannot be read.
|
||||
for k := range j.seen {
|
||||
if strings.HasPrefix(k, key(m.scope, m.user, "")) {
|
||||
failedNow[k] = true
|
||||
}
|
||||
}
|
||||
keep(m)
|
||||
continue
|
||||
}
|
||||
read++
|
||||
@@ -353,7 +389,7 @@ func (j *Judge) Look(ctx context.Context) (Statement, bool) {
|
||||
if read == 0 {
|
||||
st.State = Unknown
|
||||
}
|
||||
word := st.State
|
||||
word := st.State + "|away:" + strings.Join(st.Away, ",")
|
||||
for _, f := range st.Failed {
|
||||
word += "|" + f.Scope + "/" + f.Unit + "/" + f.Module
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user