diff --git a/api/v1alpha1/dnsrecord_types.go b/api/v1alpha1/dnsrecord_types.go index 7ba3cb56..e07baf68 100644 --- a/api/v1alpha1/dnsrecord_types.go +++ b/api/v1alpha1/dnsrecord_types.go @@ -29,6 +29,25 @@ import ( "github.com/kuadrant/dns-operator/internal/external-dns/registry" ) +type HealthProtocol string + +const HttpProtocol HealthProtocol = "HTTP" +const HttpsProtocol HealthProtocol = "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 string `json:"endpoint,omitempty"` + Port *int `json:"port,omitempty"` + Protocol *HealthProtocol `json:"protocol,omitempty"` + FailureThreshold *int `json:"failureThreshold,omitempty"` +} + +type HealthCheckStatus struct { + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + // DNSRecordSpec defines the desired state of DNSRecord type DNSRecordSpec struct { // OwnerID is a unique string used to identify all endpoints created by this kuadrant @@ -45,6 +64,9 @@ type DNSRecordSpec struct { // +kubebuilder:validation:MinItems=1 // +optional Endpoints []*externaldns.Endpoint `json:"endpoints,omitempty"` + + // +optional + HealthCheck *HealthCheckSpec `json:"healthCheck,omitempty"` } // DNSRecordStatus defines the observed state of DNSRecord @@ -73,6 +95,8 @@ type DNSRecordStatus struct { // Note: This will not be required if/when we switch to using external-dns since when // running with a "sync" policy it will clean up unused records automatically. Endpoints []*externaldns.Endpoint `json:"endpoints,omitempty"` + + HealthCheck *HealthCheckStatus `json:"healthCheck,omitempty"` } //+kubebuilder:object:root=true diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a9642445..a61edb73 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -115,6 +115,11 @@ func (in *DNSRecordSpec) DeepCopyInto(out *DNSRecordSpec) { } } } + if in.HealthCheck != nil { + in, out := &in.HealthCheck, &out.HealthCheck + *out = new(HealthCheckSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSRecordSpec. @@ -148,6 +153,11 @@ func (in *DNSRecordStatus) DeepCopyInto(out *DNSRecordStatus) { } } } + if in.HealthCheck != nil { + in, out := &in.HealthCheck, &out.HealthCheck + *out = new(HealthCheckStatus) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSRecordStatus. @@ -160,6 +170,58 @@ func (in *DNSRecordStatus) DeepCopy() *DNSRecordStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HealthCheckSpec) DeepCopyInto(out *HealthCheckSpec) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int) + **out = **in + } + if in.Protocol != nil { + in, out := &in.Protocol, &out.Protocol + *out = new(HealthProtocol) + **out = **in + } + if in.FailureThreshold != nil { + in, out := &in.FailureThreshold, &out.FailureThreshold + *out = new(int) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheckSpec. +func (in *HealthCheckSpec) DeepCopy() *HealthCheckSpec { + if in == nil { + return nil + } + out := new(HealthCheckSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HealthCheckStatus) DeepCopyInto(out *HealthCheckStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheckStatus. +func (in *HealthCheckStatus) DeepCopy() *HealthCheckStatus { + if in == nil { + return nil + } + out := new(HealthCheckStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ManagedHost) DeepCopyInto(out *ManagedHost) { *out = *in diff --git a/bundle/manifests/dns-operator.clusterserviceversion.yaml b/bundle/manifests/dns-operator.clusterserviceversion.yaml index 8730f04f..6669ea02 100644 --- a/bundle/manifests/dns-operator.clusterserviceversion.yaml +++ b/bundle/manifests/dns-operator.clusterserviceversion.yaml @@ -56,7 +56,7 @@ metadata: capabilities: Basic Install categories: Integration & Delivery containerImage: quay.io/kuadrant/dns-operator:latest - createdAt: "2024-03-15T11:01:46Z" + createdAt: "2024-04-04T08:27:01Z" 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 52b3e807..8129038e 100644 --- a/bundle/manifests/kuadrant.io_dnsrecords.yaml +++ b/bundle/manifests/kuadrant.io_dnsrecords.yaml @@ -85,6 +85,20 @@ spec: type: object minItems: 1 type: array + healthCheck: + description: 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 + properties: + endpoint: + type: string + failureThreshold: + type: integer + port: + type: integer + protocol: + type: string + type: object managedZone: description: ManagedZoneReference holds a reference to a ManagedZone properties: @@ -233,6 +247,80 @@ spec: type: array type: object type: array + healthCheck: + properties: + conditions: + items: + description: "Condition contains details for one aspect of the + current state of this API Resource. --- This struct is intended + for direct use as an array at the field path .status.conditions. + \ For example, \n type FooStatus struct{ // Represents the + observations of a foo's current state. // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type + // +patchStrategy=merge // +listType=map // +listMapKey=type + Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be + when the underlying condition changed. If that is not + known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values + and meanings for this field, and whether the values are + considered a guaranteed API. The value should be a CamelCase + string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object observedGeneration: description: observedGeneration is the most recently observed generation of the DNSRecord. When the DNSRecord is updated, the controller diff --git a/config/crd/bases/kuadrant.io_dnsrecords.yaml b/config/crd/bases/kuadrant.io_dnsrecords.yaml index 84a0a083..762b0bec 100644 --- a/config/crd/bases/kuadrant.io_dnsrecords.yaml +++ b/config/crd/bases/kuadrant.io_dnsrecords.yaml @@ -85,6 +85,20 @@ spec: type: object minItems: 1 type: array + healthCheck: + description: 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 + properties: + endpoint: + type: string + failureThreshold: + type: integer + port: + type: integer + protocol: + type: string + type: object managedZone: description: ManagedZoneReference holds a reference to a ManagedZone properties: @@ -233,6 +247,80 @@ spec: type: array type: object type: array + healthCheck: + properties: + conditions: + items: + description: "Condition contains details for one aspect of the + current state of this API Resource. --- This struct is intended + for direct use as an array at the field path .status.conditions. + \ For example, \n type FooStatus struct{ // Represents the + observations of a foo's current state. // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type + // +patchStrategy=merge // +listType=map // +listMapKey=type + Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be + when the underlying condition changed. If that is not + known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values + and meanings for this field, and whether the values are + considered a guaranteed API. The value should be a CamelCase + string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object observedGeneration: description: observedGeneration is the most recently observed generation of the DNSRecord. When the DNSRecord is updated, the controller