Let mounts write each share's mount and automount, so no node depends on a hand-written fstab line (hq ADR 0263)

A machine mounts what its assignment names: a node's share from the
provision nfs-share, whose path it reads from nfs-server's state on the
bus, and occasional sources (an SMB device, a disk) whose absence is a
state, not a fault. apply writes and arms the unit pairs as root; watch
tries each source and judges the health; the operator's fstab lines are
taken over only through adopt, on their word, once the replacement is
armed. SMB logins are an outside party's secret, given with secret accept.
This commit is contained in:
jochen
2026-10-08 18:36:01 +02:00
parent 3251758340
commit 2b1b9b0235
16 changed files with 2583 additions and 18 deletions
+36 -1
View File
@@ -42,11 +42,15 @@ type Machine struct {
Root string
Run Runner
LookPath func(name string) bool
// Escalate runs a command as root: as given where this process is root, else through `sudo -n`, as the
// bundle runs as the operator account (novox/hq ADR 0175 §4) and the sudo module lets it.
Escalate Runner
}
// Here is the machine this process runs on.
func Here() *Machine {
return &Machine{Root: "/", Run: ExecRunner, LookPath: func(n string) bool { _, err := exec.LookPath(n); return err == nil }}
return &Machine{Root: "/", Run: ExecRunner, Escalate: EscalatedRunner,
LookPath: func(n string) bool { _, err := exec.LookPath(n); return err == nil }}
}
// read answers one file's text under the root. Only regular files the module names are read; a
@@ -81,3 +85,34 @@ func unreadable(path string, err error) string {
return fmt.Sprintf("%s: not read (%v)", path, err)
}
}
// EscalatedRunner runs a command as root, through sudo without a prompt where this process is not root.
// A refusal by sudo is said as one, never read as an empty answer.
func EscalatedRunner(ctx context.Context, name string, args ...string) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 25*time.Second)
defer cancel()
program, argv := name, args
if os.Getuid() != 0 {
program, argv = "sudo", append([]string{"-n", name}, args...)
}
cmd := exec.CommandContext(ctx, program, argv...)
var stdout, stderr bytes.Buffer
cmd.Stdout, cmd.Stderr = &stdout, &stderr
if err := cmd.Run(); err != nil {
said := strings.TrimSpace(stderr.String())
if program == "sudo" && strings.HasPrefix(said, "sudo:") {
return stdout.String(), fmt.Errorf("%s needs root, and the tool runner's account may not run it without a prompt: %s", name, said)
}
if said != "" {
return stdout.String(), fmt.Errorf("%s: %w: %s", name, err, said)
}
return stdout.String(), fmt.Errorf("%s: %w", name, err)
}
return stdout.String(), nil
}
// present says whether a device or a file is there. Never used on a mount point.
func (m *Machine) present(p string) bool {
_, err := os.Stat(filepath.Join(m.Root, p))
return err == nil
}