Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Health Check in BackendTrafficPolicy #2244

Merged
merged 10 commits into from
Jan 6, 2024
5 changes: 5 additions & 0 deletions api/v1alpha1/backendtrafficpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ type BackendTrafficPolicySpec struct {
//
// +optional
TCPKeepalive *TCPKeepalive `json:"tcpKeepalive,omitempty"`

// HealthCheck allows gateway to perform active health checking on backends.
//
// +optional
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
}

// BackendTrafficPolicyStatus defines the state of BackendTrafficPolicy
Expand Down
163 changes: 163 additions & 0 deletions api/v1alpha1/healthcheck_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package v1alpha1

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// HealthCheck defines the health check configuration.
type HealthCheck struct {
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
// Timeout defines the time to wait for a health check response.
//
// +kubebuilder:validation:Format=duration
// +kubebuilder:default="1s"
// +optional
Timeout *metav1.Duration `json:"timeout"`

// Interval defines the time between health checks.
//
// +kubebuilder:validation:Format=duration
// +kubebuilder:default="3s"
// +optional
Interval *metav1.Duration `json:"interval"`

// UnhealthyThreshold defines the number of unhealthy health checks required before a backend host is marked unhealthy.
//
// +kubebuilder:validation:Minimum=1
// +kubebuilder:default=3
// +optional
UnhealthyThreshold *uint32 `json:"unhealthyThreshold"`

// HealthyThreshold defines the number of healthy health checks required before a backend host is marked healthy.
//
// +kubebuilder:validation:Minimum=1
// +kubebuilder:default=1
// +optional
HealthyThreshold *uint32 `json:"healthyThreshold"`

// HealthChecker defines the concrete health checker to do health checking.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a better name here, it currently looks like

healthCheck:
  healthChecker:
  .....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about checker ?

healthCheck:
  checker:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on endpoint ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel a little bit confused. Any thoughts from others?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PTAL #1821 the healthChecking part as a reference

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about removing healthChecking and copying the fields directly into top level struct ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this ?

  healthChecking: # optional
      connectionTimeout: duration # optional
      healthyCheckInterval: duration # optional, default=5s
      unhealthyCheckInterval: duration, # optional, default=10s
      unhealthyThreshold: int # optional, default=3
      healthyThreshold: int # optional, default=1
      type: Enum (grpc/http)
      grpc: # required when type=grpc
        upstreamName: string # required
        authority: string # optional
      http: # required when type=http
        expectedStatuses: # required, minItems=1
        - min: int # min=100, max=599
           max: int # min=100, max=599
        path: string # optional
        hostname: string # optional

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup looking good !

  • prefer "healthCheck" as the top level noun
  • lets only support tcp and http for now, and add support for grpc later

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline heathChecker to heathCheck and remove grpc checker.

done

HealthChecker HealthChecker `json:"healthChecker"`
}

// HealthCheckerType is the type of health checker.
// +kubebuilder:validation:Enum=HTTP;GRPC;TCP
type HealthCheckerType string

const (
// HealthCheckerTypeHTTP defines the HTTP type of health checking.
HealthCheckerTypeHTTP HealthCheckerType = "HTTP"
// HealthCheckerTypeGRPC defines the GRPC type of health checking.
HealthCheckerTypeGRPC HealthCheckerType = "GRPC"
// HealthCheckerTypeTCP defines the TCP type of health checking.
HealthCheckerTypeTCP HealthCheckerType = "TCP"
)

// HealthChecker defines the configuration of concrete health checker.
// EG supports various types of health checking including HTTP, GRPC, TCP.
// +union
//
// +kubebuilder:validation:XValidation:rule="self.type == 'HTTP' ? has(self.http) : !has(self.http)",message="If Health Checker type is HTTP, http field needs to be set."
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
// +kubebuilder:validation:XValidation:rule="self.type == 'GRPC' ? has(self.grpc) : !has(self.grpc)",message="If Health Checker type is GRPC, grpc field needs to be set."
// +kubebuilder:validation:XValidation:rule="self.type == 'TCP' ? has(self.tcp) : !has(self.tcp)",message="If Health Checker type is TCP, tcp field needs to be set."
type HealthChecker struct {
// Type defines the type of health checker.
// +kubebuilder:validation:Enum=HTTP;GRPC;TCP
// +unionDiscriminator
Type HealthCheckerType `json:"type" yaml:"type"`
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
// HTTP defines the configuration of http health checker.
// It's required while the health checker type is HTTP.
// +optional
HTTP *HTTPHealthChecker `json:"http,omitempty" yaml:"http,omitempty"`
// GRPC defines the configuration of grpc health checker.
// It's required while the health checker type is GRPC.
// +optional
GRPC *GRPCHealthChecker `json:"grpc,omitempty" yaml:"grpc,omitempty"`
// TCP defines the configuration of tcp health checker.
// It's required while the health checker type is TCP.
// +optional
TCP *TCPHealthChecker `json:"tcp,omitempty" yaml:"tcp,omitempty"`
}

// HTTPHealthChecker defines the settings of http health check.
type HTTPHealthChecker struct {
// Path defines the HTTP path that will be requested during health checking.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=1024
Path string `json:"path" yaml:"path"`
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
// Method defines the HTTP method used for health checking.
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
// Defaults to GET
// +optional
Method *string `json:"method,omitempty" yaml:"method,omitempty"`
// ExpectedStatuses defines a list of HTTP response statuses considered healthy.
// +optional
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
ExpectedStatuses []HTTPStatusRange `json:"expectedStatuses,omitempty" yaml:"expectedStatuses,omitempty"`
// ExpectedResponses defines a list of HTTP expected responses to match.
// +optional
ExpectedResponses []HealthCheckPayload `json:"expectedResponses,omitempty" yaml:"expectedResponses,omitempty"`
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
}

// GRPCHealthChecker defines the settings of grpc health check.
type GRPCHealthChecker struct {
// ServiceName defines the value of parameter service in the gRPC health check request.
// +optional
ServiceName *string `json:"serviceName,omitempty" yaml:"omitempty"`
// Authority defines the value of :authority header in the gRPC health check request.
// +optional
Authority *string `json:"authority,omitempty" yaml:"authority,omitempty"`
// +optional
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
}

// TCPHealthChecker defines the settings of tcp health check.
type TCPHealthChecker struct {
// Send defines the request payload.
// +optional
Send *HealthCheckPayload `json:"send,omitempty" yaml:"send,omitempty"`
// Receive defines the expected response payloads.
// +optional
Receive []HealthCheckPayload `json:"receive,omitempty" yaml:"receive,omitempty"`
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
}

// HTTPStatusRange defines the start and end of the http status range using half-open interval semantics [start, end). Only statuses in the range [100, 600) are allowed.
// +kubebuilder:validation:XValidation:rule="self.start <= self.end",message="start should be not greater than end"
type HTTPStatusRange struct {
lemonlinger marked this conversation as resolved.
Show resolved Hide resolved
// Start defines start of the range (inclusive)
// +kubebuilder:validation:Minimum=100
// +kubebuilder:validation:Maximum=600
// +kubebuilder:validation:ExclusiveMaximum=true
Start int64 `json:"start" yaml:"start"`
// End defines end of the range (exclusive)
// +kubebuilder:validation:Minimum=100
// +kubebuilder:validation:Maximum=600
End int64 `json:"end" yaml:"end"`
}

// HealthCheckPayloadType is the type of the payload.
// +kubebuilder:validation:Enum=Text;Binary
type HealthCheckPayloadType string

const (
// HealthCheckPayloadTypeText defines the Text type payload.
HealthCheckPayloadTypeText HealthCheckPayloadType = "Text"
// HealthCheckPayloadTypeBinary defines the Binary type payload.
HealthCheckPayloadTypeBinary HealthCheckPayloadType = "Binary"
)

// HealthCheckPayload defines the encoding of the payload bytes in the payload.
// +union
// +kubebuilder:validation:XValidation:rule="self.type == 'Text' ? has(self.text) : !has(self.text)",message="If payload type is Text, text field needs to be set."
// +kubebuilder:validation:XValidation:rule="self.type == 'Binary' ? has(self.binary) : !has(self.binary)",message="If payload type is Binary, binary field needs to be set."
type HealthCheckPayload struct {
// Type defines the type of the payload.
// +kubebuilder:validation:Enum=Text;Binary
// +unionDiscriminator
Type HealthCheckPayloadType `json:"type" yaml:"type"`
// Text payload in plain text.
// +optional
Text *string `json:"text,omitempty" yaml:"text,omitempty"`
// Binary payload base64 encoded.
// +optional
Binary []byte `json:"binary,omitempty" yaml:"binary,omitempty"`
}
Loading