diff --git a/chart/k8gb/templates/_helpers.tpl b/chart/k8gb/templates/_helpers.tpl index 10a5dde08e..0e10837b44 100644 --- a/chart/k8gb/templates/_helpers.tpl +++ b/chart/k8gb/templates/_helpers.tpl @@ -96,6 +96,28 @@ k8gb-{{ .Values.k8gb.dnsZone }}-{{ .Values.k8gb.clusterGeoTag }} {{- end -}} {{- end -}} +{{- define "k8gb.dnsZones" -}} +{{- $entries := list -}} +{{- range .Values.k8gb.dnsZones }} + {{- $entry := printf "%s:%s" .zone .domain }} + {{- $entries = append $entries $entry }} +{{- end }} +{{- if and .Values.k8gb.dnsZone .Values.k8gb.edgeDNSZone }} + {{- $extraEntry := printf "%s:%s" .Values.k8gb.edgeDNSZone .Values.k8gb.dnsZone }} + {{- $entries = append $entries $extraEntry }} +{{- end }} +{{- join ";" $entries }} +{{- end }} + + +{{- define "k8gb.coredns.extraPlugins" -}} +{{- if .Values.k8gb.coredns.extra_plugins }} +{{- range .Values.k8gb.coredns.extra_plugins }} + {{ . }} +{{- end }} +{{- end }} +{{- end }} + {{- define "k8gb.extdnsProviderOpts" -}} {{- if .Values.ns1.enabled -}} {{- if .Values.ns1.endpoint -}} diff --git a/chart/k8gb/templates/coredns/cm.yaml b/chart/k8gb/templates/coredns/cm.yaml index 846ebb928e..e2c92b1b66 100644 --- a/chart/k8gb/templates/coredns/cm.yaml +++ b/chart/k8gb/templates/coredns/cm.yaml @@ -8,11 +8,12 @@ metadata: {{ include "chart.labels" . | indent 4 }} data: Corefile: |- - {{ .Values.k8gb.dnsZone }}:5353 { +{{- range .Values.k8gb.dnsZones }} + {{ .domain }}:5353 { errors health -{{- if .Values.k8gb.coredns.extra_plugins }} -{{- range .Values.k8gb.coredns.extra_plugins }} +{{- if $.Values.k8gb.coredns.extra_plugins }} +{{- range $.Values.k8gb.coredns.extra_plugins }} {{ . }} {{- end }} {{- end }} @@ -21,10 +22,11 @@ data: forward . /etc/resolv.conf k8s_crd { filter k8gb.absa.oss/dnstype=local - negttl {{ .Values.k8gb.dnsZoneNegTTL }} + negttl {{ .dnsZoneNegTTL | default 30 }} loadbalance weight } } +{{- end }} {{- with .Values.k8gb.coredns.extraServerBlocks -}} {{- tpl . $ | nindent 4 }} {{- end }} diff --git a/chart/k8gb/templates/deployment.yaml b/chart/k8gb/templates/deployment.yaml index bc5a30776d..f7df89c013 100644 --- a/chart/k8gb/templates/deployment.yaml +++ b/chart/k8gb/templates/deployment.yaml @@ -59,12 +59,10 @@ spec: value: {{ quote .Values.k8gb.clusterGeoTag }} - name: EXT_GSLB_CLUSTERS_GEO_TAGS value: {{ quote .Values.k8gb.extGslbClustersGeoTags }} - - name: EDGE_DNS_ZONE - value: {{ .Values.k8gb.edgeDNSZone }} - name: EDGE_DNS_SERVERS value: {{ include "k8gb.edgeDNSServers" . }} - - name: DNS_ZONE - value: {{ .Values.k8gb.dnsZone }} + - name: DNS_ZONES + value: {{ include "k8gb.dnsZones" . }} - name: RECONCILE_REQUEUE_SECONDS value: {{ quote .Values.k8gb.reconcileRequeueSeconds }} - name: NS_RECORD_TTL diff --git a/chart/k8gb/values.schema.json b/chart/k8gb/values.schema.json index 8b40c2193f..83fb939607 100644 --- a/chart/k8gb/values.schema.json +++ b/chart/k8gb/values.schema.json @@ -266,6 +266,12 @@ "deployRbac": { "type": "boolean" }, + "dnsZones": { + "type": "array", + "items": { + "$ref": "#/definitions/k8gbDnsZone" + } + }, "dnsZone": { "format": "idn-hostname", "minLength": 1 @@ -334,12 +340,24 @@ "type": "object" } }, - "required": [ - "clusterGeoTag", - "extGslbClustersGeoTags", - "dnsZone", - "edgeDNSServers", - "edgeDNSZone" + "oneOf": [ + { + "required": [ + "clusterGeoTag", + "extGslbClustersGeoTags", + "edgeDNSServers", + "dnsZone", + "edgeDNSZone" + ] + }, + { + "required": [ + "clusterGeoTag", + "extGslbClustersGeoTags", + "edgeDNSServers", + "dnsZones" + ] + } ], "title": "k8gb" }, @@ -421,6 +439,28 @@ } } }, + "k8gbDnsZone": { + "type": "object", + "properties": { + "zone": { + "type": "string", + "format": "idn-hostname" + }, + "domain": { + "type": "string", + "format": "idn-hostname" + }, + "dnsZoneNegTTL": { + "type": "integer", + "minimum": 0, + "default": 300 + } + }, + "required": [ + "zone", + "domain" + ] + }, "Ns1": { "type": "object", "additionalProperties": false, diff --git a/chart/k8gb/values.yaml b/chart/k8gb/values.yaml index efcf58dc09..dd28a80f1a 100644 --- a/chart/k8gb/values.yaml +++ b/chart/k8gb/values.yaml @@ -13,12 +13,17 @@ k8gb: deployCrds: true # -- whether it should also deploy the service account, cluster role and cluster role binding deployRbac: true - # -- dnsZone controlled by gslb - dnsZone: "cloud.example.com" - # -- Negative TTL for SOA record - dnsZoneNegTTL: 300 - # -- main zone which would contain gslb zone to delegate - edgeDNSZone: "example.com" # main zone which would contain gslb zone to delegate + # -- deprecated: dnsZone controlled by gslb + # dnsZone: "cloud.example.org" + # -- deprecated: main zone which would contain gslb zone to delegate + # edgeDNSZone: example.org # main zone which would contain gslb zone to delegate + # -- array of dns zones controlled by gslb + dnsZones: + - zone: "example.com" # -- main zone which would contain gslb zone to delegate (same meaning as to edgeDNSZone) + domain: "cloud.example.com" # -- domain controlled by gslb (same meaning as to dnsZone) + dnsZoneNegTTL: 300 # -- Negative TTL for SOA record + - zone: "example.org" # -- main zone which would contain gslb zone to delegate (same meaning as to edgeDNSZone) + domain: "cloud.example.org" # -- domain controlled by gslb (same meaning as to dnsZone) # -- host/ip[:port] format is supported here where port defaults to 53 edgeDNSServers: # -- use this DNS server as a main resolver to enable cross k8gb DNS based communication diff --git a/controllers/depresolver/depresolver.go b/controllers/depresolver/depresolver.go index 7bc0eec22f..a6c7ed6f0b 100644 --- a/controllers/depresolver/depresolver.go +++ b/controllers/depresolver/depresolver.go @@ -124,8 +124,8 @@ type Config struct { NSRecordTTL int `env:"NS_RECORD_TTL, default=30"` // ClusterGeoTag to determine specific location ClusterGeoTag string `env:"CLUSTER_GEO_TAG"` - // ExtClustersGeoTags to identify clusters in other locations in format separated by comma. i.e.: "eu,uk,us" - ExtClustersGeoTags []string `env:"EXT_GSLB_CLUSTERS_GEO_TAGS, default=[]"` + // extClustersGeoTags to identify clusters in other locations in format separated by comma. i.e.: "eu,uk,us" + extClustersGeoTags []string `env:"EXT_GSLB_CLUSTERS_GEO_TAGS, default=[]"` // EdgeDNSType is READONLY and is set automatically by configuration EdgeDNSType EdgeDNSType // EdgeDNSServers @@ -134,10 +134,14 @@ type Config struct { fallbackEdgeDNSServerName string `env:"EDGE_DNS_SERVER"` // to avoid breaking changes is used as fallback server port for EdgeDNSServers fallbackEdgeDNSServerPort int `env:"EDGE_DNS_SERVER_PORT, default=53"` - // EdgeDNSZone main zone which would contain gslb zone to delegate; e.g. example.com - EdgeDNSZone string `env:"EDGE_DNS_ZONE"` - // DNSZone controlled by gslb; e.g. cloud.example.com - DNSZone string `env:"DNS_ZONE"` + // edgeDNSZone main zone which would contain gslb zone to delegate; e.g. example.com + edgeDNSZone string `env:"EDGE_DNS_ZONE"` + // dnsZone controlled by gslb; e.g. cloud.example.com + dnsZone string `env:"DNS_ZONE"` + // DelegationZones + DelegationZones DelegationZones + // DelegationZones pairs of dnsZone ad edgeDNSZone, eg: DNS_ZONES=example.com:cloud.example.com;example.io:cloud.example.io + dnsZones string `env:"DNS_ZONES"` // K8gbNamespace k8gb namespace K8gbNamespace string `env:"POD_NAMESPACE"` // Infoblox configuration diff --git a/controllers/depresolver/depresolver_config.go b/controllers/depresolver/depresolver_config.go index c76d2d3d9c..3d98e0ed75 100644 --- a/controllers/depresolver/depresolver_config.go +++ b/controllers/depresolver/depresolver_config.go @@ -31,6 +31,9 @@ import ( "github.com/rs/zerolog" ) +// TODO: refactor with kong.CLI to read envvars into Config +// TODO: refactor with go-playground/validator to validate + // Environment variables keys const ( ReconcileRequeueSecondsKey = "RECONCILE_REQUEUE_SECONDS" @@ -41,6 +44,7 @@ const ( EdgeDNSServersKey = "EDGE_DNS_SERVERS" EdgeDNSZoneKey = "EDGE_DNS_ZONE" DNSZoneKey = "DNS_ZONE" + DNSZonesKey = "DNS_ZONES" InfobloxGridHostKey = "INFOBLOX_GRID_HOST" InfobloxVersionKey = "INFOBLOX_WAPI_VERSION" InfobloxPortKey = "INFOBLOX_WAPI_PORT" @@ -69,6 +73,12 @@ const ( EdgeDNSServerPortKey = "EDGE_DNS_SERVER_PORT" ) +const ( + localhost = "localhost" + + localhostIPv4 = "127.0.0.1" +) + // ResolveOperatorConfig executes once. It reads operator's configuration // from environment variables into &Config and validates func (dr *DependencyResolver) ResolveOperatorConfig() (*Config, error) { @@ -87,13 +97,17 @@ func (dr *DependencyResolver) ResolveOperatorConfig() (*Config, error) { fallbackDNS := fmt.Sprintf("%s:%v", dr.config.fallbackEdgeDNSServerName, dr.config.fallbackEdgeDNSServerPort) edgeDNSServerList := env.GetEnvAsArrayOfStringsOrFallback(EdgeDNSServersKey, []string{fallbackDNS}) dr.config.EdgeDNSServers = parseEdgeDNSServers(edgeDNSServerList) - dr.config.ExtClustersGeoTags = excludeGeoTag(dr.config.ExtClustersGeoTags, dr.config.ClusterGeoTag) + dr.config.extClustersGeoTags = excludeGeoTag(dr.config.extClustersGeoTags, dr.config.ClusterGeoTag) dr.config.Log.Level, _ = zerolog.ParseLevel(strings.ToLower(dr.config.Log.level)) dr.config.Log.Format = parseLogOutputFormat(strings.ToLower(dr.config.Log.format)) dr.config.EdgeDNSType, recognizedDNSTypes = getEdgeDNSType(dr.config) - // validation + // replace validations by go-playground/validator dr.errorConfig = dr.validateConfig(dr.config, recognizedDNSTypes) + // validation + if dr.errorConfig == nil { + dr.config.DelegationZones = parseDelegationZones(dr.config) + } }) return dr.config, dr.errorConfig } @@ -128,11 +142,11 @@ func (dr *DependencyResolver) validateConfig(config *Config, recognizedDNSTypes if err != nil { return err } - err = field(ExtClustersGeoTagsKey, config.ExtClustersGeoTags).hasItems().hasUniqueItems().err + err = field(ExtClustersGeoTagsKey, config.extClustersGeoTags).hasItems().hasUniqueItems().err if err != nil { return err } - for i, geoTag := range config.ExtClustersGeoTags { + for i, geoTag := range config.extClustersGeoTags { err = field(fmt.Sprintf("%s[%v]", ExtClustersGeoTagsKey, i), geoTag). isNotEmpty().matchRegexp(geoTagRegex).err if err != nil { @@ -160,11 +174,11 @@ func (dr *DependencyResolver) validateConfig(config *Config, recognizedDNSTypes return fmt.Errorf("error for port of edge dns server(%v): it must be a positive integer between 1 and 65535", s) } } - err = field(EdgeDNSZoneKey, config.EdgeDNSZone).isNotEmpty().matchRegexp(hostNameRegex).err + err = field(EdgeDNSZoneKey, config.edgeDNSZone).isNotEmpty().matchRegexp(hostNameRegex).err if err != nil { return err } - err = field(DNSZoneKey, config.DNSZone).isNotEmpty().matchRegexp(hostNameRegex).err + err = field(DNSZoneKey, config.dnsZone).isNotEmpty().matchRegexp(hostNameRegex).err if err != nil { return err } @@ -185,12 +199,12 @@ func (dr *DependencyResolver) validateConfig(config *Config, recognizedDNSTypes return nil } - serverNames := config.GetExternalClusterNSNames() - serverNames[config.ClusterGeoTag] = config.GetClusterNSName() + serverNames := config.getExternalClusterNSNames() + serverNames[config.ClusterGeoTag] = config.getClusterNSName() for geoTag, nsName := range serverNames { if len(nsName) > dnsNameMax { return fmt.Errorf("ns name '%s' exceeds %v charactes limit for [GeoTag: '%s', %s: '%s', %s: '%s']", - nsName, dnsLabelMax, geoTag, EdgeDNSZoneKey, config.EdgeDNSZone, DNSZoneKey, config.DNSZone) + nsName, dnsLabelMax, geoTag, EdgeDNSZoneKey, config.edgeDNSZone, DNSZoneKey, config.dnsZone) } if err := validateLabels(nsName); err != nil { return fmt.Errorf("error for geo tag: %s. %s in ns name %s", geoTag, err, nsName) @@ -215,7 +229,7 @@ func (dr *DependencyResolver) validateConfig(config *Config, recognizedDNSTypes func validateLocalhostNotAmongDNSServers(config *Config) error { containsLocalhost := func(list utils.DNSList) bool { for i := 1; i < len(list); i++ { // skipping first because localhost or 127.0.0.1 can occur on the first position - if list[i].Host == "localhost" || list[i].Host == "127.0.0.1" { + if list[i].Host == localhost || list[i].Host == localhostIPv4 { return true } } @@ -370,20 +384,22 @@ func parseLogOutputFormat(value string) LogFormat { return NoFormat } -func (c *Config) GetExternalClusterNSNames() (m map[string]string) { - m = make(map[string]string, len(c.ExtClustersGeoTags)) - for _, tag := range c.ExtClustersGeoTags { - m[tag] = getNsName(tag, c.DNSZone, c.EdgeDNSZone, c.EdgeDNSServers[0].Host) +// deprecated, used for validations only +func (c *Config) getExternalClusterNSNames() (m map[string]string) { + m = make(map[string]string, len(c.extClustersGeoTags)) + for _, tag := range c.extClustersGeoTags { + m[tag] = getNsName(tag, c.dnsZone, c.edgeDNSZone, c.EdgeDNSServers[0].Host) } return } -func (c *Config) GetClusterNSName() string { - return getNsName(c.ClusterGeoTag, c.DNSZone, c.EdgeDNSZone, c.EdgeDNSServers[0].Host) +// deprecated, used for validations only +func (c *Config) getClusterNSName() string { + return getNsName(c.ClusterGeoTag, c.dnsZone, c.edgeDNSZone, c.EdgeDNSServers[0].Host) } // getNsName returns NS for geo tag. -// The values is combination of DNSZone, EdgeDNSZone and (Ext)ClusterGeoTag, see: +// The values is combination of dnsZone, edgeDNSZone and (Ext)ClusterGeoTag, see: // DNS_ZONE k8gb-test.gslb.cloud.example.com // EDGE_DNS_ZONE: cloud.example.com // CLUSTER_GEOTAG: us diff --git a/controllers/depresolver/depresolver_domaininfo.go b/controllers/depresolver/depresolver_domaininfo.go new file mode 100644 index 0000000000..2eec6b6ea5 --- /dev/null +++ b/controllers/depresolver/depresolver_domaininfo.go @@ -0,0 +1,165 @@ +package depresolver + +/* +Copyright 2022 The k8gb Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic +*/ + +import ( + "fmt" + "sort" + "strings" + + k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" +) + +type DelegationZones []DelegationZoneInfo + +type DelegationZoneInfo struct { + Domain string + Zone string + ClusterNSName string + ExtClusterNSNames map[string]string +} + +func parseDelegationZones(config *Config) []DelegationZoneInfo { + + zones := config.dnsZones + edgeDNSZone := config.edgeDNSZone + dnsZone := config.dnsZone + + getNsName := func(tag, edgeDNSServer, zone, edge string) string { + if edgeDNSServer == localhost || edgeDNSServer == localhostIPv4 { + return edgeDNSServer + } + const prefix = "gslb-ns" + d := strings.TrimSuffix(zone, "."+edge) + domainX := strings.ReplaceAll(d, ".", "-") + return fmt.Sprintf("%s-%s-%s.%s", prefix, tag, domainX, edge) + } + + // parse example.com:cloud.example.com;example.io:cloud.example.io into map[string]string + getEnvAsArrayOfPairsOrFallback := func(zones string, fallback map[string]string) map[string]string { + pairs := make(map[string]string) + slice := strings.Split(zones, ";") + if len(slice) == 0 { + return fallback + } + for _, z := range slice { + pair := strings.Split(z, ":") + if len(pair) != 2 { + return fallback + } + pairs[strings.Trim(pair[0], " ")] = strings.Trim(pair[1], " ") + } + for k, v := range fallback { + if _, found := pairs[k]; !found { + pairs[k] = v + } + } + return pairs + } + var dzi []DelegationZoneInfo + zones = strings.TrimSuffix(strings.TrimSuffix(zones, ";"), " ") + fallbackDNSZone := map[string]string{} + if !(edgeDNSZone == "" && dnsZone == "") { + fallbackDNSZone[edgeDNSZone] = dnsZone + } + di := getEnvAsArrayOfPairsOrFallback(zones, fallbackDNSZone) + + for edge, zone := range di { + zoneInfo := DelegationZoneInfo{ + Domain: zone, + Zone: edge, + ClusterNSName: getNsName(config.ClusterGeoTag, config.EdgeDNSServers[0].Host, zone, edge), + ExtClusterNSNames: func(zone, edge string) map[string]string { + m := map[string]string{} + for _, tag := range config.extClustersGeoTags { + m[tag] = getNsName(tag, config.EdgeDNSServers[0].Host, zone, edge) + } + return m + }(zone, edge), + } + dzi = append(dzi, zoneInfo) + } + return dzi +} + +// GetNSServerList returns a sorted list of all NS servers for the delegation zone +func (z *DelegationZoneInfo) GetNSServerList() []string { + list := []string{z.ClusterNSName} + for _, v := range z.ExtClusterNSNames { + list = append(list, v) + } + sort.Strings(list) + return list +} + +// GetExternalDNSEndpointName returns name of endpoint sitting in k8gb namespace +func (z *DelegationZoneInfo) GetExternalDNSEndpointName() string { + var suffix = strings.Trim(strings.ReplaceAll(z.Domain, ".", "-"), " ") + return fmt.Sprintf("k8gb-ns-extdns-%s", suffix) +} + +// FindByGslbStatusHostname returns DelegationZoneInfo for the hostname +func (d *DelegationZones) FindByGslbStatusHostname(gslb *k8gbv1beta1.Gslb) *DelegationZoneInfo { + if len(gslb.Status.Servers) == 0 { + return nil + } + for _, z := range *d { + if strings.HasSuffix(gslb.Status.Servers[0].Host, z.Domain) { + return &z + } + } + return nil +} + +func (d *DelegationZones) GetClusterNSNameByGslb(gslb *k8gbv1beta1.Gslb) string { + z := d.FindByGslbStatusHostname(gslb) + if z != nil { + return z.ClusterNSName + } + return "" +} + +func (d *DelegationZones) GetExternalClusterNSNamesByHostname(host string) map[string]string { + z := d.getZone(host) + if z != nil { + return z.ExtClusterNSNames + } + return map[string]string{} +} + +func (d *DelegationZones) ContainsZone(host string) bool { + return d.getZone(host) != nil +} + +func (d *DelegationZones) ListZones() []string { + var zones []string + for _, z := range *d { + zones = append(zones, z.Zone) + } + return zones +} + +func (d *DelegationZones) getZone(host string) *DelegationZoneInfo { + for _, z := range *d { + if strings.Contains(host, z.Zone) { + return &z + } + } + return nil +} diff --git a/controllers/depresolver/depresolver_test.go b/controllers/depresolver/depresolver_test.go index 1959956629..0d4e029649 100644 --- a/controllers/depresolver/depresolver_test.go +++ b/controllers/depresolver/depresolver_test.go @@ -51,13 +51,14 @@ const ( defaultClusterGeoTagUs2 = "us-east-1" defaultClusterGeoTagEu = "eu-central-1" defaultEdgeDNSServerIP = "10.0.40.2" + defaultDNSZones = "example.com:cloud.example.com" ) var predefinedConfig = Config{ ReconcileRequeueSeconds: 30, NSRecordTTL: 30, ClusterGeoTag: "us", - ExtClustersGeoTags: []string{"za", "eu"}, + extClustersGeoTags: []string{"za", "eu"}, EdgeDNSType: DNSTypeInfoblox, EdgeDNSServers: []utils2.DNSServer{ { @@ -67,8 +68,9 @@ var predefinedConfig = Config{ }, fallbackEdgeDNSServerName: "", fallbackEdgeDNSServerPort: 53, - EdgeDNSZone: "example.com", - DNSZone: defaultEdgeDNSZone, + dnsZones: defaultDNSZones, + edgeDNSZone: "example.com", + dnsZone: defaultEdgeDNSZone, K8gbNamespace: "k8gb", MetricsAddress: "0.0.0.0:8080", Infoblox: Infoblox{ @@ -272,6 +274,7 @@ func TestResolveConfigWithDeprecatedEdgeDNSServerKey(t *testing.T) { // act config, err := resolver.ResolveOperatorConfig() depr := resolver.GetDeprecations() + config.DelegationZones = nil // assert assert.NoError(t, err) assert.NotEmpty(t, depr) @@ -320,10 +323,12 @@ func TestConfigRunOnce(t *testing.T) { resolver := NewDependencyResolver() // act config1, err1 := resolver.ResolveOperatorConfig() + config1.DelegationZones = nil depr1 := resolver.GetDeprecations() _ = os.Setenv(ReconcileRequeueSecondsKey, "100") // resolve again with new values config2, err2 := resolver.ResolveOperatorConfig() + config2.DelegationZones = nil depr2 := resolver.GetDeprecations() // assert assert.NoError(t, err1) @@ -576,7 +581,8 @@ func TestResolveConfigWithEmptyEdgeDnsZone(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.EdgeDNSZone = "" + expected.edgeDNSZone = "" + expected.DelegationZones = nil // act,assert arrangeVariablesAndAssert(t, expected, assert.Error) } @@ -585,7 +591,7 @@ func TestResolveConfigWithHostnameEdgeDnsZone(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.EdgeDNSZone = "company.2l.com" + expected.edgeDNSZone = "company.2l.com" // act,assert arrangeVariablesAndAssert(t, expected, assert.NoError) } @@ -594,7 +600,7 @@ func TestResolveConfigWithInvalidHostnameEdgeDnsZone(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.EdgeDNSZone = "https://zone.com" + expected.edgeDNSZone = "https://zone.com" // act,assert arrangeVariablesAndAssert(t, expected, assert.Error) } @@ -603,7 +609,7 @@ func TestResolveConfigWithInvalidHostnameDnsZone(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.DNSZone = "dns-zo?ne" + expected.dnsZone = "dns-zo?ne" // act,assert arrangeVariablesAndAssert(t, expected, assert.Error) } @@ -634,7 +640,8 @@ func TestResolveEmptyExtGeoTags(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.DNSZone = "" + expected.dnsZone = "" + expected.DelegationZones = nil // act,assert arrangeVariablesAndAssert(t, expected, assert.Error, DNSZoneKey) } @@ -643,7 +650,7 @@ func TestResolveMultipleExtGeoTags(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.ExtClustersGeoTags = []string{"foo", "blah", "boom"} + expected.extClustersGeoTags = []string{"foo", "blah", "boom"} // act,assert arrangeVariablesAndAssert(t, expected, assert.NoError) } @@ -652,7 +659,7 @@ func TestResolveUnsetExtGeoTags(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.ExtClustersGeoTags = []string{} + expected.extClustersGeoTags = []string{} // act,assert arrangeVariablesAndAssert(t, expected, assert.Error, ExtClustersGeoTagsKey) } @@ -662,7 +669,7 @@ func TestResolveInvalidExtGeoTags(t *testing.T) { defer cleanup() for _, arr := range [][]string{{"good-tag", ".wrong.tag?"}, {"", ""}} { expected := predefinedConfig - expected.ExtClustersGeoTags = arr + expected.extClustersGeoTags = arr // act,assert arrangeVariablesAndAssert(t, expected, assert.Error) } @@ -674,7 +681,7 @@ func TestResolveOnlyGeoTagExistsWithinExtGeoTags(t *testing.T) { tag := "us-west1" expected := predefinedConfig expected.ClusterGeoTag = tag - expected.ExtClustersGeoTags = []string{} + expected.extClustersGeoTags = []string{} configureEnvVar(expected) os.Setenv(ExtClustersGeoTagsKey, tag) resolver := NewDependencyResolver() @@ -690,13 +697,14 @@ func TestResolveGeoTagExistsWithinExtGeoTags(t *testing.T) { for _, arr := range [][]string{{"good-tag"}, {"us-east1", "eu"}} { expected := predefinedConfig expected.ClusterGeoTag = tag - expected.ExtClustersGeoTags = arr + expected.extClustersGeoTags = arr configureEnvVar(expected) os.Setenv(ExtClustersGeoTagsKey, strings.Join(append(arr, tag), ",")) // act,assert resolver := NewDependencyResolver() // act config, err := resolver.ResolveOperatorConfig() + config.DelegationZones = nil // assert assert.NoError(t, err) assert.Equal(t, expected, *config) @@ -707,7 +715,7 @@ func TestResolveGeoTagWithRepeatingExtGeoTags(t *testing.T) { // arrange defer cleanup() expected := predefinedConfig - expected.ExtClustersGeoTags = []string{"foo", "blah", "foo"} + expected.extClustersGeoTags = []string{"foo", "blah", "foo"} // act,assert arrangeVariablesAndAssert(t, expected, assert.Error) } @@ -1160,10 +1168,10 @@ func TestNsServerNamesWithMultipleExtClusterGeoTag(t *testing.T) { // arrange defer cleanup() customConfig := predefinedConfig - customConfig.DNSZone = defaultDNSZone - customConfig.EdgeDNSZone = defaultEdgeDNSZone + customConfig.dnsZone = defaultDNSZone + customConfig.edgeDNSZone = defaultEdgeDNSZone customConfig.ClusterGeoTag = defaultClusterGeoTagUs1 - customConfig.ExtClustersGeoTags = []string{defaultClusterGeoTagUs2, defaultClusterGeoTagEu} + customConfig.extClustersGeoTags = []string{defaultClusterGeoTagUs2, defaultClusterGeoTagEu} configureEnvVar(customConfig) resolver := NewDependencyResolver() @@ -1172,11 +1180,11 @@ func TestNsServerNamesWithMultipleExtClusterGeoTag(t *testing.T) { // assert assert.NoError(t, err) - assert.Len(t, config.GetExternalClusterNSNames(), 2) - assert.Equal(t, "gslb-ns-us-west-1-k8gb-test-preprod-gslb.cloud.example.com", config.GetClusterNSName()) + assert.Len(t, config.getExternalClusterNSNames(), 2) + assert.Equal(t, "gslb-ns-us-west-1-k8gb-test-preprod-gslb.cloud.example.com", config.getClusterNSName()) for k, v := range map[string]string{defaultClusterGeoTagUs2: "gslb-ns-us-east-1-k8gb-test-preprod-gslb.cloud.example.com", defaultClusterGeoTagEu: "gslb-ns-eu-central-1-k8gb-test-preprod-gslb.cloud.example.com"} { - assert.Equal(t, config.GetExternalClusterNSNames()[k], v) + assert.Equal(t, config.getExternalClusterNSNames()[k], v) } } @@ -1197,8 +1205,8 @@ func TestNsServerNamesForLocalEdgeDNS(t *testing.T) { config, err := resolver.ResolveOperatorConfig() // assert assert.NoError(t, err) - assert.Equal(t, config.GetClusterNSName(), edgeDNSServer) - assert.True(t, reflect.DeepEqual(config.GetExternalClusterNSNames(), map[string]string{"za": edgeDNSServer, "eu": edgeDNSServer})) + assert.Equal(t, config.getClusterNSName(), edgeDNSServer) + assert.True(t, reflect.DeepEqual(config.getExternalClusterNSNames(), map[string]string{"za": edgeDNSServer, "eu": edgeDNSServer})) } } @@ -1206,10 +1214,10 @@ func TestNsServerNamesWithOneExtClusterGeoTag(t *testing.T) { // arrange defer cleanup() customConfig := predefinedConfig - customConfig.DNSZone = defaultDNSZone - customConfig.EdgeDNSZone = defaultEdgeDNSZone + customConfig.dnsZone = defaultDNSZone + customConfig.edgeDNSZone = defaultEdgeDNSZone customConfig.ClusterGeoTag = defaultClusterGeoTagUs1 - customConfig.ExtClustersGeoTags = []string{"location-2"} + customConfig.extClustersGeoTags = []string{"location-2"} configureEnvVar(customConfig) resolver := NewDependencyResolver() @@ -1218,19 +1226,19 @@ func TestNsServerNamesWithOneExtClusterGeoTag(t *testing.T) { // assert assert.NoError(t, err) - assert.Len(t, config.GetExternalClusterNSNames(), 1) - assert.Equal(t, "gslb-ns-us-west-1-k8gb-test-preprod-gslb.cloud.example.com", config.GetClusterNSName()) - assert.Equal(t, config.GetExternalClusterNSNames()["location-2"], "gslb-ns-location-2-k8gb-test-preprod-gslb.cloud.example.com") + assert.Len(t, config.getExternalClusterNSNames(), 1) + assert.Equal(t, "gslb-ns-us-west-1-k8gb-test-preprod-gslb.cloud.example.com", config.getClusterNSName()) + assert.Equal(t, config.getExternalClusterNSNames()["location-2"], "gslb-ns-location-2-k8gb-test-preprod-gslb.cloud.example.com") } func TestNsServerNamesWithExtClusterGeoTagsContainingClusterGeoTag(t *testing.T) { // arrange defer cleanup() customConfig := predefinedConfig - customConfig.DNSZone = defaultDNSZone - customConfig.EdgeDNSZone = defaultEdgeDNSZone + customConfig.dnsZone = defaultDNSZone + customConfig.edgeDNSZone = defaultEdgeDNSZone customConfig.ClusterGeoTag = defaultClusterGeoTagUs1 - customConfig.ExtClustersGeoTags = []string{"location-2", defaultClusterGeoTagUs1} + customConfig.extClustersGeoTags = []string{"location-2", defaultClusterGeoTagUs1} configureEnvVar(customConfig) resolver := NewDependencyResolver() @@ -1239,17 +1247,17 @@ func TestNsServerNamesWithExtClusterGeoTagsContainingClusterGeoTag(t *testing.T) // assert assert.NoError(t, err) - assert.Len(t, config.GetExternalClusterNSNames(), 1) - assert.Equal(t, "gslb-ns-us-west-1-k8gb-test-preprod-gslb.cloud.example.com", config.GetClusterNSName()) - assert.Equal(t, config.GetExternalClusterNSNames()["location-2"], "gslb-ns-location-2-k8gb-test-preprod-gslb.cloud.example.com") + assert.Len(t, config.getExternalClusterNSNames(), 1) + assert.Equal(t, "gslb-ns-us-west-1-k8gb-test-preprod-gslb.cloud.example.com", config.getClusterNSName()) + assert.Equal(t, config.getExternalClusterNSNames()["location-2"], "gslb-ns-location-2-k8gb-test-preprod-gslb.cloud.example.com") } func TestNsServerNamesLargeDNSZone(t *testing.T) { defer cleanup() - // arrange DNSZone exceeds + // arrange dnsZone exceeds customConfig := predefinedConfig - customConfig.DNSZone = "k8gb-test-preprod-lorem-ipsum-donor-blah-blah-blah.gslb.cloud.example.com" - customConfig.EdgeDNSZone = defaultEdgeDNSZone + customConfig.dnsZone = "k8gb-test-preprod-lorem-ipsum-donor-blah-blah-blah.gslb.cloud.example.com" + customConfig.edgeDNSZone = defaultEdgeDNSZone customConfig.ClusterGeoTag = "us" configureEnvVar(customConfig) resolver := NewDependencyResolver() @@ -1259,8 +1267,8 @@ func TestNsServerNamesLargeDNSZone(t *testing.T) { // assert assert.Error(t, err) - assert.Equal(t, "gslb-ns-us-k8gb-test-preprod-lorem-ipsum-donor-blah-blah-blah-gslb.cloud.example.com", config.GetClusterNSName()) - extNsNames := config.GetExternalClusterNSNames() + assert.Equal(t, "gslb-ns-us-k8gb-test-preprod-lorem-ipsum-donor-blah-blah-blah-gslb.cloud.example.com", config.getClusterNSName()) + extNsNames := config.getExternalClusterNSNames() expectedExtNsNames := map[string]string{"za": "gslb-ns-za-k8gb-test-preprod-lorem-ipsum-donor-blah-blah-blah-gslb.cloud.example.com", "eu": "gslb-ns-eu-k8gb-test-preprod-lorem-ipsum-donor-blah-blah-blah-gslb.cloud.example.com"} assert.True(t, reflect.DeepEqual(extNsNames, expectedExtNsNames), "maps must be equal: \n %v\n %v", extNsNames, expectedExtNsNames) @@ -1271,12 +1279,12 @@ func TestNsServerNamesWithLargeExtClusterGeoTag(t *testing.T) { defer cleanup() // arrange customConfig := predefinedConfig - customConfig.DNSZone = defaultDNSZone - customConfig.EdgeDNSZone = defaultEdgeDNSZone + customConfig.dnsZone = defaultDNSZone + customConfig.edgeDNSZone = defaultEdgeDNSZone customConfig.ClusterGeoTag = "us" - customConfig.ExtClustersGeoTags = []string{} - customConfig.ExtClustersGeoTags = append(customConfig.ExtClustersGeoTags, predefinedConfig.ExtClustersGeoTags...) - customConfig.ExtClustersGeoTags[0] = largeGeoTag + customConfig.extClustersGeoTags = []string{} + customConfig.extClustersGeoTags = append(customConfig.extClustersGeoTags, predefinedConfig.extClustersGeoTags...) + customConfig.extClustersGeoTags[0] = largeGeoTag configureEnvVar(customConfig) resolver := NewDependencyResolver() @@ -1285,8 +1293,8 @@ func TestNsServerNamesWithLargeExtClusterGeoTag(t *testing.T) { // assert assert.Error(t, err) - assert.Equal(t, "gslb-ns-us-k8gb-test-preprod-gslb.cloud.example.com", config.GetClusterNSName()) - extNsNames := config.GetExternalClusterNSNames() + assert.Equal(t, "gslb-ns-us-k8gb-test-preprod-gslb.cloud.example.com", config.getClusterNSName()) + extNsNames := config.getExternalClusterNSNames() expectedExtNsNames := map[string]string{largeGeoTag: "gslb-ns-za-lorem-ipsum-donor-b-blah-lorem-k8gb-test-preprod-gslb.cloud.example.com", "eu": "gslb-ns-eu-k8gb-test-preprod-gslb.cloud.example.com"} assert.True(t, reflect.DeepEqual(extNsNames, expectedExtNsNames), "maps must be equal: \n %v\n %v", extNsNames, expectedExtNsNames) @@ -1297,8 +1305,8 @@ func TestNsServerNamesWithLargeClusterGeoTag(t *testing.T) { defer cleanup() // arrange customConfig := predefinedConfig - customConfig.DNSZone = defaultDNSZone - customConfig.EdgeDNSZone = defaultEdgeDNSZone + customConfig.dnsZone = defaultDNSZone + customConfig.edgeDNSZone = defaultEdgeDNSZone customConfig.ClusterGeoTag = "us-lorem-ipsum-donor-blah-blah-blah-blah" configureEnvVar(customConfig) resolver := NewDependencyResolver() @@ -1308,8 +1316,8 @@ func TestNsServerNamesWithLargeClusterGeoTag(t *testing.T) { // assert assert.Error(t, err) - assert.Equal(t, "gslb-ns-us-lorem-ipsum-donor-blah-blah-blah-blah-k8gb-test-preprod-gslb.cloud.example.com", config.GetClusterNSName()) - extNsNames := config.GetExternalClusterNSNames() + assert.Equal(t, "gslb-ns-us-lorem-ipsum-donor-blah-blah-blah-blah-k8gb-test-preprod-gslb.cloud.example.com", config.getClusterNSName()) + extNsNames := config.getExternalClusterNSNames() expectedExtNsNames := map[string]string{"za": "gslb-ns-za-k8gb-test-preprod-gslb.cloud.example.com", "eu": "gslb-ns-eu-k8gb-test-preprod-gslb.cloud.example.com"} assert.True(t, reflect.DeepEqual(extNsNames, expectedExtNsNames), "maps must be equal: \n %v\n %v", extNsNames, expectedExtNsNames) @@ -1320,19 +1328,19 @@ func TestNsServerNamesWithExceededDNSNameSize(t *testing.T) { // arrange defer cleanup() customConfig := predefinedConfig - customConfig.EdgeDNSZone = "seo.cloud.example01.lorem.ipsum.alfa.bravo.charlie.delta.echo.foxtrot.golf.hotel.india." + + customConfig.edgeDNSZone = "seo.cloud.example01.lorem.ipsum.alfa.bravo.charlie.delta.echo.foxtrot.golf.hotel.india." + "juliett.kilo.lima.mike.november.oscar.papa.quebec.romeo.sierra.tango.uniform.victor.whiskey.x-ray.yenkee.zulu." + "zero.cloud.example.com" - customConfig.DNSZone = "k8gb-test-preprod.gslb." + customConfig.EdgeDNSZone + customConfig.dnsZone = "k8gb-test-preprod.gslb." + customConfig.edgeDNSZone configureEnvVar(customConfig) resolver := NewDependencyResolver() // act config, err := resolver.ResolveOperatorConfig() // assert assert.NoError(t, err) - assert.Len(t, config.GetClusterNSName(), 253) - assert.Len(t, config.GetExternalClusterNSNames()[customConfig.ExtClustersGeoTags[0]], 253) - assert.Len(t, config.GetExternalClusterNSNames()[customConfig.ExtClustersGeoTags[1]], 253) + assert.Len(t, config.getClusterNSName(), 253) + assert.Len(t, config.getExternalClusterNSNames()[customConfig.extClustersGeoTags[0]], 253) + assert.Len(t, config.getExternalClusterNSNames()[customConfig.extClustersGeoTags[1]], 253) // arrange // extend cluster geo tag with one character so NsServerName exceeds length limit @@ -1343,9 +1351,9 @@ func TestNsServerNamesWithExceededDNSNameSize(t *testing.T) { config, err = resolver.ResolveOperatorConfig() // assert assert.Error(t, err) - assert.Len(t, config.GetClusterNSName(), 254) - assert.Len(t, config.GetExternalClusterNSNames()[customConfig.ExtClustersGeoTags[0]], 253) - assert.Len(t, config.GetExternalClusterNSNames()[customConfig.ExtClustersGeoTags[1]], 253) + assert.Len(t, config.getClusterNSName(), 254) + assert.Len(t, config.getExternalClusterNSNames()[customConfig.extClustersGeoTags[0]], 253) + assert.Len(t, config.getExternalClusterNSNames()[customConfig.extClustersGeoTags[1]], 253) } func TestMetricsAddressIsValid(t *testing.T) { @@ -1433,6 +1441,7 @@ func arrangeVariablesAndAssert(t *testing.T, expected Config, if config == nil { t.Fatal("nil *config returned") } + config.DelegationZones = nil assert.Equal(t, expected, *config) errf(t, err) } @@ -1442,7 +1451,7 @@ func cleanup() { EdgeDNSServersKey, ExtDNSEnabledKey, InfobloxGridHostKey, InfobloxVersionKey, InfobloxPortKey, InfobloxUsernameKey, InfobloxPasswordKey, K8gbNamespaceKey, CoreDNSExposedKey, InfobloxHTTPRequestTimeoutKey, InfobloxHTTPPoolConnectionsKey, LogLevelKey, LogFormatKey, LogNoColorKey, MetricsAddressKey, TracingEnabled, - TracingSamplingRatio, OtelExporterOtlpEndpoint} { + TracingSamplingRatio, OtelExporterOtlpEndpoint, DNSZonesKey} { if os.Unsetenv(s) != nil { panic(fmt.Errorf("cleanup %s", s)) } @@ -1455,10 +1464,10 @@ func configureEnvVar(config Config) { _ = os.Setenv(ReconcileRequeueSecondsKey, strconv.Itoa(config.ReconcileRequeueSeconds)) _ = os.Setenv(NSRecordTTLKey, strconv.Itoa(config.NSRecordTTL)) _ = os.Setenv(ClusterGeoTagKey, config.ClusterGeoTag) - _ = os.Setenv(ExtClustersGeoTagsKey, strings.Join(config.ExtClustersGeoTags, ",")) + _ = os.Setenv(ExtClustersGeoTagsKey, strings.Join(config.extClustersGeoTags, ",")) _ = os.Setenv(EdgeDNSServersKey, config.EdgeDNSServers.String()) - _ = os.Setenv(EdgeDNSZoneKey, config.EdgeDNSZone) - _ = os.Setenv(DNSZoneKey, config.DNSZone) + _ = os.Setenv(EdgeDNSZoneKey, config.edgeDNSZone) + _ = os.Setenv(DNSZoneKey, config.dnsZone) _ = os.Setenv(K8gbNamespaceKey, config.K8gbNamespace) _ = os.Setenv(ExtDNSEnabledKey, strconv.FormatBool(config.extDNSEnabled)) _ = os.Setenv(CoreDNSExposedKey, strconv.FormatBool(config.CoreDNSExposed)) @@ -1476,6 +1485,7 @@ func configureEnvVar(config Config) { _ = os.Setenv(TracingEnabled, strconv.FormatBool(config.TracingEnabled)) _ = os.Setenv(TracingSamplingRatio, strconv.FormatFloat(config.TracingSamplingRatio, 'f', 2, 64)) _ = os.Setenv(OtelExporterOtlpEndpoint, config.OtelExporterOtlpEndpoint) + _ = os.Setenv(DNSZonesKey, config.dnsZones) } func getTestContext(testData string) (client.Client, *k8gbv1beta1.Gslb) { @@ -1499,3 +1509,173 @@ func getTestContext(testData string) (client.Client, *k8gbv1beta1.Gslb) { cl := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build() return cl, gslb } + +//nolint:goconst +func TestParseDNSZones(t *testing.T) { + contains := func(dzi []DelegationZoneInfo, compare func(info DelegationZoneInfo) bool) bool { + for _, v := range dzi { + if compare(v) { + return true + } + } + return false + } + tests := []struct { + name string + expectedLen int + config *Config + assert func(zoneInfo []DelegationZoneInfo) + }{ + { + name: "multiple zones", + config: &Config{ + dnsZones: "example.com:cloud.example.com;example.io:cloud.example.io", + edgeDNSZone: "example.org", + dnsZone: "cloud.example.org", + EdgeDNSServers: []utils2.DNSServer{{Host: "edge.com", Port: 53}}, + ClusterGeoTag: "us", + extClustersGeoTags: []string{"za", "eu"}, + }, + expectedLen: 3, + assert: func(zoneInfo []DelegationZoneInfo) { + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.com" && info.Domain == "cloud.example.com" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.io" && info.Domain == "cloud.example.io" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.org" && info.Domain == "cloud.example.org" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.ClusterNSName == "gslb-ns-us-cloud.example.com" && + info.GetNSServerList()[0] == "gslb-ns-eu-cloud.example.com" && + info.GetNSServerList()[1] == "gslb-ns-us-cloud.example.com" && + info.GetNSServerList()[2] == "gslb-ns-za-cloud.example.com" && + info.GetExternalDNSEndpointName() == "k8gb-ns-extdns-cloud-example-com" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.ClusterNSName == "gslb-ns-us-cloud.example.org" && + info.GetNSServerList()[0] == "gslb-ns-eu-cloud.example.org" && + info.GetNSServerList()[1] == "gslb-ns-us-cloud.example.org" && + info.GetNSServerList()[2] == "gslb-ns-za-cloud.example.org" && + info.GetExternalDNSEndpointName() == "k8gb-ns-extdns-cloud-example-org" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.ClusterNSName == "gslb-ns-us-cloud.example.io" && + info.GetNSServerList()[0] == "gslb-ns-eu-cloud.example.io" && + info.GetNSServerList()[1] == "gslb-ns-us-cloud.example.io" && + info.GetNSServerList()[2] == "gslb-ns-za-cloud.example.io" && + info.GetExternalDNSEndpointName() == "k8gb-ns-extdns-cloud-example-io" + })) + }, + }, + { + name: "backward compatibility", + config: &Config{ + dnsZones: "", + edgeDNSZone: "example.org", + dnsZone: "cloud.example.org", + EdgeDNSServers: []utils2.DNSServer{{Host: "edge.com", Port: 53}}, + ClusterGeoTag: "us", + extClustersGeoTags: []string{"za", "eu"}, + }, + expectedLen: 1, + assert: func(zoneInfo []DelegationZoneInfo) { + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.org" && info.Domain == "cloud.example.org" + })) + }, + }, + { + name: "override", + config: &Config{ + dnsZones: "example.com:cloud.example.com;example.io:cloud.example.io", + edgeDNSZone: "example.com", + dnsZone: "dc.example.com", + EdgeDNSServers: []utils2.DNSServer{{Host: "edge.com", Port: 53}}, + ClusterGeoTag: "us", + extClustersGeoTags: []string{"za", "eu"}, + }, + expectedLen: 2, + assert: func(zoneInfo []DelegationZoneInfo) { + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.com" && info.Domain == "cloud.example.com" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.io" && info.Domain == "cloud.example.io" + })) + }, + }, + { + name: "ends with semicolon", + config: &Config{ + dnsZones: "example.com:cloud.example.com;example.io:cloud.example.io;", + edgeDNSZone: "example.org", + dnsZone: "cloud.example.org", + EdgeDNSServers: []utils2.DNSServer{{Host: "edge.com", Port: 53}}, + ClusterGeoTag: "us", + extClustersGeoTags: []string{"za", "eu"}, + }, + expectedLen: 3, + assert: func(zoneInfo []DelegationZoneInfo) { + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.com" && info.Domain == "cloud.example.com" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.io" && info.Domain == "cloud.example.io" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.org" && info.Domain == "cloud.example.org" + })) + }, + }, + { + name: "trimmed spaces and semicolons", + config: &Config{ + dnsZones: "example.com: cloud.example.com; example.io:cloud.example.io ;", + edgeDNSZone: "example.org", + dnsZone: "cloud.example.org", + EdgeDNSServers: []utils2.DNSServer{{Host: "edge.com", Port: 53}}, + ClusterGeoTag: "us", + extClustersGeoTags: []string{"za", "eu"}, + }, + expectedLen: 3, + assert: func(zoneInfo []DelegationZoneInfo) { + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.com" && info.Domain == "cloud.example.com" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.io" && info.Domain == "cloud.example.io" + })) + assert.True(t, contains(zoneInfo, func(info DelegationZoneInfo) bool { + return info.Zone == "example.org" && info.Domain == "cloud.example.org" + })) + }, + }, + { + name: "check nsNames", + config: &Config{ + dnsZones: "cloud.example.com: k8gb-test.gslb.cloud.example.com;", + edgeDNSZone: "", + dnsZone: "", + EdgeDNSServers: []utils2.DNSServer{{Host: "edge.com", Port: 53}}, + ClusterGeoTag: "us", + extClustersGeoTags: []string{"za", "eu"}, + }, + expectedLen: 1, + assert: func(zoneInfo []DelegationZoneInfo) { + assert.True(t, zoneInfo[0].ClusterNSName == "gslb-ns-us-k8gb-test-gslb.cloud.example.com" && + zoneInfo[0].ExtClusterNSNames["za"] == "gslb-ns-za-k8gb-test-gslb.cloud.example.com" && + zoneInfo[0].ExtClusterNSNames["eu"] == "gslb-ns-eu-k8gb-test-gslb.cloud.example.com") + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + zoneInfo := parseDelegationZones(test.config) + test.assert(zoneInfo) + assert.Equal(t, test.expectedLen, len(zoneInfo)) + }) + } +} diff --git a/controllers/dnsupdate.go b/controllers/dnsupdate.go index 9099dcbb81..33815c341e 100644 --- a/controllers/dnsupdate.go +++ b/controllers/dnsupdate.go @@ -21,7 +21,6 @@ Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic import ( "context" "fmt" - "strings" "github.com/k8gb-io/k8gb/controllers/depresolver" "github.com/k8gb-io/k8gb/controllers/providers/assistant" @@ -43,8 +42,8 @@ func (r *GslbReconciler) gslbDNSEndpoint(gslb *k8gbv1beta1.Gslb) (*externaldns.D for host, health := range gslb.Status.ServiceHealth { var finalTargets = assistant.NewTargets() - if !strings.Contains(host, r.Config.EdgeDNSZone) { - return nil, fmt.Errorf("ingress host %s does not match delegated zone %s", host, r.Config.EdgeDNSZone) + if !r.Config.DelegationZones.ContainsZone(host) { + return nil, fmt.Errorf("ingress host %s does not match delegated zone %v", host, r.Config.DelegationZones.ListZones()) } isPrimary := gslb.Spec.Strategy.PrimaryGeoTag == r.Config.ClusterGeoTag diff --git a/controllers/gslb_controller_reconciliation_test.go b/controllers/gslb_controller_reconciliation_test.go index 79980aee9b..386d81accd 100644 --- a/controllers/gslb_controller_reconciliation_test.go +++ b/controllers/gslb_controller_reconciliation_test.go @@ -75,16 +75,21 @@ var crSampleYaml = "../deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingr var predefinedConfig = depresolver.Config{ ReconcileRequeueSeconds: 30, NSRecordTTL: 30, - ClusterGeoTag: "us-west-1", - ExtClustersGeoTags: []string{"us-east-1"}, + ClusterGeoTag: "us", EdgeDNSServers: []utils.DNSServer{ { Host: "127.0.0.1", Port: 7753, }, }, - EdgeDNSZone: "example.com", - DNSZone: "cloud.example.com", + DelegationZones: []depresolver.DelegationZoneInfo{ + { + Domain: "cloud.example.com", + Zone: "example.com", + ClusterNSName: "localhost", + ExtClusterNSNames: map[string]string{"eu": "localhost"}, + }, + }, K8gbNamespace: "k8gb", Infoblox: depresolver.Infoblox{ Host: "fakeinfoblox.example.com", @@ -698,7 +703,7 @@ func TestReturnsExternalRecordsUsingFailoverStrategy(t *testing.T) { // enable failover strategy settings.gslb.Spec.Strategy.Type = depresolver.FailoverStrategy - settings.gslb.Spec.Strategy.PrimaryGeoTag = "us-east-1" + settings.gslb.Spec.Strategy.PrimaryGeoTag = "eu" err = settings.client.Update(context.TODO(), settings.gslb) require.NoError(t, err, "Can't update gslb") @@ -771,7 +776,7 @@ func TestReturnsExternalRecordsUsingFailoverStrategyAndFallbackDNSserver(t *test // enable failover strategy settings.gslb.Spec.Strategy.Type = depresolver.FailoverStrategy - settings.gslb.Spec.Strategy.PrimaryGeoTag = "us-east-1" + settings.gslb.Spec.Strategy.PrimaryGeoTag = "eu" err = settings.client.Update(context.TODO(), settings.gslb) require.NoError(t, err, "Can't update gslb") @@ -816,7 +821,7 @@ func TestReflectGeoTagInStatusAsUnsetByDefault(t *testing.T) { Start(). RunTestFunc(func() { // arrange - want := "us-west-1" + want := "us" settings := provideSettings(t, predefinedConfig) // act reconcileAndUpdateGslb(t, settings) @@ -851,7 +856,12 @@ func TestDetectsIngressHostnameMismatch(t *testing.T) { // getting Gslb and Reconciler predefinedSettings := provideSettings(t, predefinedConfig) customConfig := predefinedConfig - customConfig.EdgeDNSZone = "otherdnszone.com" + customConfig.DelegationZones = depresolver.DelegationZones{ + { + Domain: "cloud.example.com", + Zone: "otherdnszone.com", + }, + } predefinedSettings.config = customConfig req := reconcile.Request{ NamespacedName: types.NamespacedName{ @@ -865,7 +875,7 @@ func TestDetectsIngressHostnameMismatch(t *testing.T) { _, err := predefinedSettings.reconciler.Reconcile(context.TODO(), req) // assert assert.Error(t, err, "expected controller to detect Ingress hostname and edgeDNSZone mismatch") - assert.True(t, strings.HasSuffix(err.Error(), "cloud.example.com does not match delegated zone otherdnszone.com")) + assert.True(t, strings.HasSuffix(err.Error(), "cloud.example.com does not match delegated zone [otherdnszone.com]")) }) } @@ -923,8 +933,14 @@ func TestCreatesDNSNSRecordsForExtDNS(t *testing.T) { // act customConfig.EdgeDNSType = depresolver.DNSTypeExternal customConfig.ClusterGeoTag = "eu" - customConfig.ExtClustersGeoTags = []string{"za", "us"} - customConfig.DNSZone = dnsZone + customConfig.DelegationZones = depresolver.DelegationZones{ + { + Domain: dnsZone, + Zone: "example.com", + ClusterNSName: "gslb-ns-eu-cloud.example.com", + ExtClusterNSNames: map[string]string{"us": "gslb-ns-us-cloud.example.com", "za": "gslb-ns-za-cloud.example.com"}, + }, + } // apply new environment variables and update config only settings.reconciler.Config = &customConfig // If config is changed, new Route53 provider needs to be re-created. There is no way and reason to change provider @@ -933,7 +949,10 @@ func TestCreatesDNSNSRecordsForExtDNS(t *testing.T) { settings.reconciler.DNSProvider = f.Provider() reconcileAndUpdateGslb(t, settings) - err = settings.client.Get(context.TODO(), client.ObjectKey{Namespace: predefinedConfig.K8gbNamespace, Name: "k8gb-ns-extdns"}, dnsEndpoint) + err = settings.client.Get( + context.TODO(), + client.ObjectKey{Namespace: predefinedConfig.K8gbNamespace, Name: "k8gb-ns-extdns-cloud-example-com"}, + dnsEndpoint) require.NoError(t, err, "Failed to get expected DNSEndpoint") got := dnsEndpoint.Annotations["k8gb.absa.oss/dnstype"] gotEp := dnsEndpoint.Spec.Endpoints @@ -999,8 +1018,14 @@ func TestCreatesDNSNSRecordsForLoadBalancer(t *testing.T) { // act customConfig.EdgeDNSType = depresolver.DNSTypeExternal customConfig.ClusterGeoTag = "eu" - customConfig.ExtClustersGeoTags = []string{"za", "us"} - customConfig.DNSZone = dnsZone + customConfig.DelegationZones = depresolver.DelegationZones{ + { + Domain: dnsZone, + Zone: "example.com", + ClusterNSName: "gslb-ns-eu-cloud.example.com", + ExtClusterNSNames: map[string]string{"eu": "gslb-ns-us-cloud.example.com", "za": "gslb-ns-za-cloud.example.com"}, + }, + } // apply new environment variables and update config only settings.reconciler.Config = &customConfig // If config is changed, new Route53 provider needs to be re-created. There is no way and reason to change provider @@ -1009,7 +1034,10 @@ func TestCreatesDNSNSRecordsForLoadBalancer(t *testing.T) { settings.reconciler.DNSProvider = f.Provider() reconcileAndUpdateGslb(t, settings) - err = settings.client.Get(context.TODO(), client.ObjectKey{Namespace: predefinedConfig.K8gbNamespace, Name: "k8gb-ns-extdns"}, dnsEndpoint) + err = settings.client.Get( + context.TODO(), + client.ObjectKey{Namespace: predefinedConfig.K8gbNamespace, Name: "k8gb-ns-extdns-cloud-example-com"}, + dnsEndpoint) require.NoError(t, err, "Failed to get expected DNSEndpoint") got := dnsEndpoint.Annotations["k8gb.absa.oss/dnstype"] gotEp := dnsEndpoint.Spec.Endpoints @@ -1434,7 +1462,7 @@ func provideSettings(t *testing.T, expected depresolver.Config) (settings testSe t.Fatalf("reconcile: (%v)", err) } r.DNSProvider = f.Provider() - a := assistant.NewGslbAssistant(r.Client, r.Config.K8gbNamespace, r.Config.EdgeDNSServers) + a := assistant.NewGslbAssistant(r.Client, r.Config.K8gbNamespace, *r.Config) res, err := r.Reconcile(context.TODO(), req) if err != nil { t.Fatalf("reconcile: (%v)", err) diff --git a/controllers/gslb_controller_weight_test.go b/controllers/gslb_controller_weight_test.go index d496e9a2a8..a497648d45 100644 --- a/controllers/gslb_controller_weight_test.go +++ b/controllers/gslb_controller_weight_test.go @@ -183,8 +183,8 @@ func TestWeight(t *testing.T) { m.EXPECT().GetExternalTargets("roundrobin.cloud.example.com").Return(ts).Times(1) m.EXPECT().GetExternalTargets("notfound.cloud.example.com").Return(assistant.Targets{}).Times(1) m.EXPECT().GetExternalTargets("unhealthy.cloud.example.com").Return(assistant.Targets{}).Times(1) - - settings := provideSettings(t, predefinedConfig) + config := predefinedConfig + settings := provideSettings(t, config) settings.reconciler.DNSProvider = m settings.reconciler.DepResolver = r diff --git a/controllers/providers/assistant/gslb.go b/controllers/providers/assistant/gslb.go index 53f854ac0f..09fe32bc98 100644 --- a/controllers/providers/assistant/gslb.go +++ b/controllers/providers/assistant/gslb.go @@ -23,6 +23,8 @@ import ( coreerrors "errors" "fmt" + "github.com/k8gb-io/k8gb/controllers/depresolver" + "github.com/k8gb-io/k8gb/controllers/utils" "github.com/k8gb-io/k8gb/controllers/logging" @@ -41,18 +43,18 @@ const coreDNSServiceLabel = "app.kubernetes.io/name=coredns" // Gslb is common wrapper operating on GSLB instance. // It uses apimachinery client to call kubernetes API type Gslb struct { - client client.Client - k8gbNamespace string - edgeDNSServers utils.DNSList + client client.Client + k8gbNamespace string + config depresolver.Config } var log = logging.Logger() -func NewGslbAssistant(client client.Client, k8gbNamespace string, edgeDNSServers []utils.DNSServer) *Gslb { +func NewGslbAssistant(client client.Client, k8gbNamespace string, config depresolver.Config) *Gslb { return &Gslb{ - client: client, - k8gbNamespace: k8gbNamespace, - edgeDNSServers: edgeDNSServers, + client: client, + k8gbNamespace: k8gbNamespace, + config: config, } } @@ -107,7 +109,6 @@ func (r *Gslb) CoreDNSExposedIPs() ([]string, error) { return coreDNSService.Spec.ClusterIPs, nil } // LoadBalancer / ExternalName / NodePort service - var lb corev1.LoadBalancerIngress if len(coreDNSService.Status.LoadBalancer.Ingress) == 0 { errMessage := "no LoadBalancer ExternalIPs are found" log.Warn(). @@ -116,8 +117,17 @@ func (r *Gslb) CoreDNSExposedIPs() ([]string, error) { err := coreerrors.New(errMessage) return nil, err } - lb = coreDNSService.Status.LoadBalancer.Ingress[0] - return extractIPFromLB(lb, r.edgeDNSServers) + + var ipList []string + for _, ingressStatusIP := range coreDNSService.Status.LoadBalancer.Ingress { + var confirmedIPs, err = extractIPFromLB(ingressStatusIP, r.config.EdgeDNSServers) + if err != nil { + return nil, err + } + ipList = append(ipList, confirmedIPs...) + } + return ipList, nil + } func extractIPFromLB(lb corev1.LoadBalancerIngress, ns utils.DNSList) (ips []string, err error) { @@ -239,13 +249,13 @@ func (r *Gslb) GetExternalTargets(host string, extClusterNsNames map[string]stri log.Info(). Str("cluster", cluster). Msg("Adding external Gslb targets from cluster") - glueA, err := dnsQuery(cluster, r.edgeDNSServers) + glueA, err := dnsQuery(cluster, r.config.EdgeDNSServers) if err != nil { return targets } log.Info(). Str("nameserver", cluster). - Interface("edgeDNSServers", r.edgeDNSServers). + Interface("edgeDNSServers", r.config.EdgeDNSServers). Interface("glueARecord", glueA.Answer). Msg("Resolved glue A record for NS") glueARecords := getARecords(glueA) @@ -255,7 +265,7 @@ func (r *Gslb) GetExternalTargets(host string, extClusterNsNames map[string]stri } else { hostToUse = cluster } - nameServersToUse := getNSCombinations(r.edgeDNSServers, hostToUse) + nameServersToUse := getNSCombinations(r.config.EdgeDNSServers, hostToUse) lHost := fmt.Sprintf("localtargets-%s", host) a, err := dnsQuery(lHost, nameServersToUse) if err != nil { diff --git a/controllers/providers/dns/empty.go b/controllers/providers/dns/empty.go index 298c670b96..4093e92068 100644 --- a/controllers/providers/dns/empty.go +++ b/controllers/providers/dns/empty.go @@ -44,7 +44,7 @@ func (p *EmptyDNSProvider) CreateZoneDelegationForExternalDNS(*k8gbv1beta1.Gslb) } func (p *EmptyDNSProvider) GetExternalTargets(host string) (targets assistant.Targets) { - return p.assistant.GetExternalTargets(host, p.config.GetExternalClusterNSNames()) + return p.assistant.GetExternalTargets(host, p.config.DelegationZones.GetExternalClusterNSNamesByHostname(host)) } func (p *EmptyDNSProvider) SaveDNSEndpoint(gslb *k8gbv1beta1.Gslb, i *externaldns.DNSEndpoint) error { diff --git a/controllers/providers/dns/external.go b/controllers/providers/dns/external.go index b4aa210e58..7d3b2ae549 100644 --- a/controllers/providers/dns/external.go +++ b/controllers/providers/dns/external.go @@ -21,7 +21,6 @@ Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic import ( "context" "fmt" - "sort" "strings" "github.com/k8gb-io/k8gb/controllers/logging" @@ -38,18 +37,16 @@ import ( const externalDNSTypeCommon = "extdns" type ExternalDNSProvider struct { - assistant assistant2.Assistant - config depresolver.Config - endpointName string + assistant assistant2.Assistant + config depresolver.Config } var log = logging.Logger() func NewExternalDNS(config depresolver.Config, assistant assistant2.Assistant) *ExternalDNSProvider { return &ExternalDNSProvider{ - assistant: assistant, - config: config, - endpointName: fmt.Sprintf("k8gb-ns-%s", externalDNSTypeCommon), + assistant: assistant, + config: config, } } @@ -58,11 +55,7 @@ func (p *ExternalDNSProvider) CreateZoneDelegationForExternalDNS(gslb *k8gbv1bet log.Info(). Interface("provider", p). Msg("Creating/Updating DNSEndpoint CRDs") - NSServerList := []string{p.config.GetClusterNSName()} - for _, v := range p.config.GetExternalClusterNSNames() { - NSServerList = append(NSServerList, v) - } - sort.Strings(NSServerList) + var NSServerIPs []string var err error if p.config.CoreDNSExposed { @@ -78,22 +71,27 @@ func (p *ExternalDNSProvider) CreateZoneDelegationForExternalDNS(gslb *k8gbv1bet if err != nil { return err } + + domainInfo := p.config.DelegationZones.FindByGslbStatusHostname(gslb) + if domainInfo == nil { + return fmt.Errorf("domainInfo not found for GSLB: %s. Check if the gslb.Status.Servers[*].Host property matches any of the DNSZones", gslb.Name) + } NSRecord := &externaldns.DNSEndpoint{ ObjectMeta: metav1.ObjectMeta{ - Name: p.endpointName, + Name: domainInfo.GetExternalDNSEndpointName(), Namespace: p.config.K8gbNamespace, Annotations: map[string]string{"k8gb.absa.oss/dnstype": externalDNSTypeCommon}, }, Spec: externaldns.DNSEndpointSpec{ Endpoints: []*externaldns.Endpoint{ { - DNSName: p.config.DNSZone, + DNSName: domainInfo.Domain, RecordTTL: ttl, RecordType: "NS", - Targets: NSServerList, + Targets: domainInfo.GetNSServerList(), }, { - DNSName: p.config.GetClusterNSName(), + DNSName: domainInfo.ClusterNSName, RecordTTL: ttl, RecordType: "A", Targets: NSServerIPs, @@ -121,11 +119,17 @@ func (p *ExternalDNSProvider) Finalize(_ *k8gbv1beta1.Gslb, k8sClient client.Cli return nil } - return p.assistant.RemoveEndpoint(p.endpointName) + for _, domainInfo := range p.config.DelegationZones { + err = p.assistant.RemoveEndpoint(domainInfo.GetExternalDNSEndpointName()) + if err != nil { + return err + } + } + return nil } func (p *ExternalDNSProvider) GetExternalTargets(host string) (targets assistant2.Targets) { - return p.assistant.GetExternalTargets(host, p.config.GetExternalClusterNSNames()) + return p.assistant.GetExternalTargets(host, p.config.DelegationZones.GetExternalClusterNSNamesByHostname(host)) } func (p *ExternalDNSProvider) SaveDNSEndpoint(gslb *k8gbv1beta1.Gslb, i *externaldns.DNSEndpoint) error { diff --git a/controllers/providers/dns/external_test.go b/controllers/providers/dns/external_test.go index e50943cc47..e8f0a54bf4 100644 --- a/controllers/providers/dns/external_test.go +++ b/controllers/providers/dns/external_test.go @@ -61,15 +61,20 @@ var a = struct { ReconcileRequeueSeconds: 30, NSRecordTTL: 30, ClusterGeoTag: "us", - ExtClustersGeoTags: []string{"za", "eu"}, EdgeDNSServers: []utils2.DNSServer{ { Host: "dns.cloud.example.com", Port: 53, }, }, - EdgeDNSZone: "example.com", - DNSZone: "cloud.example.com", + DelegationZones: depresolver.DelegationZones{ + { + Domain: "cloud.example.com", + Zone: "example.com", + ClusterNSName: "gslb-ns-us-cloud.example.com", + ExtClusterNSNames: map[string]string{"eu": "gslb-ns-eu-cloud.example.com", "za": "gslb-ns-za-cloud.example.com"}, + }, + }, K8gbNamespace: "k8gb", }, Gslb: func() *k8gbv1beta1.Gslb { @@ -96,7 +101,7 @@ var expectedDNSEndpoint = &externaldns.DNSEndpoint{ Spec: externaldns.DNSEndpointSpec{ Endpoints: []*externaldns.Endpoint{ { - DNSName: a.Config.DNSZone, + DNSName: a.Config.DelegationZones[0].Domain, RecordTTL: externaldns.TTL(a.Config.NSRecordTTL), RecordType: "NS", Targets: a.TargetNSNamesSorted, @@ -116,19 +121,88 @@ func TestCreateZoneDelegationOnExternalDNS(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := mocks.NewMockAssistant(ctrl) + ep1 := expectedDNSEndpoint.DeepCopy() + ep1.Name = "k8gb-ns-extdns-cloud-example-com" p := NewExternalDNS(a.Config, m) - m.EXPECT().SaveDNSEndpoint(a.Config.K8gbNamespace, gomock.Eq(expectedDNSEndpoint)).Return(nil).Times(1). + m.EXPECT().SaveDNSEndpoint(a.Config.K8gbNamespace, gomock.Eq(ep1)).Return(nil).Times(1). Do(func(ns string, ep *externaldns.DNSEndpoint) { - require.True(t, reflect.DeepEqual(ep, expectedDNSEndpoint)) + require.True(t, reflect.DeepEqual(ep, ep1)) require.Equal(t, ns, a.Config.K8gbNamespace) }) - + gslb := a.Gslb.DeepCopy() + gslb.Status.Servers = []*k8gbv1beta1.Server{ + { + Host: "cloud.example.com", + }, + } // act - err := p.CreateZoneDelegationForExternalDNS(a.Gslb) + err := p.CreateZoneDelegationForExternalDNS(gslb) // assert assert.NoError(t, err) } +func TestCreateZoneDelegationOnExternalDNSWithMultipleEndpoints(t *testing.T) { + // arrange + ctrl := gomock.NewController(t) + defer ctrl.Finish() + m := mocks.NewMockAssistant(ctrl) + di := depresolver.DelegationZoneInfo{ + Domain: "common.sampledomain.com", + Zone: "sampledomain.com", + ClusterNSName: "gslb-ns-us-common.sampledomain.com", + ExtClusterNSNames: map[string]string{"za": "gslb-ns-za-common.sampledomain.com", "eu": "gslb-ns-eu-common.sampledomain.com"}, + } + a.Config.DelegationZones = append(a.Config.DelegationZones, di) + ep1 := expectedDNSEndpoint.DeepCopy() + ep1.Name = "k8gb-ns-extdns-cloud-example-com" + ep2 := expectedDNSEndpoint.DeepCopy() + ep2.Name = "k8gb-ns-extdns-common-sampledomain-com" + ep2.Spec.Endpoints[0].DNSName = "common.sampledomain.com" + ep2.Spec.Endpoints[1].DNSName = "gslb-ns-us-common.sampledomain.com" + ep2.Spec.Endpoints[0].Targets = []string{ + "gslb-ns-eu-common.sampledomain.com", + "gslb-ns-us-common.sampledomain.com", + "gslb-ns-za-common.sampledomain.com", + } + p := NewExternalDNS(a.Config, m) + m.EXPECT().SaveDNSEndpoint(a.Config.K8gbNamespace, gomock.Eq(ep1)).Return(nil).Times(1). + Do(func(ns string, ep *externaldns.DNSEndpoint) { + require.True(t, reflect.DeepEqual(ep, ep1)) + require.Equal(t, ns, a.Config.K8gbNamespace) + }) + + m.EXPECT().SaveDNSEndpoint(a.Config.K8gbNamespace, gomock.Eq(ep2)).Return(nil).Times(1). + Do(func(ns string, ep *externaldns.DNSEndpoint) { + require.True(t, reflect.DeepEqual(ep, ep2)) + require.Equal(t, ns, a.Config.K8gbNamespace) + }) + gslb1 := a.Gslb.DeepCopy() + gslb1.Status.Servers = []*k8gbv1beta1.Server{ + { + Host: "cloud.example.com", + }, + } + gslb2 := a.Gslb.DeepCopy() + gslb2.Status.Servers = []*k8gbv1beta1.Server{ + { + Host: "common.sampledomain.com", + }, + } + gslb3 := a.Gslb.DeepCopy() + gslb3.Status.Servers = []*k8gbv1beta1.Server{ + { + Host: "common.dummy.com", + }, + } + // act + err := p.CreateZoneDelegationForExternalDNS(gslb1) + assert.NoError(t, err) + err = p.CreateZoneDelegationForExternalDNS(gslb2) + assert.NoError(t, err) + err = p.CreateZoneDelegationForExternalDNS(gslb3) + assert.Error(t, err) +} + func TestSaveNewDNSEndpointOnExternalDNS(t *testing.T) { // arrange var ep = &corev1.Endpoints{ @@ -153,7 +227,7 @@ func TestSaveNewDNSEndpointOnExternalDNS(t *testing.T) { var cl = fake.NewClientBuilder().WithScheme(runtimeScheme).WithObjects(ep).Build() - assistant := assistant.NewGslbAssistant(cl, a.Config.K8gbNamespace, a.Config.EdgeDNSServers) + assistant := assistant.NewGslbAssistant(cl, a.Config.K8gbNamespace, a.Config) p := NewExternalDNS(a.Config, assistant) // act, assert err := p.SaveDNSEndpoint(a.Gslb, expectedDNSEndpoint) @@ -173,7 +247,7 @@ func TestSaveExistingDNSEndpointOnExternalDNS(t *testing.T) { require.NoError(t, schemeBuilder.AddToScheme(runtimeScheme)) var cl = fake.NewClientBuilder().WithScheme(runtimeScheme).WithObjects(endpointToSave).Build() - assistant := assistant.NewGslbAssistant(cl, a.Config.K8gbNamespace, a.Config.EdgeDNSServers) + assistant := assistant.NewGslbAssistant(cl, a.Config.K8gbNamespace, a.Config) p := NewExternalDNS(a.Config, assistant) // act, assert err := p.SaveDNSEndpoint(a.Gslb, endpointToSave) diff --git a/controllers/providers/dns/factory.go b/controllers/providers/dns/factory.go index f6c8e7ef93..bc75a7e7d3 100644 --- a/controllers/providers/dns/factory.go +++ b/controllers/providers/dns/factory.go @@ -44,7 +44,7 @@ func NewDNSProviderFactory(client client.Client, config depresolver.Config) (f * } func (f *ProviderFactory) Provider() Provider { - a := assistant.NewGslbAssistant(f.client, f.config.K8gbNamespace, f.config.EdgeDNSServers) + a := assistant.NewGslbAssistant(f.client, f.config.K8gbNamespace, f.config) switch f.config.EdgeDNSType { case depresolver.DNSTypeExternal: return NewExternalDNS(f.config, a) diff --git a/controllers/providers/dns/infoblox.go b/controllers/providers/dns/infoblox.go index 37202bb70e..1f313ed3b6 100644 --- a/controllers/providers/dns/infoblox.go +++ b/controllers/providers/dns/infoblox.go @@ -49,12 +49,12 @@ func NewInfobloxDNS(config depresolver.Config, assistant assistant.Assistant, cl } } -func (p *InfobloxProvider) sanitizeDelegateZone(local, upstream []ibcl.NameServer) []ibcl.NameServer { +func (p *InfobloxProvider) sanitizeDelegateZone(local, upstream []ibcl.NameServer, zoneInfo *depresolver.DelegationZoneInfo) []ibcl.NameServer { // Drop own records for straight away update // And ensure local entries are up to date // And final list is sorted final := local - remote := p.filterOutDelegateTo(upstream, p.config.GetClusterNSName()) + remote := p.filterOutDelegateTo(upstream, zoneInfo.ClusterNSName) final = append(final, remote...) sortZones(final) @@ -81,18 +81,22 @@ func (p *InfobloxProvider) CreateZoneDelegationForExternalDNS(gslb *k8gbv1beta1. var delegateTo []ibcl.NameServer for _, address := range addresses { - nameServer := ibcl.NameServer{Address: address, Name: p.config.GetClusterNSName()} + nameServer := ibcl.NameServer{Address: address, Name: p.config.DelegationZones.GetClusterNSNameByGslb(gslb)} delegateTo = append(delegateTo, nameServer) } - findZone, err := p.getZoneDelegated(objMgr, p.config.DNSZone) + zoneInfo := p.config.DelegationZones.FindByGslbStatusHostname(gslb) + if zoneInfo == nil { + return fmt.Errorf("domainInfo not found for GSLB: %s. Check if the gslb.Status.Servers[*].Host property matches any of the DNSZones", gslb.Name) + } + findZone, err := p.getZoneDelegated(objMgr, zoneInfo.Domain) if err != nil { m.InfobloxIncrementZoneUpdateError(gslb) return err } if findZone != nil { - err = p.checkZoneDelegated(findZone) + err = p.checkZoneDelegated(findZone, zoneInfo) if err != nil { m.InfobloxIncrementZoneUpdateError(gslb) return err @@ -101,13 +105,13 @@ func (p *InfobloxProvider) CreateZoneDelegationForExternalDNS(gslb *k8gbv1beta1. if len(findZone.Ref) > 0 { sortZones(findZone.DelegateTo) - currentList := p.sanitizeDelegateZone(delegateTo, findZone.DelegateTo) + currentList := p.sanitizeDelegateZone(delegateTo, findZone.DelegateTo, zoneInfo) if !reflect.DeepEqual(findZone.DelegateTo, currentList) { log.Info(). Interface("records", findZone.DelegateTo). Msg("Found delegated zone records") log.Info(). - Str("DNSZone", p.config.DNSZone). + Str("DNSZone", zoneInfo.Domain). Interface("serverList", currentList). Msg("Updating delegated zone with the server list") _, err = p.updateZoneDelegated(objMgr, findZone.Ref, currentList) @@ -120,13 +124,13 @@ func (p *InfobloxProvider) CreateZoneDelegationForExternalDNS(gslb *k8gbv1beta1. } } else { log.Info(). - Str("DNSZone", p.config.DNSZone). + Str("DNSZone", zoneInfo.Domain). Msg("Creating delegated zone") sortZones(delegateTo) log.Debug(). Interface("records", delegateTo). Msg("Delegated records") - _, err = p.createZoneDelegated(objMgr, p.config.DNSZone, delegateTo) + _, err = p.createZoneDelegated(objMgr, zoneInfo.Domain, delegateTo) if err != nil { m.InfobloxIncrementZoneUpdateError(gslb) return err @@ -141,31 +145,33 @@ func (p *InfobloxProvider) Finalize(_ *k8gbv1beta1.Gslb, _ client.Client) error if err != nil { return err } - findZone, err := p.getZoneDelegated(objMgr, p.config.DNSZone) - if err != nil { - return err - } - - if findZone != nil { - err = p.checkZoneDelegated(findZone) + for _, zoneInfo := range p.config.DelegationZones { + findZone, err := p.getZoneDelegated(objMgr, zoneInfo.Domain) if err != nil { return err } - if len(findZone.Ref) > 0 { - log.Info(). - Str("DNSZone", p.config.DNSZone). - Msg("Deleting delegated zone") - _, err := p.deleteZoneDelegated(objMgr, findZone.Ref) + + if findZone != nil { + err = p.checkZoneDelegated(findZone, &zoneInfo) if err != nil { return err } + if len(findZone.Ref) > 0 { + log.Info(). + Str("DNSZone", zoneInfo.Domain). + Msg("Deleting delegated zone") + _, err := p.deleteZoneDelegated(objMgr, findZone.Ref) + if err != nil { + return err + } + } } } return nil } func (p *InfobloxProvider) GetExternalTargets(host string) (targets assistant.Targets) { - return p.assistant.GetExternalTargets(host, p.config.GetExternalClusterNSNames()) + return p.assistant.GetExternalTargets(host, p.config.DelegationZones.GetExternalClusterNSNamesByHostname(host)) } func (p *InfobloxProvider) SaveDNSEndpoint(gslb *k8gbv1beta1.Gslb, i *externaldns.DNSEndpoint) error { @@ -176,9 +182,9 @@ func (p *InfobloxProvider) String() string { return "Infoblox" } -func (p *InfobloxProvider) checkZoneDelegated(findZone *ibcl.ZoneDelegated) error { - if findZone.Fqdn != p.config.DNSZone { - err := fmt.Errorf("delegated zone returned from infoblox(%s) does not match requested gslb zone(%s)", findZone.Fqdn, p.config.DNSZone) +func (p *InfobloxProvider) checkZoneDelegated(findZone *ibcl.ZoneDelegated, info *depresolver.DelegationZoneInfo) error { + if findZone.Fqdn != info.Domain { + err := fmt.Errorf("delegated zone returned from infoblox(%s) does not match requested gslb zone(%s)", findZone.Fqdn, info.Domain) return err } return nil diff --git a/controllers/providers/dns/infoblox_test.go b/controllers/providers/dns/infoblox_test.go index 9a720e75f7..c84f051854 100644 --- a/controllers/providers/dns/infoblox_test.go +++ b/controllers/providers/dns/infoblox_test.go @@ -44,16 +44,21 @@ const ( var ( defaultConfig = depresolver.Config{ ReconcileRequeueSeconds: 30, - ClusterGeoTag: "us-west-1", - ExtClustersGeoTags: []string{"us-east-1"}, + ClusterGeoTag: "us", EdgeDNSServers: []utils.DNSServer{ { Host: "8.8.8.8", Port: 53, }, }, - EdgeDNSZone: "example.com", - DNSZone: "cloud.example.com", + DelegationZones: depresolver.DelegationZones{ + { + Domain: "cloud.example.com", + Zone: "example.com", + ClusterNSName: "gslb-ns-us-west-1-cloud.example.com", + ExtClusterNSNames: map[string]string{"us": "gslb-ns-us-cloud.example.com", "za": "gslb-ns-za-cloud.example.com"}, + }, + }, K8gbNamespace: "k8gb", Infoblox: depresolver.Infoblox{ Host: "fakeinfoblox.example.com", @@ -65,7 +70,7 @@ var ( } defaultDelegatedZone = ibclient.ZoneDelegated{ - Fqdn: defaultConfig.DNSZone, + Fqdn: defaultConfig.DelegationZones[0].Domain, DelegateTo: []ibclient.NameServer{}, Ref: ref, } @@ -89,15 +94,14 @@ func TestCanFilterOutDelegatedZoneEntryAccordingFQDNProvided(t *testing.T) { {Address: "10.0.0.3", Name: "gslb-ns-eu-cloud.example.com"}, } customConfig := defaultConfig - customConfig.EdgeDNSZone = "example.com" - customConfig.ExtClustersGeoTags = []string{"za"} - a := assistant.NewGslbAssistant(nil, customConfig.K8gbNamespace, customConfig.EdgeDNSServers) + // customConfig.DelegationZones[0].ExtClusterNSNames = map[string]string{"za": "gslb-ns-za-cloud.example.com"} + a := assistant.NewGslbAssistant(nil, customConfig.K8gbNamespace, customConfig) ctrl := gomock.NewController(t) defer ctrl.Finish() m := mocks.NewMockInfobloxClient(ctrl) provider := NewInfobloxDNS(customConfig, a, m) // act - extClusters := customConfig.GetExternalClusterNSNames() + extClusters := customConfig.DelegationZones[0].ExtClusterNSNames got := provider.filterOutDelegateTo(delegateTo, extClusters["za"]) // assert assert.Equal(t, want, got, "got:\n %q filtered out delegation records,\n\n want:\n %q", got, want) @@ -126,16 +130,17 @@ func TestCanSanitizeDelegatedZone(t *testing.T) { {Address: "10.1.0.3", Name: "gslb-ns-za-cloud.example.com"}, } customConfig := defaultConfig - customConfig.EdgeDNSZone = "example.com" - customConfig.ExtClustersGeoTags = []string{"za"} - customConfig.ClusterGeoTag = "eu" - a := assistant.NewGslbAssistant(nil, customConfig.K8gbNamespace, customConfig.EdgeDNSServers) + a := assistant.NewGslbAssistant(nil, customConfig.K8gbNamespace, customConfig) ctrl := gomock.NewController(t) defer ctrl.Finish() m := mocks.NewMockInfobloxClient(ctrl) provider := NewInfobloxDNS(customConfig, a, m) // act - got := provider.sanitizeDelegateZone(local, upstream) + got := provider.sanitizeDelegateZone(local, upstream, &depresolver.DelegationZoneInfo{ + Domain: "cloud.example.com", + Zone: "example.com", + ClusterNSName: "gslb-ns-eu-cloud.example.com", + }) // assert assert.Equal(t, want, got, "got:\n %q filtered out delegation records,\n\n want:\n %q", got, want) } @@ -165,19 +170,41 @@ func TestInfobloxCreateZoneDelegationForExternalDNS(t *testing.T) { // arrange ctrl := gomock.NewController(t) defer ctrl.Finish() + defaultDelegatedZone2 := defaultDelegatedZone + defaultDelegatedZone2.Fqdn = "cloud.example.org" + defaultDelegatedZone2.Ref = "zone_delegated/ZG5zLnpvbmUkLl9kZWZhdWx0LnphLmNvLmFic2EuY2Fhcy5vaG15Z2xiLmdzbGJpYmNsaWVudA:cloud.example.org/default" a := mocks.NewMockAssistant(ctrl) cl := mocks.NewMockInfobloxClient(ctrl) con := mocks.NewMockIBConnector(ctrl) con.EXPECT().CreateObject(gomock.Any()).Return(ref, nil).AnyTimes() - con.EXPECT().UpdateObject(gomock.Any(), gomock.Any()).Return(ref, nil).Times(1) - con.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).SetArg(2, []ibclient.ZoneDelegated{defaultDelegatedZone}).Return(nil) - cl.EXPECT().GetObjectManager().Return(ibclient.NewObjectManager(con, "k8gbclient", ""), nil).Times(1) + con.EXPECT().UpdateObject(gomock.Any(), gomock.Any()).Return(ref, nil).Times(2) + con.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).SetArg(2, []ibclient.ZoneDelegated{defaultDelegatedZone}).Return(nil).Times(1) + con.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).SetArg(2, []ibclient.ZoneDelegated{defaultDelegatedZone2}).Return(nil).Times(1) + cl.EXPECT().GetObjectManager().Return(ibclient.NewObjectManager(con, "k8gbclient", ""), nil).Times(2) config := defaultConfig + config.DelegationZones = []depresolver.DelegationZoneInfo{ + { + Domain: "cloud.example.com", + Zone: "example.com", + }, + { + Domain: "cloud.example.org", + Zone: "example.org", + }, + } + gslb1 := defaultGslb.DeepCopy() + gslb2 := defaultGslb.DeepCopy() + gslb1.Status.Servers = []*k8gbv1beta1.Server{{Host: "cloud.example.com"}} + gslb1.Status.LoadBalancer.ExposedIPs = []string{"10.0.0.1"} + gslb2.Status.Servers = []*k8gbv1beta1.Server{{Host: "cloud.example.org"}} + gslb2.Status.LoadBalancer.ExposedIPs = []string{"10.0.0.1"} provider := NewInfobloxDNS(config, a, cl) // act - err := provider.CreateZoneDelegationForExternalDNS(defaultGslb) // assert + err := provider.CreateZoneDelegationForExternalDNS(gslb1) + assert.NoError(t, err) + err = provider.CreateZoneDelegationForExternalDNS(gslb2) assert.NoError(t, err) } @@ -185,6 +212,8 @@ func TestInfobloxFinalize(t *testing.T) { // arrange ctrl := gomock.NewController(t) defer ctrl.Finish() + defaultDelegatedZone2 := defaultDelegatedZone + defaultDelegatedZone2.Fqdn = "cloud.example.org" a := mocks.NewMockAssistant(ctrl) cl := mocks.NewMockInfobloxClient(ctrl) con := mocks.NewMockIBConnector(ctrl) @@ -193,10 +222,21 @@ func TestInfobloxFinalize(t *testing.T) { }).AnyTimes() con.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).SetArg(2, []ibclient.ZoneDelegated{defaultDelegatedZone}). Return(nil).Times(1) + con.EXPECT().GetObject(gomock.Any(), gomock.Any(), gomock.Any()).SetArg(2, []ibclient.ZoneDelegated{defaultDelegatedZone2}). + Return(nil).Times(1) cl.EXPECT().GetObjectManager().Return(ibclient.NewObjectManager(con, "k8gbclient", ""), nil).Times(1) config := defaultConfig + config.DelegationZones = []depresolver.DelegationZoneInfo{ + { + Domain: "cloud.example.com", + Zone: "example.com", + }, + { + Domain: "cloud.example.org", + Zone: "example.org", + }, + } provider := NewInfobloxDNS(config, a, cl) - // act err := provider.Finalize(defaultGslb, nil) diff --git a/controllers/providers/metrics/prometheus_test.go b/controllers/providers/metrics/prometheus_test.go index d71f49705b..a847ff5a0f 100644 --- a/controllers/providers/metrics/prometheus_test.go +++ b/controllers/providers/metrics/prometheus_test.go @@ -47,7 +47,15 @@ const ( var ( defaultGslb = new(k8gbv1beta1.Gslb) defaultEndpoint = new(externaldns.DNSEndpoint) - defaultConfig = depresolver.Config{K8gbNamespace: namespace, DNSZone: "cloud.example.com"} + defaultConfig = depresolver.Config{ + K8gbNamespace: namespace, + DelegationZones: depresolver.DelegationZones{ + { + Domain: "cloud.example.com", + Zone: "example.com", + }, + }, + } ) func TestMetricsSingletonIsNotNil(t *testing.T) { diff --git a/go.mod b/go.mod index 1cb81dc3b6..91a23d2b68 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,6 @@ require ( go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect diff --git a/go.sum b/go.sum index 4a71ef1daa..48c6e31265 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -151,8 +149,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/miekg/dns v1.1.0/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -218,32 +214,20 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= -go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -252,16 +236,13 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -271,8 +252,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -302,14 +281,10 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -346,19 +321,13 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= -google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -370,8 +339,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -403,8 +370,6 @@ istio.io/client-go v1.24.2/go.mod h1:dgZ9EmJzh1EECzf6nQhwNL4R6RvlyeH/RXeNeNp/MRg k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE= k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0= -k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= -k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0= k8s.io/apiextensions-apiserver v0.32.0/go.mod h1:86hblMvN5yxMvZrZFX2OhIHAuFIMJIZ19bTvzkP+Fmw= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= @@ -422,8 +387,6 @@ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.19.4 h1:SUmheabttt0nx8uJtoII4oIP27BVVvAKFvdvGFwV/Qo= -sigs.k8s.io/controller-runtime v0.19.4/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-runtime v0.20.1 h1:JbGMAG/X94NeM3xvjenVUaBjy6Ui4Ogd/J5ZtjZnHaE= sigs.k8s.io/controller-runtime v0.20.1/go.mod h1:BrP3w158MwvB3ZbNpaAcIKkHQ7YGpYnzpoSTZ8E14WU= sigs.k8s.io/external-dns v0.15.1 h1:7UXUtMrEuS4DZM/1A7gtuooJh2cIYSn3RiUX3buqPHs= diff --git a/terratest/test/k8gb_annotation_test.go b/terratest/test/k8gb_annotation_test.go index 6572a293d9..bc3c38f1a7 100644 --- a/terratest/test/k8gb_annotation_test.go +++ b/terratest/test/k8gb_annotation_test.go @@ -105,7 +105,7 @@ func testAnnotations(t *testing.T, test struct { err = instanceEU.WaitForAppIsRunning() require.NoError(t, err) - err = instanceEU.WaitForExternalDNSEndpointExists() + err = instanceEU.WaitForExternalDNSEndpointExists("cloud.example.com") require.NoError(t, err) err = instanceEU.Resources().Ingress().PatchAnnotations(test.patch) diff --git a/terratest/test/k8gb_weight_test.go b/terratest/test/k8gb_weight_test.go index b881c3cc0a..b4285aefde 100644 --- a/terratest/test/k8gb_weight_test.go +++ b/terratest/test/k8gb_weight_test.go @@ -45,6 +45,7 @@ func TestWeightsExistsInLocalDNSEndpoint(t *testing.T) { func abstractTestWeightsExistsInLocalDNSEndpoint(t *testing.T, host string, workflowEU, workflowUS *utils.Workflow) { const endpointDNSNameEU = "gslb-ns-eu-cloud.example.com" const endpointDNSNameUS = "gslb-ns-us-cloud.example.com" + const zone = "cloud.example.com" workflowEU = workflowEU.WithTestApp("eu") instanceEU, err := workflowEU.Start() require.NoError(t, err) @@ -60,13 +61,13 @@ func abstractTestWeightsExistsInLocalDNSEndpoint(t *testing.T, host string, work err = instanceUS.WaitForAppIsRunning() require.NoError(t, err) - err = instanceEU.Resources().WaitForExternalDNSEndpointHasTargets(endpointDNSNameEU) + err = instanceEU.Resources().WaitForExternalDNSEndpointHasTargets(zone, endpointDNSNameEU) require.NoError(t, err) - epExternalEU, err := instanceEU.Resources().GetK8gbExternalDNSEndpoint().GetEndpointByName(endpointDNSNameEU) + epExternalEU, err := instanceEU.Resources().GetK8gbExternalDNSEndpoint(zone).GetEndpointByName(endpointDNSNameEU) require.NoError(t, err, "missing EU endpoint %s", endpointDNSNameEU) - err = instanceUS.Resources().WaitForExternalDNSEndpointHasTargets(endpointDNSNameUS) + err = instanceUS.Resources().WaitForExternalDNSEndpointHasTargets(zone, endpointDNSNameUS) require.NoError(t, err) - epExternalUS, err := instanceUS.Resources().GetK8gbExternalDNSEndpoint().GetEndpointByName(endpointDNSNameUS) + epExternalUS, err := instanceUS.Resources().GetK8gbExternalDNSEndpoint(zone).GetEndpointByName(endpointDNSNameUS) require.NoError(t, err, "missing US endpoint %s", endpointDNSNameUS) expectedTargets := append(epExternalEU.Targets, epExternalUS.Targets...) diff --git a/terratest/utils/extensions.go b/terratest/utils/extensions.go index 7510963b52..3450d48033 100644 --- a/terratest/utils/extensions.go +++ b/terratest/utils/extensions.go @@ -453,18 +453,18 @@ func (i *Instance) WaitForLocalDNSEndpointExists() error { return tickerWaiter(DefaultRetries, "LocalDNSEndpoint exists:", periodic) } -func (i *Instance) WaitForExternalDNSEndpointExists() error { +func (i *Instance) WaitForExternalDNSEndpointExists(zone string) error { periodic := func() (result bool, err error) { - lep := i.Resources().GetK8gbExternalDNSEndpoint() + lep := i.Resources().GetK8gbExternalDNSEndpoint(zone) result = len(lep.Spec.Endpoints) > 0 return result, err } return tickerWaiter(DefaultRetries, "ExternalDNSEndpoint exists:", periodic) } -func (r *Resources) WaitForExternalDNSEndpointHasTargets(epName string) error { +func (r *Resources) WaitForExternalDNSEndpointHasTargets(zone, epName string) error { periodic := func() (result bool, err error) { - epx, err := r.GetK8gbExternalDNSEndpoint().GetEndpointByName(epName) + epx, err := r.GetK8gbExternalDNSEndpoint(zone).GetEndpointByName(epName) if err != nil { return false, nil } @@ -740,8 +740,9 @@ func (r *Resources) GetLocalDNSEndpoint() DNSEndpoint { return ep } -func (r *Resources) GetK8gbExternalDNSEndpoint() DNSEndpoint { - return r.GetExternalDNSEndpointByName("k8gb-ns-extdns", "k8gb") +func (r *Resources) GetK8gbExternalDNSEndpoint(zone string) DNSEndpoint { + var suffix = strings.Trim(strings.ReplaceAll(zone, ".", "-"), " ") + return r.GetExternalDNSEndpointByName("k8gb-ns-extdns-"+suffix, "k8gb") } func (r *Resources) GetExternalDNSEndpointByName(name, namespace string) DNSEndpoint {