The controller writes no /etc/hosts (hq ADR 0199)
/etc/hosts is the file of the node-hosts-file seat's holder; the controller writes into no file another seat's holder owns, and asks that holder if it ever needs a line there. The private network's module stops asking for the node-names fact; every machine already asks the mesh's one resolver for these names, and the host gives the region back at the next push.
This commit is contained in:
@@ -31,19 +31,18 @@ const Requirement = "private-network"
|
||||
|
||||
// Name is the module that answers it with WireGuard.
|
||||
//
|
||||
// **The names went with it.** A mesh-names module used to sit beside this — it wrote /etc/hosts
|
||||
// and ran nothing, which is not a module. Being on the private network is what gives a machine a
|
||||
// name, so this module asks for the `node-names` fact and the mesh writes the file. The
|
||||
// name-resolution provision went the same way: names are facts the mesh computes, not something a
|
||||
// module that runs nowhere can provide.
|
||||
// **It writes no names.** A machine's mesh names are answered by the mesh's one resolver (novox/hq
|
||||
// ADR 0194), and /etc/hosts is the file of one module, the holder of `node-hosts-file` (ADR 0199): the
|
||||
// controller writes into no file another seat's holder owns. If the mesh ever needs a line there, it
|
||||
// asks that holder to register it. This module asked for a `node-names` fact written into /etc/hosts
|
||||
// until 2026-10-05; the host gives that region back at the first push without it.
|
||||
const Name = "mesh-wireguard"
|
||||
|
||||
// Addressing is the mesh handing out addresses on the private network itself.
|
||||
//
|
||||
// Names are computed from it, which is why they require this rather than a private network in
|
||||
// general. A different VPN that hands out its own addresses would come with its own names — the
|
||||
// mesh has nothing to write about a machine whose address it did not choose. Saying so here is
|
||||
// what keeps a machine from being given a hosts file full of addresses that mean nothing.
|
||||
// The mesh's resolver answers names from it, which is why it requires this rather than a private
|
||||
// network in general. A different VPN that hands out its own addresses would come with its own
|
||||
// names — the mesh has nothing to answer about a machine whose address it did not choose.
|
||||
const Addressing = "mesh-addressing"
|
||||
|
||||
// TheNetwork is what a machine can only have one of.
|
||||
@@ -82,7 +81,8 @@ type Generator struct {
|
||||
// registry is the mesh's artifact store as the network reaches it (host:port), or empty when
|
||||
// the mesh has none. Being on the network is what grants a machine the right to pull from it
|
||||
// (novox/hq ADR 0082), so the module that puts a machine on the network is what writes the
|
||||
// runtime's trust — the same reasoning that has it write /etc/hosts.
|
||||
// runtime's trust. (That is still a write into another module's file, the container runtime's;
|
||||
// novox/hq issue 190 has it handed to that module as a value.)
|
||||
registry string
|
||||
}
|
||||
|
||||
@@ -161,20 +161,6 @@ func (g *Generator) Nodes() []Node { return g.nodes }
|
||||
// Graph is the peer list per node, for showing.
|
||||
func (g *Generator) Graph() Graph { return g.graph }
|
||||
|
||||
// hostsTemplate is the mesh's region of `/etc/hosts` — every machine's mesh name at its private
|
||||
// address, written into a marked region and merged (RosterFile.Shared → `into: block`), so the rest
|
||||
// of the file (localhost, the machine's own name, other tools' blocks) is kept byte for byte
|
||||
// (novox/hq issue 128). It is a roster template like any module's: the mesh owns the data, this owns
|
||||
// the format, and the control plane holds no formatter.
|
||||
//
|
||||
// - No floor: no header, no localhost, no `127.0.1.1` — those are the machine's, above the region.
|
||||
// - A machine's own line is marked, and its mesh name resolves to its mesh address, not loopback.
|
||||
// - `.Names` is the machines (novox/hq ADR 0191): a route's internal name is under its node's
|
||||
// internal domain and the resolver answers it by wildcard, and a public name is public DNS's.
|
||||
// Machines with no address yet are already left out of the set.
|
||||
const hostsTemplate = "# The mesh's names. This region is replaced whenever a machine joins or leaves.\n" +
|
||||
"{{range .Names}}{{.Address}}\t{{.FQDN}}{{if ne .Name .FQDN}}\t{{.Name}}{{end}}{{if eq .Name $.Node}}\t# this machine{{end}}\n{{end}}"
|
||||
|
||||
// Manifest is the module the mesh provides for itself.
|
||||
//
|
||||
// It ships with the control plane rather than coming from a repository, because the thing that
|
||||
@@ -186,17 +172,7 @@ func Manifest() map[string]any {
|
||||
"version": "1",
|
||||
"computed": Name,
|
||||
"provides": []string{Requirement, Addressing},
|
||||
// Being on the private network is what gives a machine a name, so the module that puts it
|
||||
// there is what writes them. Asked for rather than generated by a module of its own: the
|
||||
// mesh knows which machines exist and where; writing that into a hosts file is not a thing
|
||||
// that needs a module to run nowhere. The format is a template like any other roster fact —
|
||||
// the mesh's own module owns the `/etc/hosts` layout the way dnsmasq owns its zones, and the
|
||||
// control plane holds no formatter (see catalogue.RosterFile). `shared`: the mesh owns only
|
||||
// its region of the file and keeps the rest (novox/hq issue 128).
|
||||
"facts": map[string]any{
|
||||
"node-names": map[string]any{"path": "/etc/hosts", "template": hostsTemplate, "shared": true},
|
||||
},
|
||||
"claims": []map[string]any{{"name": TheNetwork, "scope": "node"}},
|
||||
"claims": []map[string]any{{"name": TheNetwork, "scope": "node"}},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user