From 8d52be27552ff45f922f01ace386e09ef8244412 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:07:01 -0700 Subject: [PATCH 01/10] template functions: replaceAll, isIPv6, isIPv4 --- source/source.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/source.go b/source/source.go index 132f40dcd9..960ef68cbc 100644 --- a/source/source.go +++ b/source/source.go @@ -143,12 +143,15 @@ func execTemplate(tmpl *template.Template, obj kubeObject) (hostnames []string, return hostnames, nil } -func parseTemplate(fqdnTemplate string) (tmpl *template.Template, err error) { +func parseTemplate(fqdnTemplate string, ) (tmpl *template.Template, err error) { if fqdnTemplate == "" { return nil, nil } funcs := template.FuncMap{ "trimPrefix": strings.TrimPrefix, + "replaceAll": strings.ReplaceAll, + "isIPv6": isIPv6String, + "isIPv4": isIPv4String, } return template.New("endpoint").Funcs(funcs).Parse(fqdnTemplate) } @@ -393,3 +396,8 @@ func isIPv6String(ip string) bool { netIP := net.ParseIP(ip) return netIP != nil && netIP.To4() == nil } + +func isIPv4String(input string) bool { + netIP := net.ParseIP(input) + return netIP != nil && netIP.To4() != nil +} From b37cb516ee6e6275dfac4e7477c95f452fb87925 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:25:26 -0700 Subject: [PATCH 02/10] typeo --- source/source.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/source.go b/source/source.go index 960ef68cbc..5a8189c605 100644 --- a/source/source.go +++ b/source/source.go @@ -143,7 +143,7 @@ func execTemplate(tmpl *template.Template, obj kubeObject) (hostnames []string, return hostnames, nil } -func parseTemplate(fqdnTemplate string, ) (tmpl *template.Template, err error) { +func parseTemplate(fqdnTemplate string) (tmpl *template.Template, err error) { if fqdnTemplate == "" { return nil, nil } From b5a6cbd12bf1522278d2a445ebe695bf31601d7e Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:05:38 -0700 Subject: [PATCH 03/10] unit test --- source/node_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/node_test.go b/source/node_test.go index bf047bae84..179ec9f285 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -61,6 +61,11 @@ func testNodeSourceNewNodeSource(t *testing.T) { expectError: false, fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com", }, + { + title: "complex template", + expectError: false, + fqdnTemplate: "{{range .Status.Addresses}}{{if and (eq .Type \"ExternalIP\") (isIPv4 .Address)}}{{replaceAll .Address \".\" \"-\"}}{{break}}{{end}}{{end}}.ext-dns.test.com", + }, { title: "non-empty annotation filter label", expectError: false, From 3f77b0abf7e5ab3833c92edb664a01766ece282f Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:13:38 -0700 Subject: [PATCH 04/10] docs --- docs/sources/nodes.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/sources/nodes.md b/docs/sources/nodes.md index ca88b44f5a..99569a84af 100644 --- a/docs/sources/nodes.md +++ b/docs/sources/nodes.md @@ -6,6 +6,7 @@ Using nodes (`--source=node`) as source is possible to synchronize a DNS zone wi The node source adds an `A` record per each node `externalIP` (if not found, any IPv4 `internalIP` is used instead). It also adds an `AAAA` record per each node IPv6 `internalIP`. The TTL of the records can be set with the `external-dns.alpha.kubernetes.io/ttl` node annotation. +The FQDN template includes a function to replace all `.` with `-` in the node name, which is useful for cloud providers that include dots in the node name. Nodes marked as **Unschedulable** as per [core/v1/NodeSpec](https://pkg.go.dev/k8s.io/api@v0.31.1/core/v1#NodeSpec) are excluded. This avoid exposing Unhealthy, NotReady or SchedulingDisabled (cordon) nodes. @@ -40,7 +41,7 @@ spec: - --domain-filter=external-dns-test.my-org.com - --aws-zone-type=public - --registry=txt - - --fqdn-template={{.Name}}.external-dns-test.my-org.com + - --fqdn-template={{replaceAll .Name "." "-"}}.external-dns-test.my-org.com - --txt-owner-id=my-identifier - --policy=sync - --log-level=debug @@ -111,8 +112,9 @@ spec: - --domain-filter=external-dns-test.my-org.com - --aws-zone-type=public - --registry=txt - - --fqdn-template={{.Name}}.external-dns-test.my-org.com + - --fqdn-template={{replaceAll .Name "." "-"}}.external-dns-test.my-org.com - --txt-owner-id=my-identifier - --policy=sync - --log-level=debug ``` + From 57980699425112207b0a99597e64a41cff91f7ec Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 26 Oct 2023 18:23:36 -0700 Subject: [PATCH 05/10] johngmyers review: use sprig, fix ipv4 check --- go.mod | 1 + go.sum | 1 + source/source.go | 14 +++++++------- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 106dc71f2e..bbe9770990 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 github.com/go-gandi/go-gandi v0.7.0 github.com/go-logr/logr v1.4.2 + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/gophercloud/gophercloud v1.14.1 diff --git a/go.sum b/go.sum index 4a06b14a8f..751d4c4732 100644 --- a/go.sum +++ b/go.sum @@ -427,6 +427,7 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= diff --git a/source/source.go b/source/source.go index 5a8189c605..893b3aee9f 100644 --- a/source/source.go +++ b/source/source.go @@ -29,6 +29,7 @@ import ( "time" "unicode" + sprig "github.com/go-task/slim-sprig" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -147,12 +148,11 @@ func parseTemplate(fqdnTemplate string) (tmpl *template.Template, err error) { if fqdnTemplate == "" { return nil, nil } - funcs := template.FuncMap{ - "trimPrefix": strings.TrimPrefix, - "replaceAll": strings.ReplaceAll, - "isIPv6": isIPv6String, - "isIPv4": isIPv4String, - } + + funcs := sprig.HermeticTxtFuncMap() + funcs["isIPv6"] = isIPv6String + funcs["isIPv4"] = isIPv4String + return template.New("endpoint").Funcs(funcs).Parse(fqdnTemplate) } @@ -399,5 +399,5 @@ func isIPv6String(ip string) bool { func isIPv4String(input string) bool { netIP := net.ParseIP(input) - return netIP != nil && netIP.To4() != nil + return netIP != nil && netIP.To4() != nil && !strings.Contains(input, ":") } From db35373b89fa79bf3fbb9c444c8727247e1f3226 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 26 Oct 2023 18:31:38 -0700 Subject: [PATCH 06/10] update test and docs --- docs/sources/nodes.md | 4 ++-- source/node_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sources/nodes.md b/docs/sources/nodes.md index 99569a84af..de00dd3d9c 100644 --- a/docs/sources/nodes.md +++ b/docs/sources/nodes.md @@ -41,7 +41,7 @@ spec: - --domain-filter=external-dns-test.my-org.com - --aws-zone-type=public - --registry=txt - - --fqdn-template={{replaceAll .Name "." "-"}}.external-dns-test.my-org.com + - --fqdn-template={{.Name | replace "." "-"}}.external-dns-test.my-org.com - --txt-owner-id=my-identifier - --policy=sync - --log-level=debug @@ -112,7 +112,7 @@ spec: - --domain-filter=external-dns-test.my-org.com - --aws-zone-type=public - --registry=txt - - --fqdn-template={{replaceAll .Name "." "-"}}.external-dns-test.my-org.com + - --fqdn-template={{.Name | replace "." "-"}}.external-dns-test.my-org.com - --txt-owner-id=my-identifier - --policy=sync - --log-level=debug diff --git a/source/node_test.go b/source/node_test.go index 179ec9f285..9f971f2ffa 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -64,7 +64,7 @@ func testNodeSourceNewNodeSource(t *testing.T) { { title: "complex template", expectError: false, - fqdnTemplate: "{{range .Status.Addresses}}{{if and (eq .Type \"ExternalIP\") (isIPv4 .Address)}}{{replaceAll .Address \".\" \"-\"}}{{break}}{{end}}{{end}}.ext-dns.test.com", + fqdnTemplate: "{{range .Status.Addresses}}{{if and (eq .Type \"ExternalIP\") (isIPv4 .Address)}}{{.Address | replace \".\" \"-\"}}{{break}}{{end}}{{end}}.ext-dns.test.com", }, { title: "non-empty annotation filter label", From ae43729c51188a7d5789e5568cc9a02684993727 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:25:44 -0800 Subject: [PATCH 07/10] Update docs/tutorials/nodes.md Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- docs/sources/nodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/nodes.md b/docs/sources/nodes.md index de00dd3d9c..1230f2d953 100644 --- a/docs/sources/nodes.md +++ b/docs/sources/nodes.md @@ -6,7 +6,7 @@ Using nodes (`--source=node`) as source is possible to synchronize a DNS zone wi The node source adds an `A` record per each node `externalIP` (if not found, any IPv4 `internalIP` is used instead). It also adds an `AAAA` record per each node IPv6 `internalIP`. The TTL of the records can be set with the `external-dns.alpha.kubernetes.io/ttl` node annotation. -The FQDN template includes a function to replace all `.` with `-` in the node name, which is useful for cloud providers that include dots in the node name. +The FQDN template provides more than 100+ functions, documented [here](https://go-task.github.io/slim-sprig/). For instance, it includes a function to replace all `.` with `-` in the node name, which can be useful with cloud providers that include dots in the node name. Nodes marked as **Unschedulable** as per [core/v1/NodeSpec](https://pkg.go.dev/k8s.io/api@v0.31.1/core/v1#NodeSpec) are excluded. This avoid exposing Unhealthy, NotReady or SchedulingDisabled (cordon) nodes. From db55aa1996ebd2911d3dfde2e901907f4ae52383 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Mon, 12 Feb 2024 10:42:39 -0800 Subject: [PATCH 08/10] document isIPv4 and isIPv6 template functions --- docs/sources/nodes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/sources/nodes.md b/docs/sources/nodes.md index 1230f2d953..940ad3dfcf 100644 --- a/docs/sources/nodes.md +++ b/docs/sources/nodes.md @@ -6,7 +6,7 @@ Using nodes (`--source=node`) as source is possible to synchronize a DNS zone wi The node source adds an `A` record per each node `externalIP` (if not found, any IPv4 `internalIP` is used instead). It also adds an `AAAA` record per each node IPv6 `internalIP`. The TTL of the records can be set with the `external-dns.alpha.kubernetes.io/ttl` node annotation. -The FQDN template provides more than 100+ functions, documented [here](https://go-task.github.io/slim-sprig/). For instance, it includes a function to replace all `.` with `-` in the node name, which can be useful with cloud providers that include dots in the node name. +The FQDN template provides more than 100+ functions, documented [here](https://go-task.github.io/slim-sprig/). For instance, it includes a function to replace all `.` with `-` in the node name, which can be useful with cloud providers that include dots in the node name. There are two additional functions available on top of the standard sprig functions: `isIPv4` and `isIPv6`. The functions can be used to test a string for being an IPv4 or IPv6 address. Nodes marked as **Unschedulable** as per [core/v1/NodeSpec](https://pkg.go.dev/k8s.io/api@v0.31.1/core/v1#NodeSpec) are excluded. This avoid exposing Unhealthy, NotReady or SchedulingDisabled (cordon) nodes. @@ -117,4 +117,3 @@ spec: - --policy=sync - --log-level=debug ``` - From 664ea01d4abe93a62a1312513590ee33342abb8a Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:17:46 -0800 Subject: [PATCH 09/10] use netip to determine ipv4 and ipv6 --- source/source.go | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/source/source.go b/source/source.go index ef9990ea1e..ada85cda78 100644 --- a/source/source.go +++ b/source/source.go @@ -269,6 +269,25 @@ func suitableType(target string) string { return endpoint.RecordTypeCNAME } +// isIPv6String reports whether the target string is an IPv6 address, +// including IPv4-mapped IPv6 addresses. +func isIPv6String(target string) bool { + netIP, err := netip.ParseAddr(target) + if err != nil { + return false + } + return netIP.Is6() +} + +// isIPv4String reports whether the target string is an IPv4 address. +func isIPv4String(target string) bool { + netIP, err := netip.ParseAddr(target) + if err != nil { + return false + } + return netIP.Is4() +} + // endpointsForHostname returns the endpoint objects for each host-target combination. func endpointsForHostname(hostname string, targets endpoint.Targets, ttl endpoint.TTL, providerSpecific endpoint.ProviderSpecific, setIdentifier string, resource string) []*endpoint.Endpoint { var endpoints []*endpoint.Endpoint @@ -385,14 +404,3 @@ func waitForDynamicCacheSync(ctx context.Context, factory dynamicInformerFactory } return nil } - -// isIPv6String returns if ip is IPv6. -func isIPv6String(ip string) bool { - netIP := net.ParseIP(ip) - return netIP != nil && netIP.To4() == nil -} - -func isIPv4String(input string) bool { - netIP := net.ParseIP(input) - return netIP != nil && netIP.To4() != nil && !strings.Contains(input, ":") -} From 20e5eb968a677cd02e0cbfd6a55d98553e1d1948 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar <578302+matkam@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:21:04 -0800 Subject: [PATCH 10/10] slim-sprig v3 --- go.mod | 2 +- go.sum | 2 -- source/source.go | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index acf239d480..c9705920bb 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 github.com/go-gandi/go-gandi v0.7.0 github.com/go-logr/logr v1.4.2 - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 + github.com/go-task/slim-sprig/v3 v3.0.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/gophercloud/gophercloud v1.14.1 diff --git a/go.sum b/go.sum index 279dc300aa..0d8eb2fb3a 100644 --- a/go.sum +++ b/go.sum @@ -426,8 +426,6 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= diff --git a/source/source.go b/source/source.go index ada85cda78..8c917b5f00 100644 --- a/source/source.go +++ b/source/source.go @@ -29,7 +29,7 @@ import ( "time" "unicode" - sprig "github.com/go-task/slim-sprig" + sprig "github.com/go-task/slim-sprig/v3" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels"