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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user