Files
mesh-catalog/modules/time-sync/cmd/time-sync-tools/main.go
T
jochen 21d8a7f6b4 time-sync: one time daemon, timesyncd, with its servers declared
Three machines ran timesyncd and one ran ntpd. The module declares
timesyncd running with a 50-mesh.conf drop-in (European pool) and ntp absent
(hq ADR 0180). A run-once step of its Go binary stops and disables ntpd first
and takes out only dangling wants-links, so removing the package leaves no
enabled unit pointing at nothing. A provider's drop-in sorting after the
mesh's still wins and is reported, not removed. Tools: time_sync_status,
_servers, _sync_now (to-be 42 Phase 1).
2026-10-04 12:50:20 +02:00

78 lines
2.7 KiB
Go

// time-sync's tools bundle (novox/hq to-be 42 Phase 1, research 026/05), and its step.
//
// Served by the node's runtime over MCP on stdio through the Go SDK (ADR 0188, ADR 0193) when it is
// started with no arguments. Started as `time-sync-tools retire <unit>…` it is the module's step,
// which the host runs once as root for every version of the bundle (timesync.go says why).
package main
import (
"context"
"fmt"
"os"
"strings"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// binaryName is what the build names this bundle's executable: the manifest's `binary`.
const binaryName = "time-sync-tools"
func bg() context.Context { return context.Background() }
func main() {
m := ThisMachine()
if len(os.Args) > 1 {
if os.Args[1] != "retire" || len(os.Args) < 3 {
fmt.Fprintf(os.Stderr, "usage: %s [retire <unit>…]\n", binaryName)
os.Exit(2)
}
r, err := m.Retire(os.Args[2:], Wants, Dangling, os.Remove)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Printf("disabled: %s; dangling links taken out: %s\n", orNone(r.Disabled), orNone(r.Removed))
return
}
// An empty name serves as the module the runtime names (MESH_SERVED_MODULE): time-sync.
if err := stdio.Serve("", tools(m)); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func orNone(list []string) string {
if len(list) == 0 {
return "none"
}
return strings.Join(list, ", ")
}
func tools(m *Machine) []stdio.Tool {
return []stdio.Tool{
{
Name: "time_sync_status",
Description: "Whether the clock is synchronised and how well: NTP on, synchronised, timesyncd's unit state, the server " +
"it uses, offset, delay and jitter in milliseconds, stratum and packet count (timedatectl timesync-status, with " +
"its every line), and any other time daemon installed beside it. timesyncd not answering is said, not failed.",
Input: schema(map[string]any{}),
Run: func(map[string]any) (any, error) { return m.Status() },
},
{
Name: "time_sync_servers",
Description: "The servers timesyncd uses (the one now, the configured, the fallback, the link's and the runtime's) " +
"and every configuration file in the order it reads them with the NTP= and FallbackNTP= each sets; which file " +
"decides, and a note when a drop-in sorting after the mesh's wins.",
Input: schema(map[string]any{}),
Run: func(map[string]any) (any, error) { return m.Servers() },
},
{
Name: "time_sync_sync_now",
Description: "Restart timesyncd (sudo -n), which asks its server at once, and answer the status after up to ten " +
"seconds of waiting for its first packet.",
Input: schema(map[string]any{}),
Run: func(map[string]any) (any, error) { return m.SyncNow() },
},
}
}