Skip to content

Commit d9e1c2c

Browse files
committed
using functional interfaces for future cleaners and validators of other record types
Signed-off-by: hfuss <[email protected]>
1 parent f8546f3 commit d9e1c2c

File tree

6 files changed

+130
-12
lines changed

6 files changed

+130
-12
lines changed

endpoint/endpoint.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,17 @@ func NewEndpoint(dnsName, recordType string, targets ...string) *Endpoint {
255255
// NewEndpointWithTTL initialization method to be used to create an endpoint with a TTL struct
256256
func NewEndpointWithTTL(dnsName, recordType string, ttl TTL, targets ...string) *Endpoint {
257257
cleanTargets := make([]string, len(targets))
258-
for idx, target := range targets {
258+
var cleaner endpointTargetCleaner
259+
switch recordType {
260+
case RecordTypeTXT, RecordTypeNAPTR:
259261
// Only trim trailing dots for domain name record types, not for TXT or NAPTR records
260262
// TXT records can contain arbitrary text including multiple dots
261-
switch recordType {
262-
case RecordTypeTXT, RecordTypeNAPTR:
263-
cleanTargets[idx] = target
264-
default:
265-
cleanTargets[idx] = strings.TrimSuffix(target, ".")
266-
}
263+
cleaner = &arbitraryTextEndpointTargetCleaner{}
264+
default:
265+
cleaner = &defaultEndpointTargetCleaner{}
266+
}
267+
for idx, target := range targets {
268+
cleanTargets[idx] = cleaner.Clean(target)
267269
}
268270

269271
for label := range strings.SplitSeq(dnsName, ".") {

endpoint/target_cleaner.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package endpoint
18+
19+
import "strings"
20+
21+
// endpointTargetCleaner is essentially a function that cleans a target string for a given record.
22+
// It returns the cleaned target string, which is used to create an endpoint. Different record types have different cleaning rules.
23+
type endpointTargetCleaner interface {
24+
Clean(target string) string
25+
}
26+
27+
// defaultEndpointTargetCleaner is a function that cleans a target string for a given record, trimming trailing dots which are not allowed
28+
// for most record types.
29+
type defaultEndpointTargetCleaner struct{}
30+
31+
func (v *defaultEndpointTargetCleaner) Clean(target string) string {
32+
return strings.TrimSuffix(target, ".")
33+
}
34+
35+
// arbitraryTextEndpointTargetCleaner is a function that cleans a target string for a given record, preserving arbitrary text including trailing dots.
36+
// This is used for TXT and NAPTR records.
37+
type arbitraryTextEndpointTargetCleaner struct{}
38+
39+
func (v *arbitraryTextEndpointTargetCleaner) Clean(target string) string {
40+
return target
41+
}

endpoint/target_cleaner_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package endpoint
18+
19+
import (
20+
"testing"
21+
22+
"github.com/stretchr/testify/assert"
23+
)
24+
25+
func TestDefaultEndpointTargetCleaner(t *testing.T) {
26+
cleaner := &defaultEndpointTargetCleaner{}
27+
assert.Equal(t, "example.com", cleaner.Clean("example.com."))
28+
assert.Equal(t, "example.com", cleaner.Clean("example.com"))
29+
}
30+
31+
func TestArbitraryTextEndpointTargetCleaner(t *testing.T) {
32+
cleaner := &arbitraryTextEndpointTargetCleaner{}
33+
assert.Equal(t, "example.com.", cleaner.Clean("example.com."))
34+
assert.Equal(t, "example.com", cleaner.Clean("example.com"))
35+
}

source/crd.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,18 @@ func (cs *crdSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error
185185
if (ep.RecordType == endpoint.RecordTypeCNAME || ep.RecordType == endpoint.RecordTypeA || ep.RecordType == endpoint.RecordTypeAAAA) && len(ep.Targets) < 1 {
186186
log.Debugf("Endpoint %s with DNSName %s has an empty list of targets, allowing it to pass through for default-targets processing", dnsEndpoint.Name, ep.DNSName)
187187
}
188-
isNAPTR := ep.RecordType == endpoint.RecordTypeNAPTR
189-
isTXT := ep.RecordType == endpoint.RecordTypeTXT
188+
189+
var validator endpointTargetValidator
190+
switch ep.RecordType {
191+
case endpoint.RecordTypeTXT, endpoint.RecordTypeNAPTR:
192+
validator = &arbitraryTextEndpointTargetValidator{}
193+
default:
194+
validator = &defaultEndpointTargetValidator{}
195+
}
196+
190197
illegalTarget := false
191198
for _, target := range ep.Targets {
192-
hasDot := strings.HasSuffix(target, ".")
193-
// Skip dot validation for TXT records as they can contain arbitrary text
194-
if !isTXT && ((isNAPTR && !hasDot) || (!isNAPTR && hasDot)) {
199+
if validator.IsInvalid(target) {
195200
illegalTarget = true
196201
break
197202
}

source/endpoints.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package source
1515

1616
import (
1717
"fmt"
18+
"strings"
1819

1920
"k8s.io/apimachinery/pkg/labels"
2021
coreinformers "k8s.io/client-go/informers/core/v1"
@@ -110,3 +111,25 @@ func EndpointTargetsFromServices(svcInformer coreinformers.ServiceInformer, name
110111
}
111112
return endpoint.NewTargets(targets...), nil
112113
}
114+
115+
// endpointTargetValidator is a function that validates a target string for a given record type
116+
// It returns true if the target is _invalid_, and false if it is valid.
117+
type endpointTargetValidator interface {
118+
IsInvalid(target string) bool
119+
}
120+
121+
// defaultEndpointTargetValidator is a function that validates a target string for a given record type, trimming trailing dots which are not allowed
122+
// for most record types.
123+
type defaultEndpointTargetValidator struct{}
124+
125+
func (v *defaultEndpointTargetValidator) IsInvalid(target string) bool {
126+
return strings.HasSuffix(target, ".")
127+
}
128+
129+
// arbitraryTextTargetValidator is a function that validates a target string for a given record type, allowing arbitrary text including trailing dots.
130+
// This is used for TXT and NAPTR records.
131+
type arbitraryTextEndpointTargetValidator struct{}
132+
133+
func (v *arbitraryTextEndpointTargetValidator) IsInvalid(target string) bool {
134+
return false
135+
}

source/endpoints_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,15 @@ func TestEndpointTargetsFromServicesWithFixtures(t *testing.T) {
344344
assert.NoError(t, err)
345345
assert.Equal(t, 2, targets.Len())
346346
}
347+
348+
func TestDefaultEndpointTargetValidator(t *testing.T) {
349+
validator := &defaultEndpointTargetValidator{}
350+
assert.True(t, validator.IsInvalid("example.com."))
351+
assert.False(t, validator.IsInvalid("example.com"))
352+
}
353+
354+
func TestArbitraryTextEndpointTargetValidator(t *testing.T) {
355+
validator := &arbitraryTextEndpointTargetValidator{}
356+
assert.False(t, validator.IsInvalid("example.com."))
357+
assert.False(t, validator.IsInvalid("example.com"))
358+
}

0 commit comments

Comments
 (0)