// Copyright 2025 Envoy Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package envoy.config.core.v3;

import "envoy/config/core/v3/base.proto";
import "envoy/config/core/v3/event_service_config.proto";
import "envoy/config/core/v3/extension.proto";
import "envoy/config/core/v3/proxy_protocol.proto";
import "envoy/type/matcher/v3/string.proto";
import "envoy/type/v3/http.proto";
import "envoy/type/v3/range.proto";

import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/wrappers.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.config.core.v3";
option java_outer_classname = "HealthCheckProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/config/core/v3;corev3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Health check]
// * Health checking :ref:`architecture overview <arch_overview_health_checking>`.
// * If health checking is configured for a cluster, additional statistics are emitted. They are
//   documented :ref:`here <config_cluster_manager_cluster_stats>`.

// Endpoint health status.
enum HealthStatus {
  // The health status is not known. This is interpreted by Envoy as ``HEALTHY``.
  UNKNOWN = 0;

  // Healthy.
  HEALTHY = 1;

  // Unhealthy.
  UNHEALTHY = 2;

  // Connection draining in progress. E.g.,
  // `<https://aws.amazon.com/blogs/aws/elb-connection-draining-remove-instances-from-service-with-care/>`_
  // or
  // `<https://cloud.google.com/compute/docs/load-balancing/enabling-connection-draining>`_.
  // This is interpreted by Envoy as ``UNHEALTHY``.
  DRAINING = 3;

  // Health check timed out. This is part of HDS and is interpreted by Envoy as
  // ``UNHEALTHY``.
  TIMEOUT = 4;

  // Degraded.
  DEGRADED = 5;
}

message HealthStatusSet {
  // An order-independent set of health status.
  repeated HealthStatus statuses = 1
      [(validate.rules).repeated = {items {enum {defined_only: true}}}];
}

// [#next-free-field: 27]
message HealthCheck {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.HealthCheck";

  // Describes the encoding of the payload bytes in the payload.
  message Payload {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.Payload";

    oneof payload {
      option (validate.required) = true;

      // Hex encoded payload. E.g., "000000FF".
      string text = 1 [(validate.rules).string = {min_len: 1}];

      // Binary payload.
      bytes binary = 2;
    }
  }

  // [#next-free-field: 15]
  message HttpHealthCheck {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.HttpHealthCheck";

    reserved 5, 7;

    reserved "service_name", "use_http2";

    // The value of the host header in the HTTP health check request. If
    // left empty (default value), the name of the cluster this health check is associated
    // with will be used. The host header can be customized for a specific endpoint by setting the
    // :ref:`hostname <envoy_v3_api_field_config.endpoint.v3.Endpoint.HealthCheckConfig.hostname>` field.
    string host = 1 [(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE}];

    // Specifies the HTTP path that will be requested during health checking. For example
    // ``/healthcheck``.
    string path = 2 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_VALUE}];

    // HTTP specific payload to be sent as the request body during health checking.
    // If specified, the method should support a request body (POST, PUT, PATCH, etc.).
    Payload send = 3;

    // Specifies a list of HTTP expected responses to match in the first ``response_buffer_size`` bytes of the response body.
    // If it is set, both the expected response check and status code determine the health check.
    // When checking the response, “fuzzy” matching is performed such that each payload block must be found,
    // and in the order specified, but not necessarily contiguous.
    //
    // .. note::
    //
    //   It is recommended to set ``response_buffer_size`` based on the total Payload size for efficiency.
    //   The default buffer size is 1024 bytes when it is not set.
    repeated Payload receive = 4;

    // Specifies the size of response buffer in bytes that is used to Payload match.
    // The default value is 1024. Setting to 0 implies that the Payload will be matched against the entire response.
    google.protobuf.UInt64Value response_buffer_size = 14 [(validate.rules).uint64 = {gte: 0}];

    // Specifies a list of HTTP headers that should be added to each request that is sent to the
    // health checked cluster. For more information, including details on header value syntax, see
    // the documentation on :ref:`custom request headers
    // <config_http_conn_man_headers_custom_request_headers>`.
    repeated HeaderValueOption request_headers_to_add = 6
        [(validate.rules).repeated = {max_items: 1000}];

    // Specifies a list of HTTP headers that should be removed from each request that is sent to the
    // health checked cluster.
    repeated string request_headers_to_remove = 8 [(validate.rules).repeated = {
      items {string {well_known_regex: HTTP_HEADER_NAME strict: false}}
    }];

    // Specifies a list of HTTP response statuses considered healthy. If provided, replaces default
    // 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open
    // semantics of :ref:`Int64Range <envoy_v3_api_msg_type.v3.Int64Range>`. The start and end of each
    // range are required. Only statuses in the range [100, 600) are allowed.
    repeated type.v3.Int64Range expected_statuses = 9;

    // Specifies a list of HTTP response statuses considered retriable. If provided, responses in this range
    // will count towards the configured :ref:`unhealthy_threshold <envoy_v3_api_field_config.core.v3.HealthCheck.unhealthy_threshold>`,
    // but will not result in the host being considered immediately unhealthy. Ranges follow half-open semantics of
    // :ref:`Int64Range <envoy_v3_api_msg_type.v3.Int64Range>`. The start and end of each range are required.
    // Only statuses in the range [100, 600) are allowed. The :ref:`expected_statuses <envoy_v3_api_field_config.core.v3.HealthCheck.HttpHealthCheck.expected_statuses>`
    // field takes precedence for any range overlaps with this field i.e. if status code 200 is both retriable and expected, a 200 response will
    // be considered a successful health check. By default all responses not in
    // :ref:`expected_statuses <envoy_v3_api_field_config.core.v3.HealthCheck.HttpHealthCheck.expected_statuses>` will result in
    // the host being considered immediately unhealthy i.e. if status code 200 is expected and there are no configured retriable statuses, any
    // non-200 response will result in the host being marked unhealthy.
    repeated type.v3.Int64Range retriable_statuses = 12;

    // Use specified application protocol for health checks.
    type.v3.CodecClientType codec_client_type = 10 [(validate.rules).enum = {defined_only: true}];

    // An optional service name parameter which is used to validate the identity of
    // the health checked cluster using a :ref:`StringMatcher
    // <envoy_v3_api_msg_type.matcher.v3.StringMatcher>`. See the :ref:`architecture overview
    // <arch_overview_health_checking_identity>` for more information.
    type.matcher.v3.StringMatcher service_name_matcher = 11;

    // HTTP Method that will be used for health checking, default is "GET".
    // GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE, PATCH methods are supported.
    // Request body payloads are supported for POST, PUT, PATCH, and OPTIONS methods only.
    // CONNECT method is disallowed because it is not appropriate for health check request.
    // If a non-200 response is expected by the method, it needs to be set in :ref:`expected_statuses <envoy_v3_api_field_config.core.v3.HealthCheck.HttpHealthCheck.expected_statuses>`.
    RequestMethod method = 13 [(validate.rules).enum = {defined_only: true not_in: 6}];
  }

  message TcpHealthCheck {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.TcpHealthCheck";

    // Empty payloads imply a connect-only health check.
    Payload send = 1;

    // When checking the response, “fuzzy” matching is performed such that each
    // payload block must be found, and in the order specified, but not
    // necessarily contiguous.
    repeated Payload receive = 2;

    // When setting this value, it tries to attempt health check request with ProxyProtocol.
    // When ``send`` is presented, they are sent after preceding ProxyProtocol header.
    // Only ProxyProtocol header is sent when ``send`` is not presented.
    // It allows to use both ProxyProtocol V1 and V2. In V1, it presents L3/L4. In V2, it includes
    // LOCAL command and doesn't include L3/L4.
    ProxyProtocolConfig proxy_protocol_config = 3;
  }

  message RedisHealthCheck {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.RedisHealthCheck";

    // If set, optionally perform ``EXISTS <key>`` instead of ``PING``. A return value
    // from Redis of 0 (does not exist) is considered a passing healthcheck. A return value other
    // than 0 is considered a failure. This allows the user to mark a Redis instance for maintenance
    // by setting the specified key to any value and waiting for traffic to drain.
    string key = 1;
  }

  // `grpc.health.v1.Health
  // <https://github.com/grpc/grpc/blob/master/src/proto/grpc/health/v1/health.proto>`_-based
  // healthcheck. See `gRPC doc <https://github.com/grpc/grpc/blob/master/doc/health-checking.md>`_
  // for details.
  message GrpcHealthCheck {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.GrpcHealthCheck";

    // An optional service name parameter which will be sent to gRPC service in
    // `grpc.health.v1.HealthCheckRequest
    // <https://github.com/grpc/grpc/blob/master/src/proto/grpc/health/v1/health.proto#L20>`_.
    // message. See `gRPC health-checking overview
    // <https://github.com/grpc/grpc/blob/master/doc/health-checking.md>`_ for more information.
    string service_name = 1;

    // The value of the :authority header in the gRPC health check request. If
    // left empty (default value), the name of the cluster this health check is associated
    // with will be used. The authority header can be customized for a specific endpoint by setting
    // the :ref:`hostname <envoy_v3_api_field_config.endpoint.v3.Endpoint.HealthCheckConfig.hostname>` field.
    string authority = 2
        [(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}];

    // Specifies a list of key-value pairs that should be added to the metadata of each GRPC call
    // that is sent to the health checked cluster. For more information, including details on header value syntax,
    // see the documentation on :ref:`custom request headers
    // <config_http_conn_man_headers_custom_request_headers>`.
    repeated HeaderValueOption initial_metadata = 3 [(validate.rules).repeated = {max_items: 1000}];
  }

  // Custom health check.
  message CustomHealthCheck {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.CustomHealthCheck";

    reserved 2;

    reserved "config";

    // The registered name of the custom health checker.
    string name = 1 [(validate.rules).string = {min_len: 1}];

    // A custom health checker specific configuration which depends on the custom health checker
    // being instantiated. See :api:`envoy/config/health_checker` for reference.
    // [#extension-category: envoy.health_checkers]
    oneof config_type {
      google.protobuf.Any typed_config = 3;
    }
  }

  // Health checks occur over the transport socket specified for the cluster. This implies that if a
  // cluster is using a TLS-enabled transport socket, the health check will also occur over TLS.
  //
  // This allows overriding the cluster TLS settings, just for health check connections.
  message TlsOptions {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.api.v2.core.HealthCheck.TlsOptions";

    // Specifies the ALPN protocols for health check connections. This is useful if the
    // corresponding upstream is using ALPN-based :ref:`FilterChainMatch
    // <envoy_v3_api_msg_config.listener.v3.FilterChainMatch>` along with different protocols for health checks
    // versus data connections. If empty, no ALPN protocols will be set on health check connections.
    repeated string alpn_protocols = 1;
  }

  reserved 10;

  // The time to wait for a health check response. If the timeout is reached the
  // health check attempt will be considered a failure.
  google.protobuf.Duration timeout = 1 [(validate.rules).duration = {
    required: true
    gt {}
  }];

  // The interval between health checks.
  google.protobuf.Duration interval = 2 [(validate.rules).duration = {
    required: true
    gt {}
  }];

  // An optional jitter amount in milliseconds. If specified, Envoy will start health
  // checking after for a random time in ms between 0 and initial_jitter. This only
  // applies to the first health check.
  google.protobuf.Duration initial_jitter = 20;

  // An optional jitter amount in milliseconds. If specified, during every
  // interval Envoy will add interval_jitter to the wait time.
  google.protobuf.Duration interval_jitter = 3;

  // An optional jitter amount as a percentage of interval_ms. If specified,
  // during every interval Envoy will add ``interval_ms`` *
  // ``interval_jitter_percent`` / 100 to the wait time.
  //
  // If interval_jitter_ms and interval_jitter_percent are both set, both of
  // them will be used to increase the wait time.
  uint32 interval_jitter_percent = 18;

  // The number of unhealthy health checks required before a host is marked
  // unhealthy. Note that for ``http`` health checking if a host responds with a code not in
  // :ref:`expected_statuses <envoy_v3_api_field_config.core.v3.HealthCheck.HttpHealthCheck.expected_statuses>`
  // or :ref:`retriable_statuses <envoy_v3_api_field_config.core.v3.HealthCheck.HttpHealthCheck.retriable_statuses>`,
  // this threshold is ignored and the host is considered immediately unhealthy.
  google.protobuf.UInt32Value unhealthy_threshold = 4 [(validate.rules).message = {required: true}];

  // The number of healthy health checks required before a host is marked
  // healthy. Note that during startup, only a single successful health check is
  // required to mark a host healthy.
  google.protobuf.UInt32Value healthy_threshold = 5 [(validate.rules).message = {required: true}];

  // [#not-implemented-hide:] Non-serving port for health checking.
  google.protobuf.UInt32Value alt_port = 6;

  // Reuse health check connection between health checks. Default is true.
  google.protobuf.BoolValue reuse_connection = 7;

  oneof health_checker {
    option (validate.required) = true;

    // HTTP health check.
    HttpHealthCheck http_health_check = 8;

    // TCP health check.
    TcpHealthCheck tcp_health_check = 9;

    // gRPC health check.
    GrpcHealthCheck grpc_health_check = 11;

    // Custom health check.
    CustomHealthCheck custom_health_check = 13;
  }

  // The "no traffic interval" is a special health check interval that is used when a cluster has
  // never had traffic routed to it. This lower interval allows cluster information to be kept up to
  // date, without sending a potentially large amount of active health checking traffic for no
  // reason. Once a cluster has been used for traffic routing, Envoy will shift back to using the
  // standard health check interval that is defined. Note that this interval takes precedence over
  // any other.
  //
  // The default value for "no traffic interval" is 60 seconds.
  google.protobuf.Duration no_traffic_interval = 12 [(validate.rules).duration = {gt {}}];

  // The "no traffic healthy interval" is a special health check interval that
  // is used for hosts that are currently passing active health checking
  // (including new hosts) when the cluster has received no traffic.
  //
  // This is useful for when we want to send frequent health checks with
  // ``no_traffic_interval`` but then revert to lower frequency ``no_traffic_healthy_interval`` once
  // a host in the cluster is marked as healthy.
  //
  // Once a cluster has been used for traffic routing, Envoy will shift back to using the
  // standard health check interval that is defined.
  //
  // If no_traffic_healthy_interval is not set, it will default to the
  // no traffic interval and send that interval regardless of health state.
  google.protobuf.Duration no_traffic_healthy_interval = 24 [(validate.rules).duration = {gt {}}];

  // The "unhealthy interval" is a health check interval that is used for hosts that are marked as
  // unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the
  // standard health check interval that is defined.
  //
  // The default value for "unhealthy interval" is the same as "interval".
  google.protobuf.Duration unhealthy_interval = 14 [(validate.rules).duration = {gt {}}];

  // The "unhealthy edge interval" is a special health check interval that is used for the first
  // health check right after a host is marked as unhealthy. For subsequent health checks
  // Envoy will shift back to using either "unhealthy interval" if present or the standard health
  // check interval that is defined.
  //
  // The default value for "unhealthy edge interval" is the same as "unhealthy interval".
  google.protobuf.Duration unhealthy_edge_interval = 15 [(validate.rules).duration = {gt {}}];

  // The "healthy edge interval" is a special health check interval that is used for the first
  // health check right after a host is marked as healthy. For subsequent health checks
  // Envoy will shift back to using the standard health check interval that is defined.
  //
  // The default value for "healthy edge interval" is the same as the default interval.
  google.protobuf.Duration healthy_edge_interval = 16 [(validate.rules).duration = {gt {}}];

  // Specifies the path to the :ref:`health check event log <arch_overview_health_check_logging>`.
  //
  // .. attention::
  //   This field is deprecated in favor of the extension
  //   :ref:`event_logger <envoy_v3_api_field_config.core.v3.HealthCheck.event_logger>` and
  //   :ref:`event_log_path <envoy_v3_api_field_extensions.health_check.event_sinks.file.v3.HealthCheckEventFileSink.event_log_path>`
  //   in the file sink extension.
  string event_log_path = 17
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  // A list of event log sinks to process the health check event.
  // [#extension-category: envoy.health_check.event_sinks]
  repeated TypedExtensionConfig event_logger = 25;

  // [#not-implemented-hide:]
  // The gRPC service for the health check event service.
  // If empty, health check events won't be sent to a remote endpoint.
  EventServiceConfig event_service = 22;

  // If set to true, health check failure events will always be logged. If set to false, only the
  // initial health check failure event will be logged.
  // The default value is false.
  bool always_log_health_check_failures = 19;

  // If set to true, health check success events will always be logged. If set to false, only host addition event will be logged
  // if it is the first successful health check, or if the healthy threshold is reached.
  // The default value is false.
  bool always_log_health_check_success = 26;

  // This allows overriding the cluster TLS settings, just for health check connections.
  TlsOptions tls_options = 21;

  // Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's
  // :ref:`tranport socket matches <envoy_v3_api_field_config.cluster.v3.Cluster.transport_socket_matches>`.
  // For example, the following match criteria
  //
  // .. code-block:: yaml
  //
  //  transport_socket_match_criteria:
  //    useMTLS: true
  //
  // Will match the following :ref:`cluster socket match <envoy_v3_api_msg_config.cluster.v3.Cluster.TransportSocketMatch>`
  //
  // .. code-block:: yaml
  //
  //  transport_socket_matches:
  //  - name: "useMTLS"
  //    match:
  //      useMTLS: true
  //    transport_socket:
  //      name: envoy.transport_sockets.tls
  //      config: { ... } # tls socket configuration
  //
  // If this field is set, then for health checks it will supersede an entry of ``envoy.transport_socket`` in the
  // :ref:`LbEndpoint.Metadata <envoy_v3_api_field_config.endpoint.v3.LbEndpoint.metadata>`.
  // This allows using different transport socket capabilities for health checking versus proxying to the
  // endpoint.
  //
  // If the key/values pairs specified do not match any
  // :ref:`transport socket matches <envoy_v3_api_field_config.cluster.v3.Cluster.transport_socket_matches>`,
  // the cluster's :ref:`transport socket <envoy_v3_api_field_config.cluster.v3.Cluster.transport_socket>`
  // will be used for health check socket configuration.
  google.protobuf.Struct transport_socket_match_criteria = 23;
}
