A live restart of the system bus during an upgrade hung every login on a workstation until a reboot. The module owns the bus's packages, declares the bus running with no restart or reload trigger, publishes only curated events (health, services, denials; never traffic) and serves tools to look at both buses.
100 lines
4.1 KiB
Go
100 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
var busArg = map[string]any{"type": "string", "enum": Buses,
|
|
"description": "system (the default) or session (this account's login session bus, where one exists)"}
|
|
|
|
func busOf(args map[string]any) string {
|
|
b, _ := args["bus"].(string)
|
|
return b
|
|
}
|
|
|
|
// Tools are the module's tools over MCP (novox/hq ADR 0215): the names on either bus, what an object
|
|
// offers, a bounded watch of message headers, the module's check, and the bus's health.
|
|
func Tools(m *Machine, w *Watcher) []stdio.Tool {
|
|
return []stdio.Tool{
|
|
{
|
|
Name: "dbus_names",
|
|
Description: "Every well-known name on the system or session bus: its owner's pid, process, user and " +
|
|
"systemd unit, the activatable names that are not running, and how many connections the bus has. " +
|
|
"Read as the operator's account.",
|
|
Input: map[string]any{"type": "object", "properties": map[string]any{"bus": busArg}},
|
|
Run: func(args map[string]any) (any, error) {
|
|
return m.Names(context.Background(), busOf(args))
|
|
},
|
|
},
|
|
{
|
|
Name: "dbus_introspect",
|
|
Description: "What one object on a bus offers: its interfaces with their methods (arguments in and out), " +
|
|
"properties (type and access, never their values) and signals, and its child objects. A service " +
|
|
"that is not running is not started for it.",
|
|
Input: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"bus": busArg,
|
|
"service": map[string]any{"type": "string", "description": "the bus name, e.g. org.freedesktop.login1"},
|
|
"path": map[string]any{"type": "string", "description": "the object path (default /)"},
|
|
},
|
|
"required": []string{"service"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
service, _ := args["service"].(string)
|
|
path, _ := args["path"].(string)
|
|
return m.Introspect(context.Background(), busOf(args), service, path)
|
|
},
|
|
},
|
|
{
|
|
Name: "dbus_monitor",
|
|
Description: fmt.Sprintf("Watch a bus for a few seconds (at most %d) and answer the headers of the "+
|
|
"messages that passed: type, sender, destination, path, interface, member. Never a message's body, "+
|
|
"which carries secrets, notification text and the clipboard. Optional match rule and names to "+
|
|
"narrow it. The system bus is watched as root through sudo -n.", MaxMonitorSeconds),
|
|
Input: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"bus": busArg,
|
|
"seconds": map[string]any{"type": "integer", "description": fmt.Sprintf("how long (default 5, at most %d)", MaxMonitorSeconds)},
|
|
"match": map[string]any{"type": "string", "description": "a D-Bus match rule, e.g. type='signal',interface='org.freedesktop.login1.Manager'"},
|
|
"names": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "only messages to or from these bus names"},
|
|
},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
s := 5
|
|
if v, ok := args["seconds"].(float64); ok {
|
|
s = int(v)
|
|
}
|
|
match, _ := args["match"].(string)
|
|
var names []string
|
|
if list, ok := args["names"].([]any); ok {
|
|
for _, n := range list {
|
|
if str, ok := n.(string); ok {
|
|
names = append(names, str)
|
|
}
|
|
}
|
|
}
|
|
return m.Monitor(context.Background(), busOf(args), s, match, names)
|
|
},
|
|
},
|
|
{
|
|
Name: "dbus_check",
|
|
Description: "Whether this machine's message bus is as the mesh expects: the bus's packages installed, " +
|
|
"dbus-broker running behind dbus.service, whether the running bus is older than its installed " +
|
|
"package (then a reboot is due: the bus is never restarted live), activatable services whose " +
|
|
"unit does not exist, policy denials in the last hour, and the watcher's state.",
|
|
Run: func(map[string]any) (any, error) { return m.Check(context.Background(), w), nil },
|
|
},
|
|
{
|
|
Name: "dbus_health",
|
|
Description: "The system bus's health now: a ping's round trip, how many connections it has, its unit, " +
|
|
"pid and uptime, and what the watcher last saw.",
|
|
Run: func(map[string]any) (any, error) { return m.Health(context.Background(), w), nil },
|
|
},
|
|
}
|
|
}
|