80 lines
2.7 KiB
Go
80 lines
2.7 KiB
Go
// The mounts module's Go bundle (novox/hq research 038, ADR 0263). One binary, three ways to run:
|
|
//
|
|
// - with no argument it is the bundle the node's tool runner launches and speaks MCP to over stdio, as the
|
|
// operator account: the tools that read what a machine mounts and shares, the seat node-mounts' verbs
|
|
// and the health check; and beside them the module's half on the bus (bus.go);
|
|
// - `apply` and `watch` are the module's two long-running processes, run by the node-engine as root:
|
|
// one writes the unit pair of every share and source the machine is asked to mount and arms the
|
|
// automounts, the other tries each source and says what it found (apply.go);
|
|
// - `adopt <mountpoint>` is the root half of the verb adopt, run by the bundle through sudo (adopt.go).
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) > 1 {
|
|
switch os.Args[1] {
|
|
case "apply", "watch":
|
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt)
|
|
defer stop()
|
|
a := NewApplier()
|
|
a.Act, a.Judge = os.Args[1] == "apply", os.Args[1] == "watch"
|
|
RunApply(ctx, a)
|
|
return
|
|
case "adopt":
|
|
os.Exit(RunAdopt(os.Args[2:]))
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "mounts: %q is not a way to run; with no argument it serves its tools, with apply it "+
|
|
"writes and arms the machine's mounts, with watch it says how they are, with adopt <mountpoint> it takes over an fstab line\n", os.Args[1])
|
|
os.Exit(2)
|
|
}
|
|
}
|
|
m := Here()
|
|
go shareOnTheBus(m)
|
|
// An empty name serves as the module the runtime names (MESH_SERVED_MODULE): mounts.
|
|
if err := stdio.Serve("", Tools(m)); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// shareOnTheBus is the bundle's half on the bus, every LookEvery for as long as the bundle runs.
|
|
func shareOnTheBus(m *Machine) {
|
|
node := os.Getenv("MESH_NODE")
|
|
get := func(key string) (json.RawMessage, error) {
|
|
e, err := stdio.State(ExportsState).Get(key)
|
|
if err != nil || e == nil {
|
|
return nil, err
|
|
}
|
|
return e.Value, nil
|
|
}
|
|
put := func(key string, value any) error {
|
|
_, err := stdio.State(SharesState).Put(key, value)
|
|
return err
|
|
}
|
|
ask := func(key string, body any) (json.RawMessage, error) { return stdio.Ask(key, body) }
|
|
last, lastSaid := "", ""
|
|
for n := 0; ; n++ {
|
|
said := m.Share(node, get, put, &last, time.Now())
|
|
// Where the mesh keeps data here changes only with an assignment: asked at start and every five minutes.
|
|
if n%10 == 0 {
|
|
said = append(said, m.LeaveData(node, ask, time.Now())...)
|
|
}
|
|
if s := fmt.Sprint(said); len(said) > 0 && s != lastSaid {
|
|
fmt.Fprintln(os.Stderr, "mounts:", s)
|
|
lastSaid = s
|
|
}
|
|
time.Sleep(LookEvery)
|
|
}
|
|
}
|