Files
mesh-catalog/modules/mounts/cmd/mounts/main.go
T

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)
}
}