diff --git a/api/v1alpha1/dnsrecord_types.go b/api/v1alpha1/dnsrecord_types.go index f2460efb..2cdf2b5e 100644 --- a/api/v1alpha1/dnsrecord_types.go +++ b/api/v1alpha1/dnsrecord_types.go @@ -26,31 +26,47 @@ import ( "github.com/kuadrant/dns-operator/internal/common/hash" ) -type HealthProtocol string +type Protocol string -const HttpProtocol HealthProtocol = "HTTP" -const HttpsProtocol HealthProtocol = "HTTPS" +const HttpProtocol Protocol = "HTTP" +const HttpsProtocol Protocol = "HTTPS" // HealthCheckSpec configures health checks in the DNS provider. // By default this health check will be applied to each unique DNS A Record for // the listeners assigned to the target gateway type HealthCheckSpec struct { - // Endpoint is the path to append to the host to reach the expected health check. - // Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common - // +kubebuilder:validation:Pattern=`^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$` - Endpoint string `json:"endpoint,omitempty"` - // Port to connect to the host on. Must be either 80, 443 or 1024-49151 // +kubebuilder:validation:XValidation:rule="self in [80, 443] || (self >= 1024 && self <= 49151)",message="Only ports 80, 443, 1024-49151 are allowed" Port *int `json:"port,omitempty"` - + // Path is the path to append to the host to reach the expected health check. + // Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common + // +kubebuilder:validation:Pattern=`^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$` + Path string `json:"path,omitempty"` // Protocol to use when connecting to the host, valid values are "HTTP" or "HTTPS" // +kubebuilder:validation:XValidation:rule="self in ['HTTP','HTTPS']",message="Only HTTP or HTTPS protocols are allowed" - Protocol *HealthProtocol `json:"protocol,omitempty"` - + Protocol Protocol `json:"protocol,omitempty"` + // Interval defines how frequently this probe should execute + Interval metav1.Duration `json:"interval,omitempty"` + // AdditionalHeadersRef refers to a secret that contains extra headers to send in the probe request, this is primarily useful if an authentication + // token is required by the endpoint. + AdditionalHeadersRef *AdditionalHeadersRef `json:"additionalHeadersRef,omitempty"` // FailureThreshold is a limit of consecutive failures that must occur for a host to be considered unhealthy // +kubebuilder:validation:XValidation:rule="self > 0",message="Failure threshold must be greater than 0" FailureThreshold *int `json:"failureThreshold,omitempty"` + // AllowInsecureCertificate will instruct the health check probe to not fail on a self-signed or otherwise invalid SSL certificate + // this is primarily used in development or testing environments + AllowInsecureCertificate bool `json:"allowInsecureCertificate,omitempty"` +} + +type AdditionalHeadersRef struct { + Name string `json:"name"` +} + +type AdditionalHeaders []AdditionalHeader + +type AdditionalHeader struct { + Name string `json:"name"` + Value string `json:"value"` } type HealthCheckStatus struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index dc1075a3..6a574d4f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -26,6 +26,55 @@ import ( "sigs.k8s.io/external-dns/endpoint" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdditionalHeader) DeepCopyInto(out *AdditionalHeader) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalHeader. +func (in *AdditionalHeader) DeepCopy() *AdditionalHeader { + if in == nil { + return nil + } + out := new(AdditionalHeader) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AdditionalHeaders) DeepCopyInto(out *AdditionalHeaders) { + { + in := &in + *out = make(AdditionalHeaders, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalHeaders. +func (in AdditionalHeaders) DeepCopy() AdditionalHeaders { + if in == nil { + return nil + } + out := new(AdditionalHeaders) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdditionalHeadersRef) DeepCopyInto(out *AdditionalHeadersRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalHeadersRef. +func (in *AdditionalHeadersRef) DeepCopy() *AdditionalHeadersRef { + if in == nil { + return nil + } + out := new(AdditionalHeadersRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSRecord) DeepCopyInto(out *DNSRecord) { *out = *in @@ -169,9 +218,10 @@ func (in *HealthCheckSpec) DeepCopyInto(out *HealthCheckSpec) { *out = new(int) **out = **in } - if in.Protocol != nil { - in, out := &in.Protocol, &out.Protocol - *out = new(HealthProtocol) + out.Interval = in.Interval + if in.AdditionalHeadersRef != nil { + in, out := &in.AdditionalHeadersRef, &out.AdditionalHeadersRef + *out = new(AdditionalHeadersRef) **out = **in } if in.FailureThreshold != nil { diff --git a/bundle/manifests/dns-operator.clusterserviceversion.yaml b/bundle/manifests/dns-operator.clusterserviceversion.yaml index 1636c079..404255fc 100644 --- a/bundle/manifests/dns-operator.clusterserviceversion.yaml +++ b/bundle/manifests/dns-operator.clusterserviceversion.yaml @@ -38,7 +38,7 @@ metadata: capabilities: Basic Install categories: Integration & Delivery containerImage: quay.io/kuadrant/dns-operator:latest - createdAt: "2024-09-11T15:34:57Z" + createdAt: "2024-10-01T10:02:18Z" description: A Kubernetes Operator to manage the lifecycle of DNS resources operators.operatorframework.io/builder: operator-sdk-v1.33.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 diff --git a/bundle/manifests/kuadrant.io_dnsrecords.yaml b/bundle/manifests/kuadrant.io_dnsrecords.yaml index ade810bb..e1c7ab96 100644 --- a/bundle/manifests/kuadrant.io_dnsrecords.yaml +++ b/bundle/manifests/kuadrant.io_dnsrecords.yaml @@ -98,12 +98,21 @@ spec: By default this health check will be applied to each unique DNS A Record for the listeners assigned to the target gateway properties: - endpoint: + additionalHeadersRef: description: |- - Endpoint is the path to append to the host to reach the expected health check. - Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common - pattern: ^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$ - type: string + AdditionalHeadersRef refers to a secret that contains extra headers to send in the probe request, this is primarily useful if an authentication + token is required by the endpoint. + properties: + name: + type: string + required: + - name + type: object + allowInsecureCertificate: + description: |- + AllowInsecureCertificate will instruct the health check probe to not fail on a self-signed or otherwise invalid SSL certificate + this is primarily used in development or testing environments + type: boolean failureThreshold: description: FailureThreshold is a limit of consecutive failures that must occur for a host to be considered unhealthy @@ -111,6 +120,16 @@ spec: x-kubernetes-validations: - message: Failure threshold must be greater than 0 rule: self > 0 + interval: + description: Interval defines how frequently this probe should + execute + type: string + path: + description: |- + Path is the path to append to the host to reach the expected health check. + Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common + pattern: ^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$ + type: string port: description: Port to connect to the host on. Must be either 80, 443 or 1024-49151 diff --git a/charts/dns-operator/templates/manifests.yaml b/charts/dns-operator/templates/manifests.yaml index a251f8cc..a5d720e8 100644 --- a/charts/dns-operator/templates/manifests.yaml +++ b/charts/dns-operator/templates/manifests.yaml @@ -110,12 +110,21 @@ spec: By default this health check will be applied to each unique DNS A Record for the listeners assigned to the target gateway properties: - endpoint: + additionalHeadersRef: description: |- - Endpoint is the path to append to the host to reach the expected health check. - Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common - pattern: ^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$ - type: string + AdditionalHeadersRef refers to a secret that contains extra headers to send in the probe request, this is primarily useful if an authentication + token is required by the endpoint. + properties: + name: + type: string + required: + - name + type: object + allowInsecureCertificate: + description: |- + AllowInsecureCertificate will instruct the health check probe to not fail on a self-signed or otherwise invalid SSL certificate + this is primarily used in development or testing environments + type: boolean failureThreshold: description: FailureThreshold is a limit of consecutive failures that must occur for a host to be considered unhealthy @@ -123,6 +132,16 @@ spec: x-kubernetes-validations: - message: Failure threshold must be greater than 0 rule: self > 0 + interval: + description: Interval defines how frequently this probe should + execute + type: string + path: + description: |- + Path is the path to append to the host to reach the expected health check. + Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common + pattern: ^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$ + type: string port: description: Port to connect to the host on. Must be either 80, 443 or 1024-49151 diff --git a/config/crd/bases/kuadrant.io_dnsrecords.yaml b/config/crd/bases/kuadrant.io_dnsrecords.yaml index 4d121900..26c131be 100644 --- a/config/crd/bases/kuadrant.io_dnsrecords.yaml +++ b/config/crd/bases/kuadrant.io_dnsrecords.yaml @@ -98,12 +98,21 @@ spec: By default this health check will be applied to each unique DNS A Record for the listeners assigned to the target gateway properties: - endpoint: + additionalHeadersRef: description: |- - Endpoint is the path to append to the host to reach the expected health check. - Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common - pattern: ^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$ - type: string + AdditionalHeadersRef refers to a secret that contains extra headers to send in the probe request, this is primarily useful if an authentication + token is required by the endpoint. + properties: + name: + type: string + required: + - name + type: object + allowInsecureCertificate: + description: |- + AllowInsecureCertificate will instruct the health check probe to not fail on a self-signed or otherwise invalid SSL certificate + this is primarily used in development or testing environments + type: boolean failureThreshold: description: FailureThreshold is a limit of consecutive failures that must occur for a host to be considered unhealthy @@ -111,6 +120,16 @@ spec: x-kubernetes-validations: - message: Failure threshold must be greater than 0 rule: self > 0 + interval: + description: Interval defines how frequently this probe should + execute + type: string + path: + description: |- + Path is the path to append to the host to reach the expected health check. + Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common + pattern: ^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$ + type: string port: description: Port to connect to the host on. Must be either 80, 443 or 1024-49151 diff --git a/internal/controller/dnsrecord_controller_test.go b/internal/controller/dnsrecord_controller_test.go index 5e7dc561..c40dba43 100644 --- a/internal/controller/dnsrecord_controller_test.go +++ b/internal/controller/dnsrecord_controller_test.go @@ -152,16 +152,16 @@ var _ = Describe("DNSRecordReconciler", func() { }, Endpoints: getTestEndpoints("bar.example.com", "127.0.0.1"), HealthCheck: &v1alpha1.HealthCheckSpec{ - Endpoint: "health", + Path: "health", Port: ptr.To(5), - Protocol: ptr.To(v1alpha1.HealthProtocol("cat")), + Protocol: v1alpha1.Protocol("cat"), FailureThreshold: ptr.To(-1), }, }, } err := k8sClient.Create(ctx, dnsRecord) Expect(err).To(MatchError(ContainSubstring("spec.rootHost: Invalid value"))) - Expect(err).To(MatchError(ContainSubstring("spec.healthCheck.endpoint: Invalid value"))) + Expect(err).To(MatchError(ContainSubstring("spec.healthCheck.path: Invalid value"))) Expect(err).To(MatchError(ContainSubstring("Only ports 80, 443, 1024-49151 are allowed"))) Expect(err).To(MatchError(ContainSubstring("Only HTTP or HTTPS protocols are allowed"))) Expect(err).To(MatchError(ContainSubstring("Failure threshold must be greater than 0"))) diff --git a/internal/controller/dnsrecord_healthchecks.go b/internal/controller/dnsrecord_healthchecks.go index 00cd01a1..418c6ba1 100644 --- a/internal/controller/dnsrecord_healthchecks.go +++ b/internal/controller/dnsrecord_healthchecks.go @@ -164,10 +164,10 @@ func getHealthChecksConfig(dnsRecord *v1alpha1.DNSRecord) *healthChecksConfig { failureThreshold := int64(*dnsRecord.Spec.HealthCheck.FailureThreshold) return &healthChecksConfig{ - Endpoint: dnsRecord.Spec.HealthCheck.Endpoint, + Endpoint: dnsRecord.Spec.HealthCheck.Path, Port: &port, FailureThreshold: &failureThreshold, - Protocol: (*provider.HealthCheckProtocol)(dnsRecord.Spec.HealthCheck.Protocol), + Protocol: (*provider.HealthCheckProtocol)(&dnsRecord.Spec.HealthCheck.Protocol), } }