mesh/delivery-group group feat/774-l3-reland rejected: composed together: the checker's verdict at the members' heads (b48c90fea31f): integration: mesh-self-ch…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: integration: mesh-self-check/cmd/mesh-self-check.TestTheSelfCheckWholeRunsOnTheBus: the run answered {Run:doctor-1793351737-1 At:20…
One commit with exactly the tree of the reviewed head35b4509c0a, on main12c2574c9d, so two compiled programs added and removed on the branch leave no trace in history (issue 1577).
105 lines
3.2 KiB
Go
105 lines
3.2 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"
|
|
"git.novox.be/novox/mesh-sdk/go/health"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"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
|
|
}
|
|
read := func(node string) ([]health.Reading, error) {
|
|
st := stdio.State(health.ReadingsRead)
|
|
keys, err := st.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var out []health.Reading
|
|
for _, k := range keys {
|
|
if !strings.HasPrefix(k, node+".") {
|
|
continue
|
|
}
|
|
e, err := st.Get(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if e == nil {
|
|
continue
|
|
}
|
|
if r, err := health.DecodeReading(e.Value); err == nil {
|
|
out = append(out, r)
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
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, read, time.Now())...)
|
|
}
|
|
if s := fmt.Sprint(said); len(said) > 0 && s != lastSaid {
|
|
fmt.Fprintln(os.Stderr, "mounts:", s)
|
|
lastSaid = s
|
|
}
|
|
time.Sleep(LookEvery)
|
|
}
|
|
}
|