- mesh-dns-resolver: a mesh seat delivering wildcard-resolution, so every node's resolver
configuration resolves to its one holder; node-dns-resolver kept until nothing claims it.
- ${bound:<provision>:address}: the providing machine's private address, for the one consumer
that cannot use a name — a machine's resolver configuration.
- zone: a module declares the zone it answers and the listen that answers it; the controller
settles it per node, refuses duplicates and shadowing, and hands the resolver .Zones to forward.
- node-hosts-file: a node seat whose holder owns /etc/hosts, with entries/add/remove.
The resolver tests follow the catalogue: no runtime dns (containers copy the machine's resolvers),
live-restore held by resolv-conf, resolv.conf naming the resolver by address then a public one.
79 lines
3.3 KiB
Go
79 lines
3.3 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A zone names the listen that answers it, or there is nothing to forward to (novox/hq ADR 0199).
|
|
func TestAZoneMustNameOneOfTheModulesListens(t *testing.T) {
|
|
_, err := ParseManifest([]byte(`{"module":"lab","version":"1",
|
|
"listens":[{"name":"dns","port":5353,"protocol":"udp","from":"mesh","why":"the lab's names"}],
|
|
"zone":{"name":"${setting:zone}","listen":"web"}}`))
|
|
if err == nil || !strings.Contains(err.Error(), `has no listen of that name`) {
|
|
t.Fatalf("a zone answered by a listen the module does not have was accepted: %v", err)
|
|
}
|
|
if _, err := ParseManifest([]byte(`{"module":"lab","version":"1",
|
|
"listens":[{"name":"dns","port":5353,"protocol":"udp","from":"mesh","why":"the lab's names"}],
|
|
"zone":{"name":"${setting:zone}","listen":"dns"}}`)); err != nil {
|
|
t.Fatalf("a well-formed zone was refused: %v", err)
|
|
}
|
|
}
|
|
|
|
// The zone is the operator's (a setting) and the port is where this machine publishes the listen —
|
|
// neither is the definition's to state.
|
|
func TestAZoneIsPlacedFromTheNodesSettingAndPublishedPort(t *testing.T) {
|
|
m := Manifest{Module: "lab", Zone: &Zone{Name: "${setting:zone}", Listen: "dns"},
|
|
Listens: []Listening{{Name: "dns", Port: 5353, From: FromMesh}}}
|
|
z, err := ZoneOn(m, []Layer{{From: "node", Values: map[string]any{"zone": "Incus."}}},
|
|
map[int]int{5353: 15353}, "workstation", "10.77.0.3")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if z.Zone != "incus" || z.Address != "10.77.0.3" || z.Port != 15353 || z.Node != "workstation" {
|
|
t.Fatalf("the zone was placed as %+v", *z)
|
|
}
|
|
if _, err := ZoneOn(m, nil, nil, "workstation", "10.77.0.3"); err == nil {
|
|
t.Fatal("a zone nobody named was placed")
|
|
}
|
|
}
|
|
|
|
// One module answers a zone, and none may shadow the mesh's names or a public domain.
|
|
func TestTheMeshRefusesAZoneTwiceOrOneThatShadows(t *testing.T) {
|
|
one := ZoneAt{Zone: "incus", Node: "workstation", Module: "lab", Address: "10.77.0.3", Port: 53}
|
|
if p := ZonesProblems([]ZoneAt{one}, "internal", []string{"example.tld"}); len(p) != 0 {
|
|
t.Fatalf("one ordinary zone was refused: %v", p)
|
|
}
|
|
twice := one
|
|
twice.Node, twice.Module = "laptop", "other"
|
|
cases := map[string][]ZoneAt{
|
|
"declared by": {one, twice},
|
|
"mesh's own suffix": {{Zone: "lab.internal", Node: "a", Module: "m"}},
|
|
"public domain": {{Zone: "dev.example.tld", Node: "a", Module: "m"}},
|
|
}
|
|
for want, zones := range cases {
|
|
p := strings.Join(ZonesProblems(zones, "internal", []string{"example.tld"}), "\n")
|
|
if !strings.Contains(p, want) {
|
|
t.Errorf("not refused for %q: %q", want, p)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The resolver's template sees every zone with where it is answered, in zone order.
|
|
func TestTheResolversTemplateRangesTheZones(t *testing.T) {
|
|
m := Manifest{Module: "dnsmasq", Facts: map[string]RosterFile{"zones": {
|
|
Path: "/etc/mesh-resolver/zones.conf",
|
|
Template: "{{range .Zones}}server=/{{.Zone}}/{{.Address}}#{{.Port}}\n{{end}}",
|
|
}}}
|
|
out, err := FactsWithZonesInto(m, Resolution{Node: "anchor"}, nil, nil, nil, "", []ZoneAt{
|
|
{Zone: "zeta", Address: "10.77.0.2", Port: 53},
|
|
{Zone: "incus", Address: "10.77.0.3", Port: 15353},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := out[0]["content"]; got != "server=/incus/10.77.0.3#15353\nserver=/zeta/10.77.0.2#53\n" {
|
|
t.Fatalf("the resolver was told %q", got)
|
|
}
|
|
}
|