Skip to content

Commit 9fece4b

Browse files
committed
Don't publish duplicate DNS records
Before attempting to publish a domain to a zone, check if that domain is already being published to the same zone.
1 parent 86f19bd commit 9fece4b

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

pkg/operator/controller/dns/controller.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ const (
6262
kubeCloudConfigName = "kube-cloud-config"
6363
// cloudCABundleKey is the key in the kube cloud config ConfigMap where the custom CA bundle is located
6464
cloudCABundleKey = "ca-bundle.pem"
65+
// dnsRecordIndexFieldName is the key for the DNSRecord index, used to identify conflicting domain names.
66+
dnsRecordIndexFieldName = "Spec.DNSName"
6567
)
6668

6769
var log = logf.Logger.WithName(controllerName)
@@ -102,6 +104,12 @@ func New(mgr manager.Manager, config Config) (runtimecontroller.Controller, erro
102104
})); err != nil {
103105
return nil, err
104106
}
107+
if err := operatorCache.IndexField(context.Background(), &iov1.DNSRecord{}, dnsRecordIndexFieldName, func(o client.Object) []string {
108+
dnsRecord := o.(*iov1.DNSRecord)
109+
return []string{dnsRecord.Spec.DNSName}
110+
}); err != nil {
111+
return nil, err
112+
}
105113
return c, nil
106114
}
107115

@@ -341,8 +349,9 @@ func (r *reconciler) publishRecordToZones(zones []configv1.DNSZone, record *iov1
341349

342350
var err error
343351
var condition iov1.DNSZoneCondition
352+
var isDomainPublished bool
344353
if dnsPolicy == iov1.UnmanagedDNS {
345-
log.Info("DNS record not published", "record", record.Spec)
354+
log.Info("DNS record not published: DNS management policy is unmanaged", "record", record.Spec)
346355
condition = iov1.DNSZoneCondition{
347356
Message: "DNS record is currently not being managed by the operator",
348357
Reason: "UnmanagedDNS",
@@ -352,6 +361,24 @@ func (r *reconciler) publishRecordToZones(zones []configv1.DNSZone, record *iov1
352361
}
353362
} else if isRecordPublished {
354363
condition, err = r.replacePublishedRecord(zones[i], record)
364+
} else if isDomainPublished, err = domainIsAlreadyPublishedInZone(context.Background(), r.cache, record, &zones[i]); err != nil {
365+
log.Error(err, "failed to validate DNS record", "record", record.Spec)
366+
condition = iov1.DNSZoneCondition{
367+
Message: "Pre-publish validation failed",
368+
Reason: "InternalError",
369+
Status: string(operatorv1.ConditionUnknown),
370+
Type: iov1.DNSRecordPublishedConditionType,
371+
LastTransitionTime: metav1.Now(),
372+
}
373+
} else if isDomainPublished {
374+
log.Info("DNS record not published: domain name already used by another DNS record", "record", record.Spec)
375+
condition = iov1.DNSZoneCondition{
376+
Message: "Domain name is already in use",
377+
Reason: "DomainAlreadyInUse",
378+
Status: string(operatorv1.ConditionUnknown),
379+
Type: iov1.DNSRecordPublishedConditionType,
380+
LastTransitionTime: metav1.Now(),
381+
}
355382
} else {
356383
condition, err = r.publishRecord(zones[i], record)
357384
}
@@ -846,3 +873,32 @@ func getIbmDNSProvider(dnsConfig *configv1.DNS, creds *corev1.Secret, instanceCR
846873
return provider, nil
847874
}
848875
}
876+
877+
// domainIsAlreadyPublishedInZone returns true if the domain name in the provided DNSRecord is already published by
878+
// another existing dnsRecord.
879+
func domainIsAlreadyPublishedInZone(ctx context.Context, cache cache.Cache, record *iov1.DNSRecord, zone *configv1.DNSZone) (bool, error) {
880+
records := iov1.DNSRecordList{}
881+
if err := cache.List(ctx, &records, client.MatchingFields{dnsRecordIndexFieldName: record.Spec.DNSName}); err != nil {
882+
return false, err
883+
}
884+
885+
if len(records.Items) == 0 {
886+
return false, nil
887+
}
888+
889+
for _, existingRecord := range records.Items {
890+
// we only care if the domain name is published by a different record, so ignore the matching record if it
891+
// already exists.
892+
// TODO: There's got to be a better way to match the same object
893+
if (record.Name == existingRecord.Name) && (record.Namespace == existingRecord.Namespace) {
894+
continue
895+
}
896+
if record.Spec.DNSName != existingRecord.Spec.DNSName {
897+
continue
898+
}
899+
if recordIsAlreadyPublishedToZone(record, zone) {
900+
return true, nil
901+
}
902+
}
903+
return false, nil
904+
}

0 commit comments

Comments
 (0)