Skip to content

Commit edc5d84

Browse files
committed
fix: provider/FindZone: transform zone name to unicode as well
Signed-off-by: Romain Beuque <[email protected]>
1 parent 0c39b6e commit edc5d84

File tree

4 files changed

+68
-8
lines changed

4 files changed

+68
-8
lines changed

provider/ovh/ovh.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"golang.org/x/sync/errgroup"
3434

3535
"sigs.k8s.io/external-dns/endpoint"
36+
"sigs.k8s.io/external-dns/internal/idna"
3637
"sigs.k8s.io/external-dns/pkg/apis/externaldns"
3738
"sigs.k8s.io/external-dns/plan"
3839
"sigs.k8s.io/external-dns/provider"
@@ -156,43 +157,55 @@ func (p *OVHProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error)
156157
return endpoints, nil
157158
}
158159

159-
func planChangesByZoneName(zones []string, changes *plan.Changes) map[string]*plan.Changes {
160+
func planChangesByZoneName(zones []string, changes *plan.Changes) (map[string]*plan.Changes, error) {
160161
zoneNameIDMapper := provider.ZoneIDName{}
161162
for _, zone := range zones {
162163
zoneNameIDMapper.Add(zone, zone)
163164
}
164165

165166
output := map[string]*plan.Changes{}
166167
for _, endpt := range changes.Delete {
167-
_, zoneName := zoneNameIDMapper.FindZone(endpt.DNSName)
168+
zoneName, _ := zoneNameIDMapper.FindZone(endpt.DNSName)
169+
if zoneName == "" {
170+
return nil, provider.NewSoftError(fmt.Errorf("record %q have not found matching DNS zone in OVH provider", endpt.DNSName))
171+
}
168172
if _, ok := output[zoneName]; !ok {
169173
output[zoneName] = &plan.Changes{}
170174
}
171175
output[zoneName].Delete = append(output[zoneName].Delete, endpt)
172176
}
173177
for _, endpt := range changes.Create {
174-
_, zoneName := zoneNameIDMapper.FindZone(endpt.DNSName)
178+
zoneName, _ := zoneNameIDMapper.FindZone(endpt.DNSName)
179+
if zoneName == "" {
180+
return nil, provider.NewSoftError(fmt.Errorf("record %q have not found matching DNS zone in OVH provider", endpt.DNSName))
181+
}
175182
if _, ok := output[zoneName]; !ok {
176183
output[zoneName] = &plan.Changes{}
177184
}
178185
output[zoneName].Create = append(output[zoneName].Create, endpt)
179186
}
180187
for _, endpt := range changes.UpdateOld {
181-
_, zoneName := zoneNameIDMapper.FindZone(endpt.DNSName)
188+
zoneName, _ := zoneNameIDMapper.FindZone(endpt.DNSName)
189+
if zoneName == "" {
190+
return nil, provider.NewSoftError(fmt.Errorf("record %q have not found matching DNS zone in OVH provider", endpt.DNSName))
191+
}
182192
if _, ok := output[zoneName]; !ok {
183193
output[zoneName] = &plan.Changes{}
184194
}
185195
output[zoneName].UpdateOld = append(output[zoneName].UpdateOld, endpt)
186196
}
187197
for _, endpt := range changes.UpdateNew {
188-
_, zoneName := zoneNameIDMapper.FindZone(endpt.DNSName)
198+
zoneName, _ := zoneNameIDMapper.FindZone(endpt.DNSName)
199+
if zoneName == "" {
200+
return nil, provider.NewSoftError(fmt.Errorf("record %q have not found matching DNS zone in OVH provider", endpt.DNSName))
201+
}
189202
if _, ok := output[zoneName]; !ok {
190203
output[zoneName] = &plan.Changes{}
191204
}
192205
output[zoneName].UpdateNew = append(output[zoneName].UpdateNew, endpt)
193206
}
194207

195-
return output
208+
return output, nil
196209
}
197210

198211
func (p *OVHProvider) computeSingleZoneChanges(_ context.Context, zoneName string, existingRecords []ovhRecord, changes *plan.Changes) ([]ovhChange, error) {
@@ -264,7 +277,10 @@ func (p *OVHProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e
264277
}
265278
}
266279

267-
changesByZoneName := planChangesByZoneName(zones, changes)
280+
changesByZoneName, err := planChangesByZoneName(zones, changes)
281+
if err != nil {
282+
return err
283+
}
268284
eg, ctx := errgroup.WithContext(ctx)
269285

270286
for zoneName, changes := range changesByZoneName {
@@ -553,6 +569,13 @@ func (p *OVHProvider) newOvhChangeCreateDelete(action int, endpoints []*endpoint
553569
}
554570

555571
func convertDNSNameIntoSubDomain(DNSName string, zoneName string) string { // nolint: gocritic // captLocal
572+
if name, err := idna.Profile.ToUnicode(DNSName); err == nil {
573+
DNSName = name
574+
}
575+
if name, err := idna.Profile.ToUnicode(zoneName); err == nil {
576+
zoneName = name
577+
}
578+
556579
if DNSName == zoneName {
557580
return ""
558581
}

provider/ovh/ovh_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,27 @@ func TestOvhApplyChanges(t *testing.T) {
585585
client.AssertExpectations(t)
586586
}
587587

588+
func TestOvhApplyChangesPunyCode(t *testing.T) {
589+
client := new(mockOvhClient)
590+
provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration)}
591+
changes := plan.Changes{
592+
Create: []*endpoint.Endpoint{
593+
{DNSName: "example.testécassé.fr", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}},
594+
},
595+
}
596+
597+
client.On("GetWithContext", "/domain/zone").Return([]string{"xn--testcass-e1ae.fr"}, nil).Once()
598+
client.On("GetWithContext", "/domain/zone/xn--testcass-e1ae.fr/record").Return([]uint64{}, nil).Once()
599+
client.On("PostWithContext", "/domain/zone/xn--testcass-e1ae.fr/record", ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "example", TTL: 10, Target: "203.0.113.42"}}).Return(nil, nil).Once()
600+
client.On("PostWithContext", "/domain/zone/xn--testcass-e1ae.fr/refresh", nil).Return(nil, nil).Once()
601+
602+
_, err := provider.Records(t.Context())
603+
td.CmpNoError(t, err)
604+
// Basic changes
605+
td.CmpNoError(t, provider.ApplyChanges(t.Context(), &changes))
606+
client.AssertExpectations(t)
607+
}
608+
588609
func TestOvhChange(t *testing.T) {
589610
assert := assert.New(t)
590611
client := new(mockOvhClient)

provider/zonefinder.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ import (
2727
type ZoneIDName map[string]string
2828

2929
func (z ZoneIDName) Add(zoneID, zoneName string) {
30-
z[zoneID] = zoneName
30+
if zone, err := idna.Profile.ToUnicode(zoneName); err == nil {
31+
z[zoneID] = zone
32+
} else {
33+
z[zoneID] = zoneName
34+
}
3135
}
3236

3337
// FindZone identifies the most suitable DNS zone for a given hostname.

provider/zonefinder_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ func TestZoneIDName(t *testing.T) {
3535
z.Add("1231231", "_foo._metadata.example.com")
3636
z.Add("456456", "_metadata.エイミー.みんな")
3737
z.Add("123412", "*.example.com")
38+
// adding a zone as punycode, see that it is injected as unicode/international format
39+
z.Add("234567", "xn--testcass-e1ae.fr")
3840

3941
assert.Equal(t, ZoneIDName{
4042
"123456": "qux.baz",
@@ -44,6 +46,7 @@ func TestZoneIDName(t *testing.T) {
4446
"1231231": "_foo._metadata.example.com",
4547
"456456": "_metadata.エイミー.みんな",
4648
"123412": "*.example.com",
49+
"234567": "testécassé.fr",
4750
}, z)
4851

4952
// simple entry in a domain
@@ -89,6 +92,15 @@ func TestZoneIDName(t *testing.T) {
8992
assert.Equal(t, "*.example.com", zoneName)
9093
assert.Equal(t, "123412", zoneID)
9194

95+
// looking for a zone that has been inserted as punycode
96+
zoneID, zoneName = z.FindZone("example.testécassé.fr")
97+
assert.Equal(t, "testécassé.fr", zoneName)
98+
assert.Equal(t, "234567", zoneID)
99+
100+
zoneID, zoneName = z.FindZone("example.xn--testcass-e1ae.fr")
101+
assert.Equal(t, "testécassé.fr", zoneName)
102+
assert.Equal(t, "234567", zoneID)
103+
92104
hook := testutils.LogsUnderTestWithLogLevel(log.WarnLevel, t)
93105
_, _ = z.FindZone("xn--not-a-valid-punycode")
94106

0 commit comments

Comments
 (0)