diff --git a/api/v1beta1/dnsrecord_types.go b/api/v1beta1/dnsrecord_types.go index f523bc1a..bf9d5394 100644 --- a/api/v1beta1/dnsrecord_types.go +++ b/api/v1beta1/dnsrecord_types.go @@ -37,8 +37,7 @@ type DNSRecordSpec struct { // Reference to an IP object // +optional IPRef DNSRecordSpecIPRef `json:"ipRef,omitempty"` - // DNS record type (A, AAAA, CNAME) - // +kubebuilder:validation:Enum=A;AAAA;CNAME + // DNS record type // +kubebuilder:default=A // +optional Type string `json:"type,omitempty"` @@ -52,6 +51,14 @@ type DNSRecordSpec struct { // +kubebuilder:default=1 // +optional TTL int `json:"ttl,omitempty"` + // Data holds arbitrary key-value pairs used for SRV and LOC records + // +optional + Data map[string]string `json:"data,omitempty"` + // Required for MX, SRV and URI records; unused by other record types. Records with lower priorities are preferred. + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=65535 + // +optional + Priority *uint16 `json:"priority,omitempty"` // Interval to check DNSRecord // +kubebuilder:default="5m" // +optional diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 78cfaef6..49341e81 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -233,6 +233,18 @@ func (in *DNSRecordSpec) DeepCopyInto(out *DNSRecordSpec) { *out = new(bool) **out = **in } + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(uint16) + **out = **in + } out.Interval = in.Interval } diff --git a/config/crd/bases/cf.containeroo.ch_dnsrecords.yaml b/config/crd/bases/cf.containeroo.ch_dnsrecords.yaml index aa5ca32d..0fb1cd77 100644 --- a/config/crd/bases/cf.containeroo.ch_dnsrecords.yaml +++ b/config/crd/bases/cf.containeroo.ch_dnsrecords.yaml @@ -57,6 +57,12 @@ spec: content: description: DNS record content (e.g. 127.0.0.1) type: string + data: + additionalProperties: + type: string + description: Data holds arbitrary key-value pairs used for SRV and + LOC records + type: object interval: default: 5m description: Interval to check DNSRecord @@ -72,6 +78,12 @@ spec: description: DNS record name (e.g. example.com) maxLength: 255 type: string + priority: + description: Required for MX, SRV and URI records; unused by other + record types. Records with lower priorities are preferred. + maximum: 65535 + minimum: 0 + type: integer proxied: default: true description: Whether the record is receiving the performance and security @@ -86,11 +98,7 @@ spec: type: integer type: default: A - description: DNS record type (A, AAAA, CNAME) - enum: - - A - - AAAA - - CNAME + description: DNS record type type: string required: - name diff --git a/controllers/dnsrecord_controller.go b/controllers/dnsrecord_controller.go index 51e819a6..98a4db2e 100644 --- a/controllers/dnsrecord_controller.go +++ b/controllers/dnsrecord_controller.go @@ -153,15 +153,6 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } } - if instance.Spec.Content == "" && instance.Spec.IPRef.Name == "" { - err := r.markFailed(instance, ctx, "No content or IP reference provided") - if err != nil { - log.Error(err, "Failed to update DNSRecord status") - return ctrl.Result{}, err - } - return ctrl.Result{}, nil - } - if (instance.Spec.Type == "A" || instance.Spec.Type == "AAAA") && instance.Spec.IPRef.Name != "" { ip := &cfv1beta1.IP{} err := r.Get(ctx, client.ObjectKey{Name: instance.Spec.IPRef.Name}, ip) @@ -192,11 +183,13 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if existingRecord.ID == "" { resp, err := r.Cf.CreateDNSRecord(ctx, cloudflare.ZoneIdentifier(dnsRecordZoneId), cloudflare.CreateDNSRecordParams{ - Name: instance.Spec.Name, - Type: instance.Spec.Type, - Content: instance.Spec.Content, - TTL: instance.Spec.TTL, - Proxied: instance.Spec.Proxied, + Name: instance.Spec.Name, + Type: instance.Spec.Type, + Content: instance.Spec.Content, + TTL: instance.Spec.TTL, + Proxied: instance.Spec.Proxied, + Priority: instance.Spec.Priority, + Data: instance.Spec.Data, }) if err != nil { err := r.markFailed(instance, ctx, err.Error()) @@ -225,14 +218,18 @@ func (r *DNSRecordReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( existingRecord.Type != instance.Spec.Type || existingRecord.Content != instance.Spec.Content || existingRecord.TTL != instance.Spec.TTL || - *existingRecord.Proxied != *instance.Spec.Proxied { + *existingRecord.Proxied != *instance.Spec.Proxied || + !comparePriority(existingRecord.Priority, instance.Spec.Priority) || + !compareData(existingRecord.Data, instance.Spec.Data) { err := r.Cf.UpdateDNSRecord(ctx, cloudflare.ZoneIdentifier(dnsRecordZoneId), cloudflare.UpdateDNSRecordParams{ - ID: existingRecord.ID, - Name: instance.Spec.Name, - Type: instance.Spec.Type, - Content: instance.Spec.Content, - TTL: instance.Spec.TTL, - Proxied: instance.Spec.Proxied, + ID: existingRecord.ID, + Name: instance.Spec.Name, + Type: instance.Spec.Type, + Content: instance.Spec.Content, + TTL: instance.Spec.TTL, + Proxied: instance.Spec.Proxied, + Priority: instance.Spec.Priority, + Data: instance.Spec.Data, }) if err != nil { err := r.markFailed(instance, ctx, err.Error()) @@ -307,3 +304,41 @@ func (r *DNSRecordReconciler) markFailed(instance *cfv1beta1.DNSRecord, ctx cont } return nil } + +// comparePriority compares the priority nil safe +func comparePriority(a, b *uint16) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + return *a == *b +} + +// compareData compares the data nil safe +func compareData(a interface{}, b map[string]string) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + am, ok := a.(map[string]interface{}) + if !ok { + return false + } + if len(am) != len(b) { + return false + } + for k, v := range am { + vv, ok := v.(string) + if !ok { + return false + } + if vv != b[k] { + return false + } + } + return true +} diff --git a/controllers/zone_controller.go b/controllers/zone_controller.go index ec6d192b..793668d4 100644 --- a/controllers/zone_controller.go +++ b/controllers/zone_controller.go @@ -146,7 +146,7 @@ func (r *ZoneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. if !strings.HasSuffix(cfDnsRecord.Name, instance.Spec.Name) { continue } - if cfDnsRecord.Type != "A" && cfDnsRecord.Type != "AAAA" && cfDnsRecord.Type != "CNAME" { + if cfDnsRecord.Type == "TXT" && strings.HasPrefix(cfDnsRecord.Content, "_acme-challenge") { continue }