diff --git a/internal/catalogue/facts.go b/internal/catalogue/facts.go index d16c59c..c785cf0 100644 --- a/internal/catalogue/facts.go +++ b/internal/catalogue/facts.go @@ -106,10 +106,11 @@ func nodeNames(r Resolution, addresses map[string]string) string { b.WriteString("\n") for _, name := range sortedNames(addresses) { at := addresses[name] + internal, bare := meshName(name) // Its mesh name resolves to its address on the private network rather than to loopback, // so a service binding the name it was given stays reachable from everywhere else. - fmt.Fprintf(&b, "%s\t%s.internal\t%s", at, name, name) - if name == r.Node { + fmt.Fprintf(&b, "%s\t%s\t%s", at, internal, bare) + if bare == r.Node { b.WriteString("\t# this machine") } b.WriteString("\n") @@ -126,11 +127,24 @@ func nodeZones(_ Resolution, addresses map[string]string) string { b.WriteString("# Generated by the mesh. Do not edit — this file is replaced whenever a machine\n") b.WriteString("# joins or leaves, and an edit would survive until then and vanish.\n\n") for _, name := range sortedNames(addresses) { - fmt.Fprintf(&b, "address=/%s.internal/%s\n", name, addresses[name]) + internal, _ := meshName(name) + fmt.Fprintf(&b, "address=/%s/%s\n", internal, addresses[name]) } return b.String() } +// meshName is a machine's internal name and its bare one, from either. The control plane keys +// the names it hands a resolution by the internal name (`homer.internal`), the same map a +// container gets as its hosts; a caller that keys by the bare name gets the same answer. Written +// once, because the alternative was `homer.internal.internal` on every machine. +func meshName(name string) (internal, bare string) { + const suffix = ".internal" + if strings.HasSuffix(name, suffix) { + return name, strings.TrimSuffix(name, suffix) + } + return name + suffix, name +} + func sortedNames(addresses map[string]string) []string { out := make([]string, 0, len(addresses)) for name, at := range addresses { diff --git a/internal/catalogue/facts_test.go b/internal/catalogue/facts_test.go index b543768..a61fa21 100644 --- a/internal/catalogue/facts_test.go +++ b/internal/catalogue/facts_test.go @@ -95,3 +95,26 @@ func TestAFactMustBeAskedForAtAnAbsolutePath(t *testing.T) { t.Fatal("a relative path was accepted") } } + +// **The names the control plane hands a resolution are already internal names** — `homer.internal`, +// the same map every container gets as its hosts. Appending the suffix again wrote +// `homer.internal.internal` into every hosts file and every resolver's zones, and the large mesh +// bed's name test was the first to read it back. Either key gives the same files. +func TestNamesKeyedByInternalNameAreNotSuffixedTwice(t *testing.T) { + internal := map[string]string{"homer.internal": "10.42.0.1", "marge.internal": "10.42.0.2"} + bare := map[string]string{"homer": "10.42.0.1", "marge": "10.42.0.2"} + if a, b := nodeZones(Resolution{Node: "homer"}, internal), nodeZones(Resolution{Node: "homer"}, bare); a != b { + t.Fatalf("the zones differ by how the names were keyed:\n%s\n---\n%s", a, b) + } + if a, b := nodeNames(Resolution{Node: "homer"}, internal), nodeNames(Resolution{Node: "homer"}, bare); a != b { + t.Fatalf("the hosts differ by how the names were keyed:\n%s\n---\n%s", a, b) + } + zones := nodeZones(Resolution{Node: "homer"}, internal) + if strings.Contains(zones, "internal.internal") || !strings.Contains(zones, "address=/homer.internal/10.42.0.1") { + t.Fatalf("the zones carry a doubled suffix or miss the name:\n%s", zones) + } + hosts := nodeNames(Resolution{Node: "homer"}, internal) + if !strings.Contains(hosts, "10.42.0.1\thomer.internal\thomer\t# this machine") { + t.Fatalf("the hosts line for the machine itself is not name, bare name and the mark:\n%s", hosts) + } +}