mesh/merge-gate pass: builds networkmanager, systemd-networkd, sent nowhere; no bus step; 4 wait(s) for a person; every machine composes with the change as…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group feat/node-uplink-verbs delivered: every member is delivered
What a machine resolves through had no tool: the resolver file and who wrote it, and every link with its default route and the resolvers its manager knows. Each holder serves the same two node-uplink verbs; the reading is one text carried by both, held to it by a test, and only asking the manager for a link's names is each holder's own.
53 lines
1.5 KiB
Go
53 lines
1.5 KiB
Go
package main
|
|
|
|
// NetworkManager's word on each link's names: `nmcli device show`, read in its terse form. A link
|
|
// NetworkManager does not manage — a tunnel a VPN client raised with `ip`, the mesh's own — is not in it,
|
|
// and the links verb says the link without what the manager does not know.
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
)
|
|
|
|
func managerDNS(ctx context.Context) (map[string]LinkDNS, error) {
|
|
out, err := execRunner(ctx, "nmcli", "-t", "-f", "GENERAL.DEVICE,GENERAL.STATE,IP4.DNS,IP6.DNS,IP4.DOMAIN,IP6.DOMAIN",
|
|
"device", "show")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseNmcli(out), nil
|
|
}
|
|
|
|
// parseNmcli reads `nmcli -t device show`: blocks of KEY:value lines, one block per device.
|
|
func parseNmcli(out string) map[string]LinkDNS {
|
|
links := map[string]LinkDNS{}
|
|
device := ""
|
|
var cur LinkDNS
|
|
flush := func() {
|
|
if device != "" && (len(cur.Servers) > 0 || len(cur.Domains) > 0) {
|
|
cur.Manager = "NetworkManager"
|
|
links[device] = cur
|
|
}
|
|
device, cur = "", LinkDNS{}
|
|
}
|
|
for _, line := range strings.Split(out, "\n") {
|
|
key, value, ok := strings.Cut(strings.TrimSpace(line), ":")
|
|
if !ok {
|
|
continue
|
|
}
|
|
switch {
|
|
case key == "GENERAL.DEVICE":
|
|
flush()
|
|
device = value
|
|
case key == "GENERAL.STATE":
|
|
cur.State = value
|
|
case strings.HasPrefix(key, "IP4.DNS"), strings.HasPrefix(key, "IP6.DNS"):
|
|
cur.Servers = append(cur.Servers, value)
|
|
case strings.HasPrefix(key, "IP4.DOMAIN"), strings.HasPrefix(key, "IP6.DOMAIN"):
|
|
cur.Domains = append(cur.Domains, value)
|
|
}
|
|
}
|
|
flush()
|
|
return links
|
|
}
|