diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index ec21778b0..c54cdf0cd 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -3,7 +3,7 @@ This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster on Azure. -Make sure to use **>=0.5.7** version of ExternalDNS for this tutorial. +Make sure to use **>=0.11.0** version of ExternalDNS for this tutorial. This tutorial uses [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) for all Azure commands and assumes that the Kubernetes cluster was created via Azure Container Services and `kubectl` commands @@ -149,6 +149,8 @@ The contents of `azure.json` should be similar to this: } ``` +*NOTE:* If there are multiple user assigned identitys available add "userAssignedIdentityID": "" to the json + If you have all the information necessary: create a file called azure.json containing the json structure above and substitute the values. Otherwise create a service principal as previously shown before creating the Kubernetes secret. Then add the secret to the Kubernetes cluster before continuing: @@ -191,7 +193,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.8.0 + image: k8s.gcr.io/external-dns/external-dns:v0.11.0 args: - --source=service - --source=ingress @@ -207,7 +209,7 @@ spec: secret: secretName: azure-config-file items: - - key: externaldns-config.json + - key: azure.json path: azure.json ``` @@ -223,15 +225,18 @@ kind: ClusterRole metadata: name: external-dns rules: -- apiGroups: [""] - resources: ["services","endpoints","pods"] - verbs: ["get","watch","list"] -- apiGroups: ["extensions","networking.k8s.io"] - resources: ["ingresses"] - verbs: ["get","watch","list"] -- apiGroups: [""] - resources: ["nodes"] - verbs: ["list"] + - apiGroups: [''] + resources: ['endpoints', 'pods', 'services'] + verbs: ['get', 'watch', 'list'] + - apiGroups: ['extensions'] + resources: ['ingresses'] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get","watch","list"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["watch", "list"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -281,7 +286,7 @@ spec: secret: secretName: azure-config-file items: - - key: externaldns-config.json + - key: azure.json path: azure.json ``` @@ -354,7 +359,7 @@ spec: secret: secretName: azure-config-file items: - - key: externaldns-config.json + - key: azure.json path: azure.json ``` diff --git a/docs/tutorials/hostport.md b/docs/tutorials/hostport.md index 75512fdf4..774a756a6 100644 --- a/docs/tutorials/hostport.md +++ b/docs/tutorials/hostport.md @@ -198,3 +198,35 @@ kafka-1.ksvc.example.org kafka-2.ksvc.example.org ``` +#### Using pods' HostIPs as targets + +Add the following annotation to your `Service`: + +```yaml +external-dns.alpha.kubernetes.io/endpoints-type: HostIP +``` + +external-dns will now publish the value of the `.status.hostIP` field of the pods backing your `Service`. +``` + +#### Using node external IPs as targets + +Add the following annotation to your `Service`: + +```yaml +external-dns.alpha.kubernetes.io/endpoints-type: NodeExternalIP +``` + +external-dns will now publish the node external IP (`.status.addresses` entries of with `type: NodeExternalIP`) of the nodes on which the pods backing your `Service` are running. + +#### Using pod annotations to specify target IPs + +Add the following annotation to the **pods** backing your `Service`: + +```yaml +external-dns.alpha.kubernetes.io/target: "1.2.3.4" +``` + +external-dns will publish the IP specified in the annotation of each pod instead of using the podIP advertised by Kubernetes. + +This can be useful e.g. if you are NATing public IPs onto your pod IPs and want to publish these in DNS. diff --git a/go.mod b/go.mod index c58df44e4..7f9b2f9b0 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/alecthomas/kingpin v2.2.5+incompatible github.com/aliyun/alibaba-cloud-sdk-go v1.61.1483 github.com/aws/aws-sdk-go v1.42.52 - github.com/bodgit/tsig v0.0.2 + github.com/bodgit/tsig v1.2.0 github.com/cloudflare/cloudflare-go v0.25.0 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 github.com/datawire/ambassador v1.6.0 @@ -36,7 +36,7 @@ require ( github.com/linki/instrumented_http v0.3.0 github.com/linode/linodego v0.32.2 github.com/maxatome/go-testdeep v1.11.0 - github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 + github.com/miekg/dns v1.1.48 github.com/nesv/go-dynect v0.6.0 github.com/nic-at/rc0go v1.1.1 github.com/onsi/ginkgo v1.16.5 @@ -45,8 +45,8 @@ require ( github.com/oracle/oci-go-sdk v24.3.0+incompatible github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 github.com/pkg/errors v0.9.1 - github.com/projectcontour/contour v1.20.0 - github.com/prometheus/client_golang v1.11.0 + github.com/projectcontour/contour v1.20.1 + github.com/prometheus/client_golang v1.11.1 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 @@ -58,7 +58,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.2 go.etcd.io/etcd/client/v3 v3.5.2 go.uber.org/ratelimit v0.2.0 - golang.org/x/net v0.0.0-20220325170049-de3da57026de + golang.org/x/net v0.0.0-20220412020605-290c469a71a5 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a golang.org/x/sync v0.0.0-20210220032951-036812b2e83c google.golang.org/api v0.74.0 @@ -96,6 +96,7 @@ require ( github.com/go-openapi/strfmt v0.20.1 // indirect github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-logr/logr v1.2.0 // indirect github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/gofrs/uuid v3.2.0+incompatible // indirect @@ -110,7 +111,7 @@ require ( github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect - github.com/hashicorp/go-multierror v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/imdario/mergo v0.3.12 // indirect @@ -118,8 +119,9 @@ require ( github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.0.0 // indirect github.com/jcmturner/goidentity/v6 v6.0.1 // indirect - github.com/jcmturner/gokrb5/v8 v8.4.1 // indirect - github.com/jcmturner/rpc/v2 v2.0.2 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/jinzhu/copier v0.3.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.0 // indirect @@ -149,11 +151,14 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect + golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb // indirect google.golang.org/grpc v1.45.0 // indirect diff --git a/go.sum b/go.sum index 4e5d9e3a1..0dddea2a7 100644 --- a/go.sum +++ b/go.sum @@ -224,6 +224,8 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bodgit/tsig v0.0.2 h1:seNt23SrPW8dkWoyRYzdeuqFEzr+lDc0dAJvo94xB8U= github.com/bodgit/tsig v0.0.2/go.mod h1:0mYe0t9it36SOvDQyeFekc7bLtvljFz7H9vHS/nYbgc= +github.com/bodgit/tsig v1.2.0 h1:wNfc7yTk2OuWh/s7nEFa9h+SkIfTn7e4xlFtf1Sgvr4= +github.com/bodgit/tsig v1.2.0/go.mod h1:bsN2ntwGE/s3EeoawjAoKUcAfO4Fr0nGKC72vNF/cqM= github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= @@ -436,6 +438,7 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= @@ -700,6 +703,7 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -739,6 +743,8 @@ github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1: github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= @@ -802,10 +808,16 @@ github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJA github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.1 h1:IGSJfqBzMS6TA0oJ7DxXdyzPK563QHa8T2IqER2ggyQ= github.com/jcmturner/gokrb5/v8 v8.4.1/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jetstack/cert-manager v1.5.1/go.mod h1:YGW5O4iuy9SvAfnXCjZOu0B5Upsvg/FaWaqm5UuwkdI= +github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= +github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -938,6 +950,9 @@ github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7 github.com/miekg/dns v1.1.34/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 h1:kZZmnTeY2r+88mDNCVV/uCXL2gG3rkVPTN9jcYfGQcI= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= @@ -1094,8 +1109,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/projectcontour/contour v1.20.0 h1:rgLAV/jn191Sm2Dxl1Qt4uBxev+91ChHEReErOoKTTs= -github.com/projectcontour/contour v1.20.0/go.mod h1:89iazZsq4zyVXPlhFUw+LeseZKmXCJkrbBelWlskXJc= +github.com/projectcontour/contour v1.20.1 h1:HpGlFhy+qH25b0SJDQmMCNORFEXTaEwVK9K/TJc4Xkc= +github.com/projectcontour/contour v1.20.1/go.mod h1:AEl8+/Hs8w4xC7LE5pReiUUaqLXUka/+daJ1mE7sp1E= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= @@ -1106,8 +1121,9 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1402,11 +1418,16 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1444,6 +1465,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1514,6 +1537,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1627,6 +1652,7 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1656,6 +1682,8 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 h1:eJv7u3ksNXoLbGSKuv2s/SIO4tJVxc/A+MTpzxDgz/Q= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1765,12 +1793,17 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go index 21fab5f88..f72ecd172 100644 --- a/provider/rfc2136/rfc2136.go +++ b/provider/rfc2136/rfc2136.go @@ -25,7 +25,6 @@ import ( "time" "github.com/bodgit/tsig" - extendedClient "github.com/bodgit/tsig/client" "github.com/bodgit/tsig/gss" "github.com/miekg/dns" @@ -75,7 +74,9 @@ var ( tsigAlgs = map[string]string{ "hmac-md5": dns.HmacMD5, "hmac-sha1": dns.HmacSHA1, + "hmac-sha224": dns.HmacSHA224, "hmac-sha256": dns.HmacSHA256, + "hmac-sha384": dns.HmacSHA384, "hmac-sha512": dns.HmacSHA512, } ) @@ -127,8 +128,8 @@ func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, k } // KeyName will return TKEY name and TSIG handle to use for followon actions with a secure connection -func (r rfc2136Provider) KeyData() (keyName *string, handle *gss.GSS, err error) { - handle, err = gss.New() +func (r rfc2136Provider) KeyData() (keyName string, handle *gss.Client, err error) { + handle, err = gss.NewClient(new(dns.Client)) if err != nil { return keyName, handle, err } @@ -394,7 +395,7 @@ func (r rfc2136Provider) SendMessage(msg *dns.Msg) error { } log.Debugf("SendMessage") - c := new(extendedClient.Client) + c := new(dns.Client) c.SingleInflight = true if !r.insecure { @@ -406,17 +407,11 @@ func (r rfc2136Provider) SendMessage(msg *dns.Msg) error { defer handle.Close() defer handle.DeleteContext(keyName) - c.TsigAlgorithm = map[string]*extendedClient.TsigAlgorithm{ - tsig.GSS: { - Generate: handle.GenerateGSS, - Verify: handle.VerifyGSS, - }, - } - c.TsigSecret = map[string]string{*keyName: ""} + c.TsigProvider = handle - msg.SetTsig(*keyName, tsig.GSS, clockSkew, time.Now().Unix()) + msg.SetTsig(keyName, tsig.GSS, clockSkew, time.Now().Unix()) } else { - c.TsigSecret = map[string]string{r.tsigKeyName: r.tsigSecret} + c.TsigProvider = tsig.HMAC{r.tsigKeyName: r.tsigSecret} msg.SetTsig(r.tsigKeyName, r.tsigSecretAlg, clockSkew, time.Now().Unix()) } } diff --git a/source/service.go b/source/service.go index ef3acd97d..9c47579dd 100644 --- a/source/service.go +++ b/source/service.go @@ -259,11 +259,13 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri pods, err := sc.podInformer.Lister().Pods(svc.Namespace).List(selector) if err != nil { - log.Errorf("List Pods of service[%s] error:%v", svc.GetName(), err) + log.Errorf("List pods of service[%s] error: %v", svc.GetName(), err) return endpoints } - targetsByHeadlessDomain := make(map[string][]string) + endpointsType := getEndpointsTypeFromAnnotations(svc.Annotations) + + targetsByHeadlessDomain := make(map[string]endpoint.Targets) for _, subset := range endpointsObject.Subsets { addresses := subset.Addresses if svc.Spec.PublishNotReadyAddresses || sc.alwaysPublishNotReadyAddresses { @@ -294,15 +296,29 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri } for _, headlessDomain := range headlessDomains { - var ep string - if sc.publishHostIP { - ep = pod.Status.HostIP - log.Debugf("Generating matching endpoint %s with HostIP %s", headlessDomain, ep) - } else { - ep = address.IP - log.Debugf("Generating matching endpoint %s with EndpointAddress IP %s", headlessDomain, ep) + targets := getTargetsFromTargetAnnotation(pod.Annotations) + if len(targets) == 0 { + if endpointsType == EndpointsTypeNodeExternalIP { + node, err := sc.nodeInformer.Lister().Get(pod.Spec.NodeName) + if err != nil { + log.Errorf("Get node[%s] of pod[%s] error: %v; not adding any NodeExternalIP endpoints", pod.Spec.NodeName, pod.GetName(), err) + return endpoints + } + for _, address := range node.Status.Addresses { + if address.Type == v1.NodeExternalIP { + targets = endpoint.Targets{address.Address} + log.Debugf("Generating matching endpoint %s with NodeExternalIP %s", headlessDomain, address.Address) + } + } + } else if endpointsType == EndpointsTypeHostIP || sc.publishHostIP { + targets = endpoint.Targets{pod.Status.HostIP} + log.Debugf("Generating matching endpoint %s with HostIP %s", headlessDomain, pod.Status.HostIP) + } else { + targets = endpoint.Targets{address.IP} + log.Debugf("Generating matching endpoint %s with EndpointAddress IP %s", headlessDomain, address.IP) + } } - targetsByHeadlessDomain[headlessDomain] = append(targetsByHeadlessDomain[headlessDomain], ep) + targetsByHeadlessDomain[headlessDomain] = append(targetsByHeadlessDomain[headlessDomain], targets...) } } } diff --git a/source/service_test.go b/source/service_test.go index a13e15169..3fffc256c 100644 --- a/source/service_test.go +++ b/source/service_test.go @@ -2008,15 +2008,18 @@ func TestHeadlessServices(t *testing.T) { fqdnTemplate string ignoreHostnameAnnotation bool labels map[string]string - annotations map[string]string + svcAnnotations map[string]string + podAnnotations map[string]string clusterIP string podIPs []string + hostIPs []string selector map[string]string lbs []string podnames []string hostnames []string podsReady []bool publishNotReadyAddresses bool + nodes []v1.Node expected []*endpoint.Endpoint expectError bool }{ @@ -2033,8 +2036,10 @@ func TestHeadlessServices(t *testing.T) { map[string]string{ hostnameAnnotationKey: "service.example.org", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.2"}, + []string{"", ""}, map[string]string{ "component": "foo", }, @@ -2043,6 +2048,7 @@ func TestHeadlessServices(t *testing.T) { []string{"foo-0", "foo-1"}, []bool{true, true}, false, + []v1.Node{}, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, {DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}}, @@ -2063,8 +2069,10 @@ func TestHeadlessServices(t *testing.T) { map[string]string{ hostnameAnnotationKey: "service.example.org", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.2"}, + []string{"", ""}, map[string]string{ "component": "foo", }, @@ -2073,6 +2081,7 @@ func TestHeadlessServices(t *testing.T) { []string{"foo-0", "foo-1"}, []bool{true, true}, false, + []v1.Node{}, []*endpoint.Endpoint{}, false, }, @@ -2090,8 +2099,10 @@ func TestHeadlessServices(t *testing.T) { hostnameAnnotationKey: "service.example.org", ttlAnnotationKey: "1", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.2"}, + []string{"", ""}, map[string]string{ "component": "foo", }, @@ -2100,6 +2111,7 @@ func TestHeadlessServices(t *testing.T) { []string{"foo-0", "foo-1"}, []bool{true, true}, false, + []v1.Node{}, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}, RecordTTL: endpoint.TTL(1)}, {DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}, RecordTTL: endpoint.TTL(1)}, @@ -2120,8 +2132,10 @@ func TestHeadlessServices(t *testing.T) { map[string]string{ hostnameAnnotationKey: "service.example.org", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.2"}, + []string{"", ""}, map[string]string{ "component": "foo", }, @@ -2130,6 +2144,7 @@ func TestHeadlessServices(t *testing.T) { []string{"foo-0", "foo-1"}, []bool{true, false}, false, + []v1.Node{}, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, {DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, @@ -2149,8 +2164,10 @@ func TestHeadlessServices(t *testing.T) { map[string]string{ hostnameAnnotationKey: "service.example.org", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.2"}, + []string{"", ""}, map[string]string{ "component": "foo", }, @@ -2159,6 +2176,7 @@ func TestHeadlessServices(t *testing.T) { []string{"foo-0", "foo-1"}, []bool{true, false}, true, + []v1.Node{}, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, {DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}}, @@ -2179,8 +2197,10 @@ func TestHeadlessServices(t *testing.T) { map[string]string{ hostnameAnnotationKey: "service.example.org", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.2"}, + []string{"", ""}, map[string]string{ "component": "foo", }, @@ -2189,6 +2209,7 @@ func TestHeadlessServices(t *testing.T) { []string{"", ""}, []bool{true, true}, false, + []v1.Node{}, []*endpoint.Endpoint{ {DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1", "1.1.1.2"}}, }, @@ -2207,8 +2228,10 @@ func TestHeadlessServices(t *testing.T) { map[string]string{ hostnameAnnotationKey: "service.example.org", }, + map[string]string{}, v1.ClusterIPNone, []string{"1.1.1.1", "1.1.1.1", "1.1.1.2"}, + []string{"", "", ""}, map[string]string{ "component": "foo", }, @@ -2217,11 +2240,120 @@ func TestHeadlessServices(t *testing.T) { []string{"", "", ""}, []bool{true, true, true}, false, + []v1.Node{}, []*endpoint.Endpoint{ {DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1", "1.1.1.2"}}, }, false, }, + { + "annotated Headless services return targets from pod annotation", + "", + "testing", + "foo", + v1.ServiceTypeClusterIP, + "", + "", + false, + map[string]string{"component": "foo"}, + map[string]string{ + hostnameAnnotationKey: "service.example.org", + }, + map[string]string{ + targetAnnotationKey: "1.2.3.4", + }, + v1.ClusterIPNone, + []string{"1.1.1.1"}, + []string{""}, + map[string]string{ + "component": "foo", + }, + []string{}, + []string{"foo"}, + []string{"", "", ""}, + []bool{true, true, true}, + false, + []v1.Node{}, + []*endpoint.Endpoint{ + {DNSName: "service.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + }, + false, + }, + { + "annotated Headless services return targets from node external IP if endpoints-type annotation is set", + "", + "testing", + "foo", + v1.ServiceTypeClusterIP, + "", + "", + false, + map[string]string{"component": "foo"}, + map[string]string{ + hostnameAnnotationKey: "service.example.org", + endpointsTypeAnnotationKey: EndpointsTypeNodeExternalIP, + }, + map[string]string{}, + v1.ClusterIPNone, + []string{"1.1.1.1"}, + []string{""}, + map[string]string{ + "component": "foo", + }, + []string{}, + []string{"foo"}, + []string{"", "", ""}, + []bool{true, true, true}, + false, + []v1.Node{ + { + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + { + Type: v1.NodeExternalIP, + Address: "1.2.3.4", + }, + }, + }, + }, + }, + []*endpoint.Endpoint{ + {DNSName: "service.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + }, + false, + }, + { + "annotated Headless services return targets from hostIP if endpoints-type annotation is set", + "", + "testing", + "foo", + v1.ServiceTypeClusterIP, + "", + "", + false, + map[string]string{"component": "foo"}, + map[string]string{ + hostnameAnnotationKey: "service.example.org", + endpointsTypeAnnotationKey: EndpointsTypeHostIP, + }, + map[string]string{}, + v1.ClusterIPNone, + []string{"1.1.1.1"}, + []string{"1.2.3.4"}, + map[string]string{ + "component": "foo", + }, + []string{}, + []string{"foo"}, + []string{"", "", ""}, + []bool{true, true, true}, + false, + []v1.Node{}, + []*endpoint.Endpoint{ + {DNSName: "service.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + }, + false, + }, } { tc := tc t.Run(tc.title, func(t *testing.T) { @@ -2241,7 +2373,7 @@ func TestHeadlessServices(t *testing.T) { Namespace: tc.svcNamespace, Name: tc.svcName, Labels: tc.labels, - Annotations: tc.annotations, + Annotations: tc.svcAnnotations, }, Status: v1.ServiceStatus{}, } @@ -2259,10 +2391,11 @@ func TestHeadlessServices(t *testing.T) { Namespace: tc.svcNamespace, Name: podname, Labels: tc.labels, - Annotations: tc.annotations, + Annotations: tc.podAnnotations, }, Status: v1.PodStatus{ - PodIP: tc.podIPs[i], + PodIP: tc.podIPs[i], + HostIP: tc.hostIPs[i], }, } @@ -2298,6 +2431,10 @@ func TestHeadlessServices(t *testing.T) { } _, err = kubernetes.CoreV1().Endpoints(tc.svcNamespace).Create(context.Background(), endpointsObject, metav1.CreateOptions{}) require.NoError(t, err) + for _, node := range tc.nodes { + _, err = kubernetes.CoreV1().Nodes().Create(context.Background(), &node, metav1.CreateOptions{}) + require.NoError(t, err) + } // Create our object under test and get the endpoints. client, _ := NewServiceSource( diff --git a/source/source.go b/source/source.go index dc3c26d65..da9909923 100644 --- a/source/source.go +++ b/source/source.go @@ -44,6 +44,8 @@ const ( hostnameAnnotationKey = "external-dns.alpha.kubernetes.io/hostname" // The annotation used for specifying whether the public or private interface address is used accessAnnotationKey = "external-dns.alpha.kubernetes.io/access" + // The annotation used for specifying the type of endpoints to use for headless services + endpointsTypeAnnotationKey = "external-dns.alpha.kubernetes.io/endpoints-type" // The annotation used for defining the desired ingress target targetAnnotationKey = "external-dns.alpha.kubernetes.io/target" // The annotation used for defining the desired DNS record TTL @@ -59,6 +61,11 @@ const ( internalHostnameAnnotationKey = "external-dns.alpha.kubernetes.io/internal-hostname" ) +const ( + EndpointsTypeNodeExternalIP = "NodeExternalIP" + EndpointsTypeHostIP = "HostIP" +) + // Provider-specific annotations const ( // The annotation used for determining if traffic will go through Cloudflare @@ -151,6 +158,10 @@ func getAccessFromAnnotations(annotations map[string]string) string { return annotations[accessAnnotationKey] } +func getEndpointsTypeFromAnnotations(annotations map[string]string) string { + return annotations[endpointsTypeAnnotationKey] +} + func getInternalHostnamesFromAnnotations(annotations map[string]string) []string { internalHostnameAnnotation, exists := annotations[internalHostnameAnnotationKey] if !exists {