diff --git a/chainsaw/step-templates/init.yaml b/chainsaw/step-templates/init.yaml index 2ca7272554..be118b0ed7 100644 --- a/chainsaw/step-templates/init.yaml +++ b/chainsaw/step-templates/init.yaml @@ -35,9 +35,9 @@ spec: (length(@)): 1 spec: endpoints: - - dnsName: (join('', ['localtargets-', $test.metadata.name, '.cloud.example.com'])) + - dnsName: (join('', ['localtargets.', $test.metadata.name, '.cloud.example.com'])) recordType: A - - dnsName: (join('', [$test.metadata.name, '.cloud.example.com'])) + - dnsName: (join('', ['localtargets.', $test.metadata.name, '.cloud.example.com'])) recordType: A timeout: 75s @@ -46,7 +46,7 @@ spec: - name: DNSENDPOINT_NAME value: ($test.metadata.name) - name: EXPECTED_DNS_NAME - value: (join('', ['localtargets-', $test.metadata.name, '.cloud.example.com'])) + value: (join('', ['localtargets.', $test.metadata.name, '.cloud.example.com'])) content: | set -eu pipefail diff --git a/controllers/providers/k8gbendpoint/applicationDNSEndpoint.go b/controllers/providers/k8gbendpoint/applicationDNSEndpoint.go index 20f4a219b3..e772dea6a2 100644 --- a/controllers/providers/k8gbendpoint/applicationDNSEndpoint.go +++ b/controllers/providers/k8gbendpoint/applicationDNSEndpoint.go @@ -233,6 +233,18 @@ func (d *ApplicationDNSEndpoint) GetExternalTargets(host string) (targets Target Msg("can't resolve FQDN using nameservers") continue } + // Fall back to legacy dash-prefix naming for backward compatibility during migration + if len(d.queryService.ExtractARecords(dnsResult.Msg)) == 0 { + lHostLegacy, err := getLocalTargetsHostLegacy(host) + if err != nil { + continue + } + dnsResultLegacy := d.queryService.Query(lHostLegacy, nameServersToUse) + if dnsResultLegacy.Err != nil { + continue + } + dnsResult = dnsResultLegacy + } clusterTargets := d.queryService.ExtractARecords(dnsResult.Msg) if len(clusterTargets) > 0 { targets[authServer.GeoTag] = &Target{clusterTargets} diff --git a/controllers/providers/k8gbendpoint/applicationDNSEndpoint_weight_test.go b/controllers/providers/k8gbendpoint/applicationDNSEndpoint_weight_test.go index 598764ed01..a022665e64 100644 --- a/controllers/providers/k8gbendpoint/applicationDNSEndpoint_weight_test.go +++ b/controllers/providers/k8gbendpoint/applicationDNSEndpoint_weight_test.go @@ -340,12 +340,12 @@ func TestWeight(t *testing.T) { ns := fmt.Sprintf("gslb-ns-%s-cloud.example.com", d.region) nsIP := test.authServers[ns].IP for _, v := range d.targets { - record := &dns.A{Hdr: dns.RR_Header{Name: dns.Fqdn("localtargets-app.gslb.cloud.example.com"), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 30}, + record := &dns.A{Hdr: dns.RR_Header{Name: dns.Fqdn("localtargets.app.gslb.cloud.example.com"), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 30}, A: net.ParseIP(v)} ips = append(ips, record) } qs.EXPECT(). - Query("localtargets-app.gslb.cloud.example.com", utils.DNSList{utils.DNSServer{Host: nsIP, Port: 53}}). + Query("localtargets.app.gslb.cloud.example.com", utils.DNSList{utils.DNSServer{Host: nsIP, Port: 53}}). Return(utils.DNSQueryResult{Msg: &dns.Msg{Answer: ips}, Err: nil, Status: utils.DNSQueryStatusResolved}). AnyTimes() } diff --git a/controllers/providers/k8gbendpoint/dns_validation.go b/controllers/providers/k8gbendpoint/dns_validation.go index 24df23c017..84397bdf74 100644 --- a/controllers/providers/k8gbendpoint/dns_validation.go +++ b/controllers/providers/k8gbendpoint/dns_validation.go @@ -24,9 +24,10 @@ import ( ) const ( - localTargetsPrefix = "localtargets-" - dnsNameMax = 253 - dnsLabelMax = 63 + localTargetsPrefix = "localtargets." + localTargetsPrefixLegacy = "localtargets-" + dnsNameMax = 253 + dnsLabelMax = 63 ) func getLocalTargetsHost(host string) (string, error) { @@ -37,6 +38,16 @@ func getLocalTargetsHost(host string) (string, error) { return localTargetsHost, nil } +// getLocalTargetsHostLegacy returns the legacy dash-separated localtargets name +// for backward compatibility during migration from localtargets- to localtargets.. +func getLocalTargetsHostLegacy(host string) (string, error) { + localTargetsHost := fmt.Sprintf("%s%s", localTargetsPrefixLegacy, host) + if err := validateDNSName(localTargetsHost); err != nil { + return "", fmt.Errorf("legacy derived localtargets name %q is invalid: %w", localTargetsHost, err) + } + return localTargetsHost, nil +} + func validateDNSName(name string) error { if len(name) > dnsNameMax { return fmt.Errorf("name exceeds %d characters", dnsNameMax) diff --git a/controllers/providers/k8gbendpoint/dns_validation_test.go b/controllers/providers/k8gbendpoint/dns_validation_test.go index b704c330c0..6de4245ad8 100644 --- a/controllers/providers/k8gbendpoint/dns_validation_test.go +++ b/controllers/providers/k8gbendpoint/dns_validation_test.go @@ -35,11 +35,13 @@ import ( ) func TestGetLocalTargetsHostRejectsTooLongFirstLabel(t *testing.T) { - host := strings.Repeat("a", 51) + ".cloud.example.com" - expectedErr := `derived localtargets name "localtargets-` + - strings.Repeat("a", 51) + - `.cloud.example.com" is invalid: label "localtargets-` + - strings.Repeat("a", 51) + + // With the dot prefix the host is split into labels, so the over-long + // label must live in the host portion: 64 'a's exceed the 63-char limit. + host := strings.Repeat("a", 64) + ".cloud.example.com" + expectedErr := `derived localtargets name "localtargets.` + + strings.Repeat("a", 64) + + `.cloud.example.com" is invalid: label "` + + strings.Repeat("a", 64) + `" exceeds 63 characters` _, err := getLocalTargetsHost(host) @@ -50,7 +52,7 @@ func TestGetLocalTargetsHostRejectsTooLongFirstLabel(t *testing.T) { func TestGetDNSEndpointRejectsInvalidLocalTargetsHost(t *testing.T) { logger := zerolog.New(io.Discard).With().Timestamp().Logger() metrics := func(*k8gbv1beta1io.Gslb, bool, k8gbv1beta1io.HealthStatus, []string) {} - host := strings.Repeat("a", 51) + ".cloud.example.com" + host := strings.Repeat("a", 64) + ".cloud.example.com" ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/controllers/utils/fakedns_test.go b/controllers/utils/fakedns_test.go index 86df1290ec..c38ba7c031 100644 --- a/controllers/utils/fakedns_test.go +++ b/controllers/utils/fakedns_test.go @@ -109,15 +109,15 @@ func TestFakeDNSBasic(t *testing.T) { func TestFakeDNSStress(t *testing.T) { for i := 1; i < 10; i++ { NewFakeDNS(testSettings). - AddARecord("localtargets-roundrobin.cloud.example.com.", net.IPv4(10, 1, 0, 3)). - AddARecord("localtargets-roundrobin.cloud.example.com.", net.IPv4(10, 1, 0, 2)). - AddARecord("localtargets-roundrobin.cloud.example.com.", net.IPv4(10, 1, 0, 1)). - AddTXTRecord("localtargets-heartbeat-us.cloud.example.com.", "5m"). + AddARecord("localtargets.roundrobin.cloud.example.com.", net.IPv4(10, 1, 0, 3)). + AddARecord("localtargets.roundrobin.cloud.example.com.", net.IPv4(10, 1, 0, 2)). + AddARecord("localtargets.roundrobin.cloud.example.com.", net.IPv4(10, 1, 0, 1)). + AddTXTRecord("localtargets.heartbeat-us.cloud.example.com.", "5m"). Start(). RunTestFunc(func() { t.Log("FakeDNS test: ", i) g := new(dns.Msg) - g.SetQuestion("localtargets-roundrobin.cloud.example.com.", dns.TypeA) + g.SetQuestion("localtargets.roundrobin.cloud.example.com.", dns.TypeA) // put server under load.... for i := 0; i <= 100; i++ { a, err := dns.Exchange(g, fmt.Sprintf("%s:%v", server, port)) diff --git a/terratest/utils/extensions.go b/terratest/utils/extensions.go index ef0f6154c0..35294e3779 100644 --- a/terratest/utils/extensions.go +++ b/terratest/utils/extensions.go @@ -541,7 +541,7 @@ func (i *Instance) waitForApp(predicate func(instances int) bool, stop bool) (er // second conditions endpointReady := false for n := 0; n < maxRetries/2; n++ { - ep, err := i.Resources().GetExternalDNSEndpointByName(i.w.state.gslb.name, i.w.namespace).GetEndpointByName(fmt.Sprintf("localtargets-%s", i.w.state.gslb.host)) + ep, err := i.Resources().GetExternalDNSEndpointByName(i.w.state.gslb.name, i.w.namespace).GetEndpointByName(fmt.Sprintf("localtargets.%s", i.w.state.gslb.host)) if err != nil { if err.Error() == notFoundError { // During startup the local DNSEndpoint can lag behind the app becoming ready, @@ -607,7 +607,7 @@ func (i *Instance) Dig() []string { // GetLocalTargets returns instance local targets func (i *Instance) GetLocalTargets() []string { - dnsName := fmt.Sprintf("localtargets-%s", i.w.state.gslb.host) + dnsName := fmt.Sprintf("localtargets.%s", i.w.state.gslb.host) dig, err := dns.Dig("localhost:"+strconv.Itoa(i.w.state.gslb.port), dnsName, i.w.settings.digUsingUDP) i.logIfError(err, "GetLocalTargets(), dig: %s", err) return dig