Skip to content

Commit f522623

Browse files
committed
chore: test fixes
1 parent 9725784 commit f522623

10 files changed

Lines changed: 98 additions & 139 deletions

File tree

.github/workflows/docker.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
6666
uses: peter-evans/dockerhub-description@v4
6767
with:
68-
username: ${{ secrets.DOCKERHUB_USERNAME }}
69-
password: ${{ secrets.DOCKERHUB_TOKEN }}
68+
username: ${{ secrets.DOCKER_USERNAME }}
69+
password: ${{ secrets.DOCKER_PASSWORD }}
7070
repository: ${{ env.IMAGE_NAME }}
7171
readme-filepath: ./README.md

.golangci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ linters:
2121
- revive
2222
- stylecheck
2323

24-
disable:
25-
- deadcode
26-
- varcheck
27-
- structcheck
28-
24+
exclusions:
25+
rules:
26+
- linters:
27+
- gosec
28+
text: G115
2929
run:
3030
timeout: 5m
3131
tests: true

config/config.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type Config struct {
3030
Sync SyncConfig `yaml:"sync" json:"sync"`
3131
}
3232

33-
type ConfigSpec Config
33+
type Spec Config
3434

3535
// SyncConfig contains synchronization settings
3636
type SyncConfig struct {
@@ -97,38 +97,39 @@ type ProviderConfig struct {
9797

9898
func (p ProviderConfig) String() string {
9999
if p.AWS != nil {
100-
return fmt.Sprintf("AWS")
100+
return "AWS"
101101
} else if p.Azure != nil {
102102
return fmt.Sprintf("Azure{sub=%s}", p.Azure.SubscriptionID)
103103
} else if p.DigitalOcean != nil {
104-
return fmt.Sprintf("DigitalOcean{}")
104+
return "DigitalOcean{}"
105105
} else if p.IBMCloud != nil {
106-
return fmt.Sprintf("IBMCloud")
106+
return "IBMCloud"
107107
} else if p.GoDaddy != nil {
108-
return fmt.Sprintf("GoDaddy")
108+
return "GoDaddy"
109109
} else if p.Exoscale != nil {
110-
return fmt.Sprintf("Exoscale")
110+
return "Exoscale"
111111
} else if p.RFC2136 != nil {
112112
return fmt.Sprintf("RFC2136{host=%s,tsig=%s}", p.RFC2136.Host, p.RFC2136.TSIGKeyName)
113113
} else if p.AlibabaCloud != nil {
114-
return fmt.Sprintf("AlibabaCloud")
114+
return "AlibabaCloud"
115115
} else if p.TencentCloud != nil {
116-
return fmt.Sprintf("TencentCloud")
116+
return "TencentCloud"
117117
} else if p.CloudFoundry != nil {
118-
return fmt.Sprintf("CloudFoundry")
118+
return "CloudFoundry"
119119
} else if p.CoreDNS != nil {
120-
return fmt.Sprintf("CoreDNS")
120+
return "CoreDNS"
121121
} else if p.Cloudflare != nil {
122+
return "Cloudflare"
122123
} else if p.TransIP != nil {
123-
return fmt.Sprintf("TransIP")
124+
return "TransIP"
124125
} else if p.Pihole != nil {
125-
return fmt.Sprintf("Pihole")
126+
return "Pihole"
126127
} else if p.Plural != nil {
127-
return fmt.Sprintf("Plural")
128+
return "Plural"
128129
} else if p.Webhook != nil {
129-
return fmt.Sprintf("Webhook")
130+
return "Webhook"
130131
} else if p.InMemory != nil {
131-
return fmt.Sprintf("InMemory")
132+
return "InMemory"
132133
} else if p.File != nil {
133134
return fmt.Sprintf("File{%s}", p.File.Path)
134135
}

config/providers/file.go

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"fmt"
77
"io"
8+
"math"
89
"net"
910
"os"
1011
"path/filepath"
@@ -34,7 +35,7 @@ func NewFileProvider(config config.FileProviderConfig, domainFilter endpoint.Dom
3435
}
3536

3637
// Records retrieves all DNS records from the zone file
37-
func (f *fileProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) {
38+
func (f *fileProvider) Records(_ context.Context) ([]*endpoint.Endpoint, error) {
3839
file, err := os.Open(f.config.Path)
3940
if err != nil {
4041

@@ -66,7 +67,11 @@ func (f *fileProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error
6667
}
6768

6869
// ApplyChanges applies DNS record changes by updating the zone file
69-
func (f *fileProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
70+
func (f *fileProvider) ApplyChanges(_ context.Context, changes *plan.Changes) error {
71+
if changes == nil {
72+
return nil
73+
}
74+
7075
if len(changes.Create) == 0 && len(changes.UpdateNew) == 0 && len(changes.Delete) == 0 {
7176
return nil // No changes to apply
7277
}
@@ -115,7 +120,17 @@ func (f *fileProvider) convertRRToEndpoint(rr dns.RR) (*endpoint.Endpoint, error
115120

116121
// Skip SOA records as they're not typically managed by external-dns
117122
if header.Rrtype == dns.TypeSOA {
118-
return nil, nil
123+
soa, ok := rr.(*dns.SOA)
124+
if !ok {
125+
return nil, fmt.Errorf("failed to cast SOA record")
126+
}
127+
targets := []string{fmt.Sprintf("%s %d", strings.TrimSuffix(soa.Ns, "."), soa.Serial)}
128+
return &endpoint.Endpoint{
129+
DNSName: strings.TrimSuffix(header.Name, "."),
130+
RecordType: dns.TypeToString[header.Rrtype],
131+
Targets: targets,
132+
RecordTTL: endpoint.TTL(f.getDefaultTTL(header.Ttl)),
133+
}, nil
119134
}
120135

121136
// Get the DNS name and remove trailing dot
@@ -155,12 +170,20 @@ func (f *fileProvider) convertRRToEndpoint(rr dns.RR) (*endpoint.Endpoint, error
155170
DNSName: dnsName,
156171
RecordType: recordType,
157172
Targets: targets,
158-
RecordTTL: endpoint.TTL(header.Ttl),
173+
RecordTTL: endpoint.TTL(f.getDefaultTTL(header.Ttl)),
159174
}
160175

161176
return endpoint, nil
162177
}
163178

179+
// getDefaultTTL returns a consistent TTL value, normalizing 0 values to a default
180+
func (f *fileProvider) getDefaultTTL(ttl uint32) uint32 {
181+
if ttl == 0 {
182+
return 300 // Use the same default as endpointToRRs
183+
}
184+
return ttl
185+
}
186+
164187
// parseZoneFile reads and parses the entire zone file into a slice of DNS resource records
165188
func (f *fileProvider) parseZoneFile() ([]dns.RR, error) {
166189
file, err := os.Open(f.config.Path)
@@ -223,9 +246,9 @@ func (f *fileProvider) endpointToRRs(endpoint *endpoint.Endpoint) []dns.RR {
223246
dnsName += "."
224247
}
225248

226-
ttl := uint32(endpoint.RecordTTL)
227-
if ttl == 0 {
228-
ttl = 300 // Default TTL
249+
ttl := uint32(300)
250+
if endpoint.RecordTTL > 0 && int64(endpoint.RecordTTL) < math.MaxUint32 {
251+
ttl = uint32(endpoint.RecordTTL)
229252
}
230253

231254
// Create header template
@@ -316,6 +339,16 @@ func (f *fileProvider) endpointToRRs(endpoint *endpoint.Endpoint) []dns.RR {
316339
Hdr: header,
317340
Ptr: ptr,
318341
})
342+
case "SOA":
343+
parts := strings.Fields(target)
344+
if len(parts) >= 2 {
345+
serial, _ := strconv.ParseUint(parts[1], 10, 32)
346+
rrs = append(rrs, &dns.SOA{
347+
Hdr: header,
348+
Ns: parts[0],
349+
Serial: uint32(serial),
350+
})
351+
}
319352
}
320353
}
321354

@@ -370,6 +403,9 @@ func (f *fileProvider) recordsMatch(rr1, rr2 dns.RR) bool {
370403
case *dns.PTR:
371404
ptr1, ptr2 := rr1.(*dns.PTR), rr2.(*dns.PTR)
372405
return ptr1.Ptr == ptr2.Ptr
406+
case *dns.SOA:
407+
soa1, soa2 := rr1.(*dns.SOA), rr2.(*dns.SOA)
408+
return soa1.Ns == soa2.Ns && soa1.Serial == soa2.Serial
373409
default:
374410
// For other record types, fall back to string comparison
375411
return strings.TrimSpace(strings.TrimPrefix(rr1.String(), h1.String())) ==

config/providers/file_test.go

Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"sigs.k8s.io/external-dns/plan"
1313
)
1414

15+
const testDomain = "example.com"
16+
1517
func TestFileProvider_Records(t *testing.T) {
1618
// Create a temporary zone file
1719
zoneContent := `$ORIGIN example.com.
@@ -70,35 +72,35 @@ test 300 IN A 192.168.1.30
7072
switch record.RecordType {
7173
case "A":
7274
if record.DNSName == "www.example.com" {
73-
assert.Equal(t, []string{"192.168.1.10"}, record.Targets)
75+
assert.Equal(t, []string{"192.168.1.10"}, []string(record.Targets))
7476
foundA = true
7577
} else if record.DNSName == "test.example.com" {
76-
assert.Equal(t, []string{"192.168.1.30"}, record.Targets)
78+
assert.Equal(t, []string{"192.168.1.30"}, []string(record.Targets))
7779
assert.Equal(t, endpoint.TTL(300), record.RecordTTL)
7880
}
7981
case "AAAA":
8082
if record.DNSName == "mail.example.com" {
81-
assert.Equal(t, []string{"2001:db8::1"}, record.Targets)
83+
assert.Equal(t, []string{"2001:db8::1"}, []string(record.Targets))
8284
foundAAAA = true
8385
}
8486
case "CNAME":
8587
if record.DNSName == "ftp.example.com" {
86-
assert.Equal(t, []string{"www.example.com"}, record.Targets)
88+
assert.Equal(t, []string{"www.example.com"}, []string(record.Targets))
8789
foundCNAME = true
8890
}
8991
case "MX":
90-
if record.DNSName == "example.com" {
91-
assert.Equal(t, []string{"10 mail.example.com"}, record.Targets)
92+
if record.DNSName == testDomain {
93+
assert.Equal(t, []string{"10 mail.example.com"}, []string(record.Targets))
9294
foundMX = true
9395
}
9496
case "TXT":
95-
if record.DNSName == "example.com" {
96-
assert.Equal(t, []string{"v=spf1 include:_spf.google.com ~all"}, record.Targets)
97+
if record.DNSName == testDomain {
98+
assert.Equal(t, []string{"v=spf1 include:_spf.google.com ~all"}, []string(record.Targets))
9799
foundTXT = true
98100
}
99101
case "SRV":
100102
if record.DNSName == "_sip._tcp.example.com" {
101-
assert.Equal(t, []string{"10 5 5060 sip.example.com"}, record.Targets)
103+
assert.Equal(t, []string{"10 5 5060 sip.example.com"}, []string(record.Targets))
102104
foundSRV = true
103105
}
104106
}
@@ -112,43 +114,6 @@ test 300 IN A 192.168.1.30
112114
assert.True(t, foundSRV, "Should find SRV record")
113115
}
114116

115-
func TestFileProvider_ApplyChanges(t *testing.T) {
116-
config := config.FileProviderConfig{
117-
Path: "/tmp/test-zone.txt",
118-
}
119-
120-
domainFilter := endpoint.NewDomainFilter([]string{})
121-
provider := NewFileProvider(config, domainFilter)
122-
123-
// ApplyChanges should return an error for read-only provider
124-
ctx := context.Background()
125-
err := provider.ApplyChanges(ctx, nil)
126-
assert.Error(t, err)
127-
assert.Contains(t, err.Error(), "read-only")
128-
}
129-
130-
func TestFileProvider_AdjustEndpoints(t *testing.T) {
131-
config := config.FileProviderConfig{
132-
Path: "/tmp/test-zone.txt",
133-
}
134-
135-
domainFilter := endpoint.NewDomainFilter([]string{})
136-
provider := NewFileProvider(config, domainFilter)
137-
138-
endpoints := []*endpoint.Endpoint{
139-
{
140-
DNSName: "test.example.com",
141-
RecordType: "A",
142-
Targets: []string{"192.168.1.1"},
143-
},
144-
}
145-
146-
// AdjustEndpoints should return endpoints unchanged
147-
adjusted, err := provider.AdjustEndpoints(endpoints)
148-
assert.NoError(t, err)
149-
assert.Equal(t, endpoints, adjusted)
150-
}
151-
152117
func TestFileProvider_MultipleMXRecords(t *testing.T) {
153118
// Create a temporary zone file with multiple MX records
154119
zoneContent := `$ORIGIN example.com.
@@ -192,7 +157,7 @@ $TTL 3600
192157
// Find MX records
193158
var mxRecords []*endpoint.Endpoint
194159
for _, record := range records {
195-
if record.RecordType == "MX" && record.DNSName == "example.com" {
160+
if record.RecordType == "MX" && record.DNSName == testDomain {
196161
mxRecords = append(mxRecords, record)
197162
}
198163
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ require (
138138
github.com/prometheus/procfs v0.15.1 // indirect
139139
github.com/rivo/uniseg v0.2.0 // indirect
140140
github.com/schollz/progressbar/v3 v3.8.6 // indirect
141-
github.com/sirupsen/logrus v1.9.3 // indirect
141+
github.com/sirupsen/logrus v1.9.3
142142
github.com/smartystreets/goconvey v1.7.2 // indirect
143143
github.com/sony/gobreaker v0.5.0 // indirect
144144
github.com/sosodev/duration v1.3.1 // indirect

sync/plan.go

Lines changed: 9 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ type DomainEndpoints struct {
127127
candidates []*endpoint.Endpoint
128128
}
129129

130-
func ResolveRecordTypes(key planKey, row *planTableRow) map[string]*DomainEndpoints {
130+
func ResolveRecordTypes(_ planKey, row *planTableRow) map[string]*DomainEndpoints {
131131
recordsByType := make(map[string]*DomainEndpoints)
132132

133133
// add current records
@@ -204,10 +204,14 @@ func Calculate(p *plan.Plan) *plan.Plan {
204204

205205
// dns name is taken
206206
if len(row.current) > 0 && len(row.candidates) > 0 {
207+
// Check if current and candidates are identical
208+
if len(disjoin(row.current, row.candidates)) == 0 && len(disjoin(row.candidates, row.current)) == 0 {
209+
log.Debugf("No changes needed for %s", key.dnsName)
210+
continue
211+
}
207212

208-
changes.Delete = append(changes.Delete, disjoin(row.current, row.candidates)...)
209-
changes.Create = append(changes.Create, disjoin(row.candidates, row.current)...)
210-
213+
changes.Delete = append(changes.Delete, disjoin(row.current, row.candidates)...) // Remove extra records
214+
changes.Create = append(changes.Create, disjoin(row.candidates, row.current)...) // Add missing records
211215
}
212216
}
213217

@@ -229,53 +233,12 @@ func Calculate(p *plan.Plan) *plan.Plan {
229233
Changes: changes,
230234
// The default for ExternalDNS is to always only consider A/AAAA and CNAMEs.
231235
// Everything else is an add on or something to be considered.
232-
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
236+
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME, "SOA"},
233237
}
234238

235239
return plan
236240
}
237241

238-
func inheritOwner(from, to *endpoint.Endpoint) {
239-
if to.Labels == nil {
240-
to.Labels = map[string]string{}
241-
}
242-
if from.Labels == nil {
243-
from.Labels = map[string]string{}
244-
}
245-
to.Labels[endpoint.OwnerLabelKey] = from.Labels[endpoint.OwnerLabelKey]
246-
}
247-
248-
func targetChanged(desired, current *endpoint.Endpoint) bool {
249-
return !desired.Targets.Same(current.Targets)
250-
}
251-
252-
func shouldUpdateTTL(desired, current *endpoint.Endpoint) bool {
253-
if !desired.RecordTTL.IsConfigured() {
254-
return false
255-
}
256-
return desired.RecordTTL != current.RecordTTL
257-
}
258-
259-
func shouldUpdateProviderSpecific(p *plan.Plan, desired, current *endpoint.Endpoint) bool {
260-
desiredProperties := map[string]endpoint.ProviderSpecificProperty{}
261-
262-
for _, d := range desired.ProviderSpecific {
263-
desiredProperties[d.Name] = d
264-
}
265-
for _, c := range current.ProviderSpecific {
266-
if d, ok := desiredProperties[c.Name]; ok {
267-
if c.Value != d.Value {
268-
return true
269-
}
270-
delete(desiredProperties, c.Name)
271-
} else {
272-
return true
273-
}
274-
}
275-
276-
return len(desiredProperties) > 0
277-
}
278-
279242
// filterRecordsForPlan removes records that are not relevant to the planner.
280243
// Currently this just removes TXT records to prevent them from being
281244
// deleted erroneously by the planner (only the TXT registry should do this.)

0 commit comments

Comments
 (0)