diff --git a/README.md b/README.md index 5eb005a..49be92a 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,13 @@ A CoreDNS plugin that is very similar to [k8s_external](https://coredns.io/plugi This plugin relies on it's own connection to the k8s API server and doesn't share any code with the existing [kubernetes](https://coredns.io/plugins/kubernetes/) plugin. The assumption is that this plugin can now be deployed as a separate instance (alongside the internal kube-dns) and act as a single external DNS interface into your Kubernetes cluster(s). - ## Description `k8s_crd` resolves Kubernetes resources with their external IP addresses based on zones specified in the configuration. This plugin will resolve the following type of resources: | Kind | Matching Against | External IPs are from | | ---- | ---------------- | -------- | -| DNSEndponit | all FQDNs from `spec.endpoints.dnszone` matching configured zones | `.spec.endpoints.dnszone.targets` | - +| DNSEndpoint | all FQDNs from `spec.endpoints.dnszone` matching configured zones | `.spec.endpoints.dnszone.targets` | Currently only supports A-type queries, all other queries result in NODATA responses. @@ -24,18 +22,19 @@ This plugin is **NOT** supposed to be used for intra-cluster DNS resolution and The recommended installation method is using the helm chart provided in the repo: -``` +```shell helm install exdns ./charts/coredns ``` + ## Configure -``` +```text k8s_crd [ZONE...] ``` Optionally, you can specify what kind of resources to watch, default TTL to return in response and a default name to use for zone apex, e.g. -``` +```text k8s_crd example.com { ttl 10 apex dns1 @@ -45,26 +44,41 @@ k8s_crd example.com { ## Resolving order ### GeoIP + In case dnsEndpoint object's target has a label of `strategy: geoip` CoreDNS `k8s_crd` plugin will respond in a special way: + * Assuming record has multiple IPs associated with it, and DNS message comes with edns0 `CLIENT-SUBNET` option. -* CoreDNS will compare `DC` tag for IP extracted from `CLIENT-SUBNET` option against available Endpoint.Targets +* CoreDNS will compare the specified field tag (`datacenter` by default, configured via the `geodatafield` plugin option) for IP extracted from `CLIENT-SUBNET` option against available Endpoint.Targets * Return only IPs where tags match * If IP has no common tag, all entries are returned. -* CoreDNS must be supplied with a specially crafted GeoIP database in MaxMind DB format and mounted as `/geoip.mmdb` Refer to [./terratest/geogen](./terratest/geogen) for examples. +* CoreDNS must be supplied with a specially crafted GeoIP database in MaxMind DB format and mounted (at `/geoip.mmdb` by default, configured via the `geodatafilepath` plugin option). Refer to [./terratest/geogen](./terratest/geogen) for examples. Using the MaxMind GeoLite2 database is supported using the necessary `geodatafield` to configure the field to use as required. +The following configuration options are available: + +```text +k8s_crd example.com { + geodatafilepath /geoip.mmdb + geodatafield country.iso_code + ... +} +``` ### Weight Round Robin + To enable the weight round robin you have to set the configuration to weight load-balancer: -``` + +```text k8s_crd example.com { loadbalance weight ... } ``` -The dnsEndpoint must also contain information about the percentage distribution per region -and their IP addresses. Thanks to this, the weight round-robin module will know in which -order to return IP addresses. Addresses with high probability will often be at the top of + +The dnsEndpoint must also contain information about the percentage distribution per region +and their IP addresses. Thanks to this, the weight round-robin module will know in which +order to return IP addresses. Addresses with high probability will often be at the top of DNS responses, while those with low probability will be at the bottom. + ```yaml labels: strategy: roundrobin @@ -73,6 +87,7 @@ labels: weight-za-0-0: 10.10.0.1 weight-us-0-50: 10.20.0.1 ``` + For more information about balancing, please visit our [go-weight-shuffling](https://github.com/k8gb-io/go-weight-shuffling ) module. @@ -80,27 +95,27 @@ For more information about balancing, please visit our [go-weight-shuffling](htt ### With compile-time configuration file -``` -$ git clone https://github.com/coredns/coredns -$ cd coredns -$ vim plugin.cfg +```shell +git clone https://github.com/coredns/coredns +cd coredns +vim plugin.cfg # Replace lines with kubernetes and k8s_external with k8s_crd:github.com/absaoss/k8s_crd -$ go generate -$ go build -$ ./coredns -plugins | grep k8s_crd +go generate +go build +./coredns -plugins | grep k8s_crd ``` ### With external golang source code -``` -$ git clone https://github.com/absaoss/k8s_crd.git -$ cd k8s_crd -$ go build cmd/coredns.go -$ ./coredns -plugins | grep k8s_crd + +```shell +git clone https://github.com/absaoss/k8s_crd.git +cd k8s_crd +go build cmd/coredns.go +./coredns -plugins | grep k8s_crd ``` For more details refer to [this CoreDNS doc](https://coredns.io/2017/07/25/compile-time-enabling-or-disabling-plugins/) - ## Notes regarding Zone Apex and NS server resolution -Due to the fact that there is not nice way to discover NS server's own IP to respond to A queries, as a wokaround, it's possible to pass the name of the LoadBalancer service used to expose the CoreDNS instance as an environment variable `EXTERNAL_SVC`. If not set, the default fallback value of `external-dns.kube-system` will be used to look up the external IP of the CoreDNS service. +Due to the fact that there is not nice way to discover NS server's own IP to respond to A queries, as a workaround, it's possible to pass the name of the LoadBalancer service used to expose the CoreDNS instance as an environment variable `EXTERNAL_SVC`. If not set, the default fallback value of `external-dns.kube-system` will be used to look up the external IP of the CoreDNS service. diff --git a/common/k8sctrl/ctrl.go b/common/k8sctrl/ctrl.go index 3f1a1ab..cf18527 100644 --- a/common/k8sctrl/ctrl.go +++ b/common/k8sctrl/ctrl.go @@ -42,7 +42,7 @@ type KubeController struct { epc cache.SharedIndexInformer } -type LookupEndpoint func(indexKey string, clientIP net.IP) (result LocalDNSEndpoint) +type LookupEndpoint func(indexKey string, clientIP net.IP, geoDataFilePath string, geoDataFieldPath ...string) (result LocalDNSEndpoint) type ResourceWithLookup struct { Name string @@ -137,19 +137,19 @@ func endpointHostnameIndexFunc(obj interface{}) ([]string, error) { return hostnames, nil } -func (ctrl *KubeController) getEndpointByName(host string, clientIP net.IP) (lep LocalDNSEndpoint) { +func (ctrl *KubeController) getEndpointByName(host string, clientIP net.IP, geoDataFilePath string, geoDataFieldPath ...string) (lep LocalDNSEndpoint) { log.Infof("Index key %+v", host) - endpoints := ctrl.getEndpointsByCaseInsensitiveName(host, clientIP) + endpoints := ctrl.getEndpointsByCaseInsensitiveName(host, clientIP, geoDataFilePath, geoDataFieldPath...) lep = ctrl.margeLocalDNSEndpoints(host, endpoints) return lep } // The function tries to find all case sensitive variants. Returns a map where the call is hostname and the value is LocalDNSEndpoint -func (ctrl *KubeController) getEndpointsByCaseInsensitiveName(host string, clientIP net.IP) (result map[string]LocalDNSEndpoint) { +func (ctrl *KubeController) getEndpointsByCaseInsensitiveName(host string, clientIP net.IP, geoDataFilePath string, geoDataFieldPath ...string) (result map[string]LocalDNSEndpoint) { // The function extracts LocalDNSEndpoints from *DNSEndpoint. The function is hardwired with a case-sensitive extraction scenario and is only used in a // single location, so it is currently declared inside the calling function. - extractLocalEndpoints := func(ep *endpoint.DNSEndpoint, ip net.IP, host string) (result []LocalDNSEndpoint) { + extractLocalEndpoints := func(ep *endpoint.DNSEndpoint, ip net.IP, host string, geoDataFieldPath ...string) (result []LocalDNSEndpoint) { result = []LocalDNSEndpoint{} for _, e := range ep.Spec.Endpoints { if strings.EqualFold(e.DNSName, host) { @@ -159,7 +159,7 @@ func (ctrl *KubeController) getEndpointsByCaseInsensitiveName(host string, clien r.TTL = e.RecordTTL r.Targets = e.Targets if e.Labels["strategy"] == "geoip" { - targets := r.extractGeo(e, ip) + targets := r.extractGeo(e, ip, geoDataFilePath, geoDataFieldPath...) if len(targets) > 0 { r.Targets = targets } @@ -174,7 +174,7 @@ func (ctrl *KubeController) getEndpointsByCaseInsensitiveName(host string, clien result = make(map[string]LocalDNSEndpoint, 0) for _, obj := range epList { ep := obj.(*endpoint.DNSEndpoint) - extracts := extractLocalEndpoints(ep, clientIP, host) + extracts := extractLocalEndpoints(ep, clientIP, host, geoDataFieldPath...) for _, extracted := range extracts { if strings.EqualFold(extracted.DNSName, host) { result[extracted.DNSName] = extracted diff --git a/common/k8sctrl/ctrl_test.go b/common/k8sctrl/ctrl_test.go index 6f624c0..4073755 100644 --- a/common/k8sctrl/ctrl_test.go +++ b/common/k8sctrl/ctrl_test.go @@ -139,30 +139,30 @@ func TestKubeController(t *testing.T) { k8sctrl.epc = mcache t.Run("get no-geo endpoint by name", func(t *testing.T) { - lep := k8sctrl.getEndpointByName(host, clientIP) + lep := k8sctrl.getEndpointByName(host, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "roundrobin.cloud.example.com: 0, Targets: [10.0.0.1 10.0.0.2], Labels: map[strategy:roundrobin]", lep.String()) }) t.Run("valid uppercase domain query", func(t *testing.T) { - lep := k8sctrl.getEndpointByName(hOSTCaseInsensitive, clientIP) + lep := k8sctrl.getEndpointByName(hOSTCaseInsensitive, clientIP, "") assert.NotNil(t, lep) sort.Strings(lep.Targets) assert.Equal(t, "roundrobin-case-insensitive.CLOUD.EXAMPLE.COM: 0, Targets: [1.1.1.1 1.1.1.2 2.2.2.2], Labels: map[strategy:roundrobin]", lep.String()) - lep = k8sctrl.getEndpointByName(hostCaseInsensitive, clientIP) + lep = k8sctrl.getEndpointByName(hostCaseInsensitive, clientIP, "") assert.NotNil(t, lep) sort.Strings(lep.Targets) assert.Equal(t, "roundrobin-case-insensitive.cloud.example.com: 0, Targets: [1.1.1.1 1.1.1.2 2.2.2.2], Labels: map[strategy:roundrobin]", lep.String()) }) t.Run("handle multiple embedded endpoints", func(t *testing.T) { - lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP) + lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP, "") assert.NotNil(t, lep) sort.Strings(lep.Targets) assert.Equal(t, "embedded.cloud.example.com: 0, Targets: [10.10.10.2 10.10.10.30 10.10.10.32], Labels: map[strategy:roundrobin]", lep.String()) - lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP) + lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP, "") assert.NotNil(t, lep) sort.Strings(lep.Targets) assert.Equal(t, "embedded.CLOUD.EXAMPLE.COM: 0, Targets: [10.10.10.2 10.10.10.30 10.10.10.32], Labels: map[strategy:roundrobin]", lep.String()) @@ -170,11 +170,11 @@ func TestKubeController(t *testing.T) { t.Run("handle multiple embedded endpoints but one EP is empty", func(t *testing.T) { epEmbedded.Spec.Endpoints[1].Targets = []string{} - lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP) + lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.cloud.example.com: 0, Targets: [10.10.10.2], Labels: map[strategy:roundrobin]", lep.String()) - lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP) + lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.CLOUD.EXAMPLE.COM: 0, Targets: [10.10.10.2], Labels: map[strategy:roundrobin]", lep.String()) @@ -184,33 +184,33 @@ func TestKubeController(t *testing.T) { epEmbedded.Spec.Endpoints[1].Targets = []string{} epEmbedded.Spec.Endpoints[2].Targets = []string{} epEmbedded.Spec.Endpoints[0].Targets = []string{} - lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP) + lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.cloud.example.com: 0, Targets: [], Labels: map[strategy:roundrobin]", lep.String()) - lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP) + lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.CLOUD.EXAMPLE.COM: 0, Targets: [], Labels: map[strategy:roundrobin]", lep.String()) }) t.Run("EP has no dns endpoints", func(t *testing.T) { epEmbedded.Spec.Endpoints = []*endpoint.Endpoint{} - lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP) + lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.cloud.example.com: 0, Targets: [], Labels: map[]", lep.String()) - lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP) + lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.CLOUD.EXAMPLE.COM: 0, Targets: [], Labels: map[]", lep.String()) }) t.Run("EP has nil dns endpoints", func(t *testing.T) { epEmbedded.Spec.Endpoints = nil - lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP) + lep := k8sctrl.getEndpointByName(embeddedCaseInsensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.cloud.example.com: 0, Targets: [], Labels: map[]", lep.String()) - lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP) + lep = k8sctrl.getEndpointByName(embeddedCaseSensitive, clientIP, "") assert.NotNil(t, lep) assert.Equal(t, "embedded.CLOUD.EXAMPLE.COM: 0, Targets: [], Labels: map[]", lep.String()) }) diff --git a/common/k8sctrl/ep.go b/common/k8sctrl/ep.go index 07f26c6..d7f6bdb 100644 --- a/common/k8sctrl/ep.go +++ b/common/k8sctrl/ep.go @@ -23,12 +23,11 @@ import ( "net" "github.com/oschwald/maxminddb-golang" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/external-dns/endpoint" ) -type geo struct { - DC string `maxminddb:"datacenter"` -} +type geo map[string]interface{} type LocalDNSEndpoint struct { Targets []string @@ -41,37 +40,64 @@ func (lep LocalDNSEndpoint) String() string { return fmt.Sprintf("%s: %v, Targets: %v, Labels: %v", lep.DNSName, lep.TTL, lep.Targets, lep.Labels) } -func (lep LocalDNSEndpoint) extractGeo(endpoint *endpoint.Endpoint, clientIP net.IP) (result []string) { - db, err := maxminddb.Open("geoip.mmdb") +func (lep LocalDNSEndpoint) extractGeo(endpoint *endpoint.Endpoint, clientIP net.IP, geoDataFilePath string, geoDataFieldPath ...string) (result []string) { + if geoDataFilePath == "" { + return nil + } + + db, err := maxminddb.Open(geoDataFilePath) if err != nil { log.Fatal(err) } defer db.Close() // nolint:errcheck - clientGeo := &geo{} - err = db.Lookup(clientIP, clientGeo) + var clientGeo geo + err = db.Lookup(clientIP, &clientGeo) if err != nil { return nil } - if clientGeo.DC == "" { - log.Infof("empty DC %+v", clientGeo) + log.Infof("extracted client geo data: %+v", clientGeo) + + if len(geoDataFieldPath) == 0 { + log.Info("no geo data field specified") + return result + } + + clientGeoData, found, err := unstructured.NestedString(clientGeo, geoDataFieldPath...) + if err != nil { + log.Infof("error retrieving client geo data for field %+v: %v", geoDataFieldPath, err) + return result + } + + if !found || clientGeoData == "" { + log.Infof("client geo data field %+v not found", geoDataFieldPath) return result } - log.Infof("clientDC: %+v", clientGeo) + log.Infof("client geo data field value for %+v: %+v", geoDataFieldPath, clientGeoData) for _, ip := range endpoint.Targets { - geoData := &geo{} + var endpointGeo geo log.Infof("processing IP %+v", ip) - err = db.Lookup(net.ParseIP(ip), geoData) + err = db.Lookup(net.ParseIP(ip), &endpointGeo) if err != nil { log.Error(err) continue } + endpointGeoData, found, err := unstructured.NestedString(endpointGeo, geoDataFieldPath...) + if err != nil { + log.Infof("error retrieving endpoint geo data for field %+v: %v", geoDataFieldPath, err) + return result + } + + if !found || endpointGeoData == "" { + log.Infof("endpoint geo data field %+v not found", geoDataFieldPath) + return result + } - log.Infof("IP info: %+v", geoData.DC) - if clientGeo.DC == geoData.DC { + log.Infof("endpoint data field value for %+v: %+v", geoDataFieldPath, clientGeoData) + if clientGeoData == endpointGeoData { result = append(result, ip) } } diff --git a/service/gateway/gateway.go b/service/gateway/gateway.go index 9c9a8c3..1b807c0 100644 --- a/service/gateway/gateway.go +++ b/service/gateway/gateway.go @@ -88,7 +88,7 @@ func (gw *Gateway) ServeDNS(_ context.Context, w dns.ResponseWriter, r *dns.Msg) } } - var ep = k8sctrl.Resources.DNSEndpoint.Lookup(indexKey, clientIP) + var ep = k8sctrl.Resources.DNSEndpoint.Lookup(indexKey, clientIP, gw.opts.geoDataFilePath, gw.opts.geoDataField...) log.Debugf("Computed response addresses %v", ep.Targets) m := new(dns.Msg) m.SetReply(state.Req) @@ -160,7 +160,7 @@ func (gw *Gateway) selfAddress(state request.Request) (records []dns.RR) { index = defaultSvc } - var ep = k8sctrl.Resources.DNSEndpoint.Lookup(index, net.ParseIP(state.IP())) + var ep = k8sctrl.Resources.DNSEndpoint.Lookup(index, net.ParseIP(state.IP()), gw.opts.geoDataFilePath, gw.opts.geoDataField...) m := new(dns.Msg) m.SetReply(state.Req) return gw.A(state, netutils.TargetToIP(ep.Targets), ep.TTL) diff --git a/service/gateway/opts.go b/service/gateway/opts.go index 0d87178..e626f54 100644 --- a/service/gateway/opts.go +++ b/service/gateway/opts.go @@ -1,5 +1,7 @@ package gateway +import "strings" + /* Copyright 2022 The k8gb Contributors @@ -19,29 +21,35 @@ Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic */ type Opts struct { - annotation string - apex string - hostmaster string - ttlLow uint32 - ttlHigh uint32 - zones []string + annotation string + apex string + hostmaster string + ttlLow uint32 + ttlHigh uint32 + zones []string + geoDataFilePath string + geoDataField []string } var ( - ttlLowDefault = uint32(60) - ttlHighDefault = uint32(3600) - defaultApex = "dns" - defaultHostmaster = "hostmaster" + ttlLowDefault = uint32(60) + ttlHighDefault = uint32(3600) + defaultApex = "dns" + defaultHostmaster = "hostmaster" + defaultGeoDataFilePath = "/geoip.mmdb" + defaultGeoDataField = "datacenter" ) -func NewGatewayOpts(annotation, apex string, ttlLow, ttlHigh uint32, zones []string) Opts { +func NewGatewayOpts(annotation, apex, geoDataFilePath, geoDataField string, ttlLow, ttlHigh uint32, zones []string) Opts { opts := Opts{ - apex: defaultApex, - ttlLow: ttlLowDefault, - ttlHigh: ttlHighDefault, - hostmaster: defaultHostmaster, + apex: defaultApex, + ttlLow: ttlLowDefault, + ttlHigh: ttlHighDefault, + hostmaster: defaultHostmaster, + geoDataFilePath: defaultGeoDataFilePath, + geoDataField: strings.Split(defaultGeoDataField, "."), } - if len(apex) != 0 { + if apex != "" { opts.apex = apex } if ttlLow != 0 { @@ -50,6 +58,12 @@ func NewGatewayOpts(annotation, apex string, ttlLow, ttlHigh uint32, zones []str if ttlHigh != 0 { opts.ttlHigh = ttlHigh } + if geoDataFilePath != "" { + opts.geoDataFilePath = geoDataFilePath + } + if geoDataField != "" { + opts.geoDataField = strings.Split(geoDataField, ".") + } opts.annotation = annotation opts.zones = zones return opts diff --git a/service/wrr/wrr.go b/service/wrr/wrr.go index 186657a..f5e5282 100644 --- a/service/wrr/wrr.go +++ b/service/wrr/wrr.go @@ -56,7 +56,7 @@ func (wrr *WeightRoundRobin) ServeDNS(_ context.Context, w dns.ResponseWriter, r state := request.Request{W: w, Req: r} clientIP = netutils.ExtractEdnsSubnet(r) indexKey := netutils.StripClosingDot(state.QName()) - var ep = k8sctrl.Resources.DNSEndpoint.Lookup(indexKey, clientIP) + var ep = k8sctrl.Resources.DNSEndpoint.Lookup(indexKey, clientIP, "") // weights are not defined, labels doesnt exists if len(ep.Labels) == 1 && strings.ToUpper(ep.Labels["strategy"]) == "ROUNDROBIN" { if err := (&loadbalance.RoundRobinResponseWriter{ResponseWriter: w}).WriteMsg(r); err != nil { diff --git a/service/wrr/wrr_test.go b/service/wrr/wrr_test.go index d1a241e..ea1dcb2 100644 --- a/service/wrr/wrr_test.go +++ b/service/wrr/wrr_test.go @@ -139,7 +139,7 @@ func TestWeightRoundRobin(t *testing.T) { }, writer: newFakeWriter(ctrl, func(w *mocks.MockResponseWriter) {}), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Targets: []string{"10.0.0.1", "10.0.0.2"}, @@ -159,7 +159,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin"}, @@ -178,7 +178,7 @@ func TestWeightRoundRobin(t *testing.T) { }, writer: newFakeWriter(ctrl, func(w *mocks.MockResponseWriter) {}), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-0-eu": "10.240.0.1"}, @@ -200,7 +200,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-0-eu-1": "10.240.0.1", "weight-0-us-1": "10.240.0.2"}, @@ -221,7 +221,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-eu-0-1": "10.240.0.1"}, @@ -242,7 +242,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-eu-0-100": "10.240.0.1"}, @@ -264,7 +264,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(0) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-us-0-50": "10.240.0.1"}, @@ -286,7 +286,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(0) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-eu-0-50": "10.240.0.1", "weight-us-0-50": "10.240.0.2"}, @@ -308,7 +308,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(fmt.Errorf("broken writer")).Times(0) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-eu-0-50": "10.240.0.1", "weight-us-0-50": "10.240.1.1"}, @@ -330,7 +330,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-us-0-50": "10.240.0.1", "weight-eu-0-50": "10.240.1.1"}, @@ -351,7 +351,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(fmt.Errorf("broken writer")).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", "weight-eu-0-100": "10.240.0.1"}, @@ -376,7 +376,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).Return(nil).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: map[string]string{"strategy": "roundrobin", @@ -400,7 +400,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).DoAndReturn(rs1.checkExpected).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: rs1.labels, @@ -419,7 +419,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).DoAndReturn(rs4.checkExpected).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: rs4.labels, @@ -438,7 +438,7 @@ func TestWeightRoundRobin(t *testing.T) { w.EXPECT().WriteMsg(gomock.Any()).DoAndReturn(rs2.checkExpected).Times(1) }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: rs2.labels, @@ -456,7 +456,7 @@ func TestWeightRoundRobin(t *testing.T) { writer: newFakeWriter(ctrl, func(w *mocks.MockResponseWriter) { }), expectedError: false, - lookup: func(indexKey string, clientIP net.IP) (result k8sctrl.LocalDNSEndpoint) { + lookup: func(indexKey string, clientIP net.IP, _ string, _ ...string) (result k8sctrl.LocalDNSEndpoint) { return k8sctrl.LocalDNSEndpoint{ DNSName: host, Labels: rs3.labels, diff --git a/setup.go b/setup.go index ebdc49d..c2a2bf7 100644 --- a/setup.go +++ b/setup.go @@ -32,14 +32,16 @@ import ( ) type args struct { - annotation string - apex string - filter string - kubecontroller string - loadbalance string - negttl uint32 - ttl uint32 - zones []string + annotation string + apex string + filter string + kubecontroller string + loadbalance string + negttl uint32 + ttl uint32 + zones []string + geoDataFilePath string + geoDataField string } const thisPlugin = "k8s_crd" @@ -62,7 +64,7 @@ func setup(c *caddy.Controller) error { if err != nil { return plugin.Error(thisPlugin, err) } - gwopts := gateway.NewGatewayOpts(rawArgs.annotation, rawArgs.apex, rawArgs.ttl, rawArgs.negttl, rawArgs.zones) + gwopts := gateway.NewGatewayOpts(rawArgs.annotation, rawArgs.apex, rawArgs.geoDataFilePath, rawArgs.geoDataField, rawArgs.ttl, rawArgs.negttl, rawArgs.zones) _ = k8sCRD.container.Register(gateway.NewGateway(gwopts)) if rawArgs.loadbalance == weightRoundRobin { _ = k8sCRD.container.Register(wrr.NewWeightRoundRobin()) @@ -123,6 +125,12 @@ func parse(c *caddy.Controller) (args, error) { case "loadbalance": log.Infof("loadbalance: %+v", args) a.loadbalance = args[0] + case "geodatafilepath": + log.Infof("geodatafilepath: %+v", args) + a.geoDataFilePath = args[0] + case "geodatafield": + log.Infof("geodatafield: %+v", args) + a.geoDataField = args[0] default: return a, c.Errf("Unknown property '%s'", c.Val()) } diff --git a/terratest/test/basic_test.go b/terratest/test/basic_test.go index d1c735e..9839a21 100644 --- a/terratest/test/basic_test.go +++ b/terratest/test/basic_test.go @@ -35,7 +35,6 @@ import ( ) func TestBasicExample(t *testing.T) { - t.Parallel() var coreDNSPods []corev1.Pod