Skip to content

Commit 2f089bd

Browse files
authored
Merge pull request #5304 from gofogo/feat-code-cleanup-01
chore(source): code cleanup
2 parents df28bbe + 68b1cdb commit 2f089bd

33 files changed

+1759
-759
lines changed

provider/cloudflare/cloudflare.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
"sigs.k8s.io/external-dns/endpoint"
3535
"sigs.k8s.io/external-dns/plan"
3636
"sigs.k8s.io/external-dns/provider"
37-
"sigs.k8s.io/external-dns/source"
37+
"sigs.k8s.io/external-dns/source/annotations"
3838
)
3939

4040
const (
@@ -735,17 +735,17 @@ func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]
735735
if proxied {
736736
e.RecordTTL = 0
737737
}
738-
e.SetProviderSpecificProperty(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
738+
e.SetProviderSpecificProperty(annotations.CloudflareProxiedKey, strconv.FormatBool(proxied))
739739

740740
if p.CustomHostnamesConfig.Enabled {
741741
// sort custom hostnames in annotation to properly detect changes
742742
if customHostnames := getEndpointCustomHostnames(e); len(customHostnames) > 1 {
743743
sort.Strings(customHostnames)
744-
e.SetProviderSpecificProperty(source.CloudflareCustomHostnameKey, strings.Join(customHostnames, ","))
744+
e.SetProviderSpecificProperty(annotations.CloudflareCustomHostnameKey, strings.Join(customHostnames, ","))
745745
}
746746
} else {
747747
// ignore custom hostnames annotations if not enabled
748-
e.DeleteProviderSpecificProperty(source.CloudflareCustomHostnameKey)
748+
e.DeleteProviderSpecificProperty(annotations.CloudflareCustomHostnameKey)
749749
}
750750

751751
adjustedEndpoints = append(adjustedEndpoints, e)
@@ -927,10 +927,10 @@ func shouldBeProxied(ep *endpoint.Endpoint, proxiedByDefault bool) bool {
927927
proxied := proxiedByDefault
928928

929929
for _, v := range ep.ProviderSpecific {
930-
if v.Name == source.CloudflareProxiedKey {
930+
if v.Name == annotations.CloudflareProxiedKey {
931931
b, err := strconv.ParseBool(v.Value)
932932
if err != nil {
933-
log.Errorf("Failed to parse annotation [%q]: %v", source.CloudflareProxiedKey, err)
933+
log.Errorf("Failed to parse annotation [%q]: %v", annotations.CloudflareProxiedKey, err)
934934
} else {
935935
proxied = b
936936
}
@@ -950,7 +950,7 @@ func getRegionKey(endpoint *endpoint.Endpoint, defaultRegionKey string) string {
950950
}
951951

952952
for _, v := range endpoint.ProviderSpecific {
953-
if v.Name == source.CloudflareRegionKey {
953+
if v.Name == annotations.CloudflareRegionKey {
954954
return v.Value
955955
}
956956
}
@@ -959,7 +959,7 @@ func getRegionKey(endpoint *endpoint.Endpoint, defaultRegionKey string) string {
959959

960960
func getEndpointCustomHostnames(ep *endpoint.Endpoint) []string {
961961
for _, v := range ep.ProviderSpecific {
962-
if v.Name == source.CloudflareCustomHostnameKey {
962+
if v.Name == annotations.CloudflareCustomHostnameKey {
963963
customHostnames := strings.Split(v.Value, ",")
964964
return customHostnames
965965
}
@@ -1014,11 +1014,11 @@ func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHost
10141014
if e == nil {
10151015
continue
10161016
}
1017-
e = e.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
1018-
// noop (customHostnames is empty) if the custom hostnames feature is not in use
1017+
e = e.WithProviderSpecific(annotations.CloudflareProxiedKey, strconv.FormatBool(proxied))
1018+
// noop (customHostnames is empty) if custom hostnames feature is not in use
10191019
if customHostnames, ok := customHostnames[records[0].Name]; ok {
10201020
sort.Strings(customHostnames)
1021-
e = e.WithProviderSpecific(source.CloudflareCustomHostnameKey, strings.Join(customHostnames, ","))
1021+
e = e.WithProviderSpecific(annotations.CloudflareCustomHostnameKey, strings.Join(customHostnames, ","))
10221022
}
10231023

10241024
endpoints = append(endpoints, e)

source/ambassador_host.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"k8s.io/client-go/tools/cache"
3939

4040
"sigs.k8s.io/external-dns/endpoint"
41+
"sigs.k8s.io/external-dns/source/annotations"
4142
)
4243

4344
// ambHostAnnotation is the annotation in the Host that maps to a Service
@@ -152,7 +153,7 @@ func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
152153
continue
153154
}
154155

155-
targets := getTargetsFromTargetAnnotation(host.Annotations)
156+
targets := annotations.TargetsFromTargetAnnotation(host.Annotations)
156157
if len(targets) == 0 {
157158
targets, err = sc.targetsFromAmbassadorLoadBalancer(ctx, service)
158159
if err != nil {
@@ -187,8 +188,8 @@ func (sc *ambassadorHostSource) endpointsFromHost(host *ambassador.Host, targets
187188
var endpoints []*endpoint.Endpoint
188189

189190
resource := fmt.Sprintf("host/%s/%s", host.Namespace, host.Name)
190-
providerSpecific, setIdentifier := getProviderSpecificAnnotations(host.Annotations)
191-
ttl := getTTLFromAnnotations(host.Annotations, resource)
191+
providerSpecific, setIdentifier := annotations.ProviderSpecificAnnotations(host.Annotations)
192+
ttl := annotations.TTLFromAnnotations(host.Annotations, resource)
192193

193194
if host.Spec != nil {
194195
hostname := host.Spec.Hostname

source/ambassador_host_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
fakeDynamic "k8s.io/client-go/dynamic/fake"
3434
fakeKube "k8s.io/client-go/kubernetes/fake"
3535
"sigs.k8s.io/external-dns/endpoint"
36+
"sigs.k8s.io/external-dns/source/annotations"
3637
)
3738

3839
const defaultAmbassadorNamespace = "ambassador"
@@ -246,8 +247,8 @@ func TestAmbassadorHostSource(t *testing.T) {
246247
ObjectMeta: metav1.ObjectMeta{
247248
Name: "basic-host",
248249
Annotations: map[string]string{
249-
ambHostAnnotation: hostAnnotation,
250-
CloudflareProxiedKey: "true",
250+
ambHostAnnotation: hostAnnotation,
251+
annotations.CloudflareProxiedKey: "true",
251252
},
252253
},
253254
Spec: &ambassador.HostSpec{

source/annotations/annotations.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package annotations
15+
16+
import (
17+
"math"
18+
)
19+
20+
const (
21+
// CloudflareProxiedKey The annotation used for determining if traffic will go through Cloudflare
22+
CloudflareProxiedKey = "external-dns.alpha.kubernetes.io/cloudflare-proxied"
23+
CloudflareCustomHostnameKey = "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname"
24+
CloudflareRegionKey = "external-dns.alpha.kubernetes.io/cloudflare-region-key"
25+
26+
AWSPrefix = "external-dns.alpha.kubernetes.io/aws-"
27+
SCWPrefix = "external-dns.alpha.kubernetes.io/scw-"
28+
IBMCloudPrefix = "external-dns.alpha.kubernetes.io/ibmcloud-"
29+
WebhookPrefix = "external-dns.alpha.kubernetes.io/webhook-"
30+
CloudflarePrefix = "external-dns.alpha.kubernetes.io/cloudflare-"
31+
32+
TtlKey = "external-dns.alpha.kubernetes.io/ttl"
33+
ttlMinimum = 1
34+
ttlMaximum = math.MaxInt32
35+
36+
SetIdentifierKey = "external-dns.alpha.kubernetes.io/set-identifier"
37+
AliasKey = "external-dns.alpha.kubernetes.io/alias"
38+
TargetKey = "external-dns.alpha.kubernetes.io/target"
39+
// The annotation used for figuring out which controller is responsible
40+
ControllerKey = "external-dns.alpha.kubernetes.io/controller"
41+
// The annotation used for defining the desired hostname
42+
HostnameKey = "external-dns.alpha.kubernetes.io/hostname"
43+
// The annotation used for specifying whether the public or private interface address is used
44+
AccessKey = "external-dns.alpha.kubernetes.io/access"
45+
// The annotation used for specifying the type of endpoints to use for headless services
46+
EndpointsTypeKey = "external-dns.alpha.kubernetes.io/endpoints-type"
47+
// The annotation used to determine the source of hostnames for ingresses. This is an optional field - all
48+
// available hostname sources are used if not specified.
49+
IngressHostnameSourceKey = "external-dns.alpha.kubernetes.io/ingress-hostname-source"
50+
// The value of the controller annotation so that we feel responsible
51+
ControllerValue = "dns-controller"
52+
// The annotation used for defining the desired hostname
53+
InternalHostnameKey = "external-dns.alpha.kubernetes.io/internal-hostname"
54+
)

source/annotations/processors.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package annotations
15+
16+
import (
17+
"strconv"
18+
"strings"
19+
"time"
20+
21+
log "github.com/sirupsen/logrus"
22+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
"k8s.io/apimachinery/pkg/labels"
24+
25+
"sigs.k8s.io/external-dns/endpoint"
26+
)
27+
28+
func hasAliasFromAnnotations(annotations map[string]string) bool {
29+
aliasAnnotation, ok := annotations[AliasKey]
30+
return ok && aliasAnnotation == "true"
31+
}
32+
33+
// TTLFromAnnotations extracts the TTL from the annotations of the given resource.
34+
func TTLFromAnnotations(annotations map[string]string, resource string) endpoint.TTL {
35+
ttlNotConfigured := endpoint.TTL(0)
36+
ttlAnnotation, ok := annotations[TtlKey]
37+
if !ok {
38+
return ttlNotConfigured
39+
}
40+
ttlValue, err := parseTTL(ttlAnnotation)
41+
if err != nil {
42+
log.Warnf("%s: %q is not a valid TTL value: %v", resource, ttlAnnotation, err)
43+
return ttlNotConfigured
44+
}
45+
if ttlValue < ttlMinimum || ttlValue > ttlMaximum {
46+
log.Warnf("TTL value %q must be between [%d, %d]", ttlValue, ttlMinimum, ttlMaximum)
47+
return ttlNotConfigured
48+
}
49+
return endpoint.TTL(ttlValue)
50+
}
51+
52+
// parseTTL parses TTL from string, returning duration in seconds.
53+
// parseTTL supports both integers like "600" and durations based
54+
// on Go Duration like "10m", hence "600" and "10m" represent the same value.
55+
//
56+
// Note: for durations like "1.5s" the fraction is omitted (resulting in 1 second for the example).
57+
func parseTTL(s string) (int64, error) {
58+
ttlDuration, errDuration := time.ParseDuration(s)
59+
if errDuration != nil {
60+
ttlInt, err := strconv.ParseInt(s, 10, 64)
61+
if err != nil {
62+
return 0, errDuration
63+
}
64+
return ttlInt, nil
65+
}
66+
67+
return int64(ttlDuration.Seconds()), nil
68+
}
69+
70+
// ParseFilter parses an annotation filter string into a labels.Selector.
71+
// Returns nil if the annotation filter is invalid.
72+
func ParseFilter(annotationFilter string) (labels.Selector, error) {
73+
labelSelector, err := metav1.ParseToLabelSelector(annotationFilter)
74+
if err != nil {
75+
return nil, err
76+
}
77+
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
78+
if err != nil {
79+
return nil, err
80+
}
81+
return selector, nil
82+
}
83+
84+
// TargetsFromTargetAnnotation gets endpoints from optional "target" annotation.
85+
// Returns empty endpoints array if none are found.
86+
func TargetsFromTargetAnnotation(annotations map[string]string) endpoint.Targets {
87+
var targets endpoint.Targets
88+
// Get the desired hostname of the ingress from the annotation.
89+
targetAnnotation, ok := annotations[TargetKey]
90+
if ok && targetAnnotation != "" {
91+
// splits the hostname annotation and removes the trailing periods
92+
targetsList := SplitHostnameAnnotation(targetAnnotation)
93+
for _, targetHostname := range targetsList {
94+
targetHostname = strings.TrimSuffix(targetHostname, ".")
95+
targets = append(targets, targetHostname)
96+
}
97+
}
98+
return targets
99+
}
100+
101+
// HostnamesFromAnnotations extracts the hostnames from the given annotations map.
102+
// It returns a slice of hostnames if the HostnameKey annotation is present, otherwise it returns nil.
103+
func HostnamesFromAnnotations(input map[string]string) []string {
104+
return extractHostnamesFromAnnotations(input, HostnameKey)
105+
}
106+
107+
// InternalHostnamesFromAnnotations extracts the internal hostnames from the given annotations map.
108+
// It returns a slice of internal hostnames if the InternalHostnameKey annotation is present, otherwise it returns nil.
109+
func InternalHostnamesFromAnnotations(input map[string]string) []string {
110+
return extractHostnamesFromAnnotations(input, InternalHostnameKey)
111+
}
112+
113+
// SplitHostnameAnnotation splits a comma-separated hostname annotation string into a slice of hostnames.
114+
// It trims any leading or trailing whitespace and removes any spaces within the anno
115+
func SplitHostnameAnnotation(input string) []string {
116+
return strings.Split(strings.TrimSpace(strings.ReplaceAll(input, " ", "")), ",")
117+
}
118+
119+
func extractHostnamesFromAnnotations(input map[string]string, key string) []string {
120+
annotation, ok := input[key]
121+
if !ok {
122+
return nil
123+
}
124+
return SplitHostnameAnnotation(annotation)
125+
}

0 commit comments

Comments
 (0)