diff --git a/api/v1alpha1/dnsrecord_types.go b/api/v1alpha1/dnsrecord_types.go index f36a88d5..8dac4700 100644 --- a/api/v1alpha1/dnsrecord_types.go +++ b/api/v1alpha1/dnsrecord_types.go @@ -19,13 +19,19 @@ package v1alpha1 import ( "fmt" "strings" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" externaldns "sigs.k8s.io/external-dns/endpoint" + externaldnsprovider "sigs.k8s.io/external-dns/provider" + externaldnsregistry "sigs.k8s.io/external-dns/registry" ) // DNSRecordSpec defines the desired state of DNSRecord type DNSRecordSpec struct { + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="OwnerID is immutable" + // +optional + OwnerID *string `json:"ownerID,omitempty"` // +kubebuilder:validation:Required // +required ManagedZoneRef *ManagedZoneReference `json:"managedZone,omitempty"` @@ -99,6 +105,13 @@ const ( NSRecordType DNSRecordType = "NS" DefaultGeo string = "default" + + txtRegistryPrefix = "kuadrant-" + txtRegistrySuffix = "" + txtRegistryWildcardReplacement = "wildcard" + txtRegistryEncryptEnabled = false + txtRegistryEncryptAESKey = "" + txtRegistryCacheInterval = time.Duration(0) ) // GetRootDomain returns the shortest domain that is shared across all spec.Endpoints dns names. @@ -128,6 +141,15 @@ func (s *DNSRecord) GetRootDomain() (string, error) { return domain, nil } +func (s *DNSRecord) GetRegistry(provider externaldnsprovider.Provider, managedDNSRecordTypes, excludeDNSRecordTypes []string) (externaldnsregistry.Registry, error) { + if s.Spec.OwnerID != nil { + return externaldnsregistry.NewTXTRegistry(provider, txtRegistryPrefix, txtRegistrySuffix, *s.Spec.OwnerID, txtRegistryCacheInterval, + txtRegistryWildcardReplacement, managedDNSRecordTypes, excludeDNSRecordTypes, txtRegistryEncryptEnabled, []byte(txtRegistryEncryptAESKey)) + } else { + return externaldnsregistry.NewNoopRegistry(provider) + } +} + func init() { SchemeBuilder.Register(&DNSRecord{}, &DNSRecordList{}) } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 298cd8e3..2552dac7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -89,6 +89,11 @@ func (in *DNSRecordList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSRecordSpec) DeepCopyInto(out *DNSRecordSpec) { *out = *in + if in.OwnerID != nil { + in, out := &in.OwnerID, &out.OwnerID + *out = new(string) + **out = **in + } if in.ManagedZoneRef != nil { in, out := &in.ManagedZoneRef, &out.ManagedZoneRef *out = new(ManagedZoneReference) diff --git a/config/crd/bases/kuadrant.io_dnsrecords.yaml b/config/crd/bases/kuadrant.io_dnsrecords.yaml index ac503169..0925404f 100644 --- a/config/crd/bases/kuadrant.io_dnsrecords.yaml +++ b/config/crd/bases/kuadrant.io_dnsrecords.yaml @@ -94,6 +94,11 @@ spec: required: - name type: object + ownerID: + type: string + x-kubernetes-validations: + - message: OwnerID is immutable + rule: self == oldSelf type: object status: description: DNSRecordStatus defines the observed state of DNSRecord diff --git a/internal/controller/dnsrecord_controller.go b/internal/controller/dnsrecord_controller.go index 3a6fe412..3d90e65e 100644 --- a/internal/controller/dnsrecord_controller.go +++ b/internal/controller/dnsrecord_controller.go @@ -19,8 +19,6 @@ package controller import ( "context" "fmt" - "strings" - "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -34,7 +32,7 @@ import ( externaldnsendpoint "sigs.k8s.io/external-dns/endpoint" externaldnsplan "sigs.k8s.io/external-dns/plan" externaldnsprovider "sigs.k8s.io/external-dns/provider" - externaldnsregistry "sigs.k8s.io/external-dns/registry" + "strings" "github.com/kuadrant/dns-operator/api/v1alpha1" "github.com/kuadrant/dns-operator/internal/common/conditions" @@ -80,6 +78,9 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( logger.Info("Removing Finalizer", "name", DNSRecordFinalizer) controllerutil.RemoveFinalizer(dnsRecord, DNSRecordFinalizer) if err = r.Update(ctx, dnsRecord); client.IgnoreNotFound(err) != nil { + if apierrors.IsConflict(err) { + return ctrl.Result{Requeue: true}, nil + } return ctrl.Result{}, err } return ctrl.Result{}, nil @@ -241,7 +242,10 @@ func (r *DNSRecordReconciler) applyChanges(ctx context.Context, dnsRecord *v1alp return err } - registry, err := externaldnsregistry.NewNoopRegistry(dnsProvider) + managedDNSRecordTypes := []string{externaldnsendpoint.RecordTypeA, externaldnsendpoint.RecordTypeAAAA, externaldnsendpoint.RecordTypeCNAME} + excludeDNSRecordTypes := []string{} + + registry, err := dnsRecord.GetRegistry(dnsProvider, managedDNSRecordTypes, excludeDNSRecordTypes) if err != nil { return err } @@ -252,9 +256,6 @@ func (r *DNSRecordReconciler) applyChanges(ctx context.Context, dnsRecord *v1alp return fmt.Errorf("unknown policy: %s", policyID) } - managedDNSRecordTypes := []string{externaldnsendpoint.RecordTypeA, externaldnsendpoint.RecordTypeAAAA, externaldnsendpoint.RecordTypeCNAME} - excludeDNSRecordTypes := []string{} - //If we are deleting set the expected endpoints to an empty array if isDelete { dnsRecord.Spec.Endpoints = []*externaldnsendpoint.Endpoint{} diff --git a/test/e2e/single_cluster_record_test.go b/test/e2e/single_cluster_record_test.go index 828c4680..2c642302 100644 --- a/test/e2e/single_cluster_record_test.go +++ b/test/e2e/single_cluster_record_test.go @@ -113,7 +113,7 @@ var _ = Describe("Single Cluster Record Test", func() { dnsRecord = &v1alpha1.DNSRecord{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-record", + Name: testID, Namespace: testNamespace, }, Spec: v1alpha1.DNSRecordSpec{