Skip to content

Commit 3602c47

Browse files
committed
Multiple A records support for the same FQDN
* Fixes #1313 * Logic is to have unique key for every of multiple `ep.Targets` and keep them around in `ep.Labels` for further consistency * Unit test is not very strict as testing functions are not ready for multiple Services with the same key but is imho good enough
1 parent 679f71a commit 3602c47

2 files changed

Lines changed: 85 additions & 8 deletions

File tree

provider/coredns.go

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,28 @@ func NewCoreDNSProvider(domainFilter endpoint.DomainFilter, prefix string, dryRu
258258
}, nil
259259
}
260260

261+
// Find takes a Endpoint slice and looks for an element in it. If found it will
262+
// return it's key, otherwise it will return -1 and a bool of false.
263+
func findEp(slice []*endpoint.Endpoint, dnsName string) (int, bool) {
264+
for i, item := range slice {
265+
if item.DNSName == dnsName {
266+
return i, true
267+
}
268+
}
269+
return -1, false
270+
}
271+
272+
// Find takes a EndpointLabels map and looks for an element in it. If found it will
273+
// return it's key, otherwise it will return -1 and a bool of false.
274+
func findLabelInTargets(targets []string, label string) (string, bool) {
275+
for _, target := range targets {
276+
if target == label {
277+
return target, true
278+
}
279+
}
280+
return "", false
281+
}
282+
261283
// Records returns all DNS records found in CoreDNS etcd backend. Depending on the record fields
262284
// it may be mapped to one or two records of type A, CNAME, TXT, A+TXT, CNAME+TXT
263285
func (p coreDNSProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) {
@@ -273,16 +295,27 @@ func (p coreDNSProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err
273295
if !p.domainFilter.Match(dnsName) {
274296
continue
275297
}
298+
log.Debugf("Getting service (%v) with service host (%s)", service, service.Host)
276299
prefix := strings.Join(domains[:service.TargetStrip], ".")
277300
if service.Host != "" {
278-
ep := endpoint.NewEndpointWithTTL(
279-
dnsName,
280-
guessRecordType(service.Host),
281-
endpoint.TTL(service.TTL),
282-
service.Host,
283-
)
301+
foundEpIndex, found := findEp(result, dnsName)
302+
var ep *endpoint.Endpoint
303+
if found {
304+
ep = result[foundEpIndex]
305+
ep.Targets = append(ep.Targets, service.Host)
306+
log.Debugf("Exteding ep (%s) with new service host (%s)", ep, service.Host)
307+
} else {
308+
ep = endpoint.NewEndpointWithTTL(
309+
dnsName,
310+
guessRecordType(service.Host),
311+
endpoint.TTL(service.TTL),
312+
service.Host,
313+
)
314+
log.Debugf("Creating new ep (%s) with new service host (%s)", ep, service.Host)
315+
}
284316
ep.Labels["originalText"] = service.Text
285317
ep.Labels[randomPrefixLabel] = prefix
318+
ep.Labels[service.Host] = prefix
286319
result = append(result, ep)
287320
}
288321
if service.Text != "" {
@@ -305,7 +338,8 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
305338
grouped[ep.DNSName] = append(grouped[ep.DNSName], ep)
306339
}
307340
for i, ep := range changes.UpdateNew {
308-
ep.Labels[randomPrefixLabel] = changes.UpdateOld[i].Labels[randomPrefixLabel]
341+
ep.Labels = changes.UpdateOld[i].Labels
342+
log.Debugf("Updating labels (%s) with old labels(%s)", ep.Labels, changes.UpdateOld[i].Labels)
309343
grouped[ep.DNSName] = append(grouped[ep.DNSName], ep)
310344
}
311345
for dnsName, group := range grouped {
@@ -320,9 +354,11 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
320354
}
321355

322356
for _, target := range ep.Targets {
323-
prefix := ep.Labels[randomPrefixLabel]
357+
prefix := ep.Labels[target]
358+
log.Debugf("Getting prefix(%s) from label(%s)", prefix, target)
324359
if prefix == "" {
325360
prefix = fmt.Sprintf("%08x", rand.Int31())
361+
log.Infof("Generating new prefix: (%s)", prefix)
326362
}
327363

328364
service := Service{
@@ -333,7 +369,29 @@ func (p coreDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
333369
TTL: uint32(ep.RecordTTL),
334370
}
335371
services = append(services, service)
372+
ep.Labels[target] = prefix
373+
log.Debugf("Putting prefix(%s) to label(%s)", prefix, target)
374+
log.Debugf("Ep labels structure now: (%v)", ep.Labels)
336375
}
376+
377+
// Clean outdated targets
378+
for label, labelPrefix := range ep.Labels {
379+
log.Debugf("Finding label (%s) in targets(%v)", label, ep.Targets)
380+
if _, ok := findLabelInTargets(ep.Targets, label); !ok {
381+
log.Debugf("Found non existing label(%s) in targets(%v)", label, ep.Targets)
382+
dnsName := ep.DNSName
383+
dnsName = labelPrefix + "." + dnsName
384+
key := p.etcdKeyFor(dnsName)
385+
log.Infof("Delete key %s", key)
386+
if !p.dryRun {
387+
err := p.client.DeleteService(key)
388+
if err != nil {
389+
return err
390+
}
391+
}
392+
}
393+
}
394+
337395
}
338396
index := 0
339397
for _, ep := range group {

provider/coredns_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,24 @@ func TestCoreDNSApplyChanges(t *testing.T) {
293293
"/skydns/local/domain2": {Host: "site.local"},
294294
}
295295
validateServices(client.services, expectedServices3, t, 3)
296+
297+
// Test for multiple A records for the same FQDN
298+
changes4 := &plan.Changes{
299+
Create: []*endpoint.Endpoint{
300+
endpoint.NewEndpoint("domain1.local", endpoint.RecordTypeA, "5.5.5.5"),
301+
endpoint.NewEndpoint("domain1.local", endpoint.RecordTypeA, "6.6.6.6"),
302+
endpoint.NewEndpoint("domain1.local", endpoint.RecordTypeA, "7.7.7.7"),
303+
},
304+
}
305+
coredns.ApplyChanges(context.Background(), changes4)
306+
307+
expectedServices4 := map[string]*Service{
308+
"/skydns/local/domain2": {Host: "site.local"},
309+
"/skydns/local/domain1/1": {Host: "5.5.5.5"},
310+
"/skydns/local/domain1/2": {Host: "6.6.6.6"},
311+
"/skydns/local/domain1": {Host: "7.7.7.7"},
312+
}
313+
validateServices(client.services, expectedServices4, t, 1)
296314
}
297315

298316
func applyServiceChanges(provider coreDNSProvider, changes *plan.Changes) {
@@ -311,6 +329,7 @@ func applyServiceChanges(provider coreDNSProvider, changes *plan.Changes) {
311329
}
312330

313331
func validateServices(services, expectedServices map[string]*Service, t *testing.T, step int) {
332+
t.Helper()
314333
if len(services) != len(expectedServices) {
315334
t.Errorf("wrong number of records on step %d: %d != %d", step, len(services), len(expectedServices))
316335
}

0 commit comments

Comments
 (0)