// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

syntax = "proto3";

package hashicorp.consul.mesh.v2beta1;

import "google/protobuf/duration.proto";
import "pbresource/annotations.proto";

// DestinationPolicy is the destination-controlled set of defaults that
// are used when similar controls defined in an DestinationsConfiguration are
// left unspecified.
//
// Users may wish to share commonly configured settings for communicating with
// a service in one place, but yet retain the ability to tweak those on a
// client-by-client basis, which is why there are separate resources to control
// the definition of these values from either end of the connection.
//
// This is a Resource type.
message DestinationPolicy {
  option (hashicorp.consul.resource.spec) = {scope: SCOPE_NAMESPACE};

  // PortConfigs defines the destination policy for a specific port on a service.
  //
  // For more details on potential values of the service port identifier key,
  // see documentation for Service.ServicePort.
  map<string, DestinationConfig> port_configs = 1;
}

message DestinationConfig {
  // ConnectTimeout is the timeout for establishing new network connections
  // to this service.
  // +kubebuilder:validation:Format=duration
  google.protobuf.Duration connect_timeout = 1;

  // RequestTimeout is the timeout for an HTTP request to complete before the
  // connection is automatically terminated. If unspecified, defaults to 15
  // seconds.
  // +kubebuilder:validation:Format=duration
  google.protobuf.Duration request_timeout = 2;

  // LoadBalancer determines the load balancing policy and configuration for
  // services issuing requests to this upstream service.
  LoadBalancer load_balancer = 3;

  // LocalityPrioritization controls whether the locality of services within the
  // local partition will be used to prioritize connectivity.
  LocalityPrioritization locality_prioritization = 4;
}

message LocalityPrioritization {
  // Mode specifies the type of prioritization that will be performed
  // when selecting nodes in the local partition.
  // Valid values are: "" (default "none"), "none", and "failover".
  LocalityPrioritizationMode mode = 1;
}

// +kubebuilder:validation:Enum=LOCALITY_PRIORITIZATION_MODE_UNSPECIFIED;LOCALITY_PRIORITIZATION_MODE_NONE;LOCALITY_PRIORITIZATION_MODE_FAILOVER
// +kubebuilder:validation:Type=string
enum LocalityPrioritizationMode {
  LOCALITY_PRIORITIZATION_MODE_UNSPECIFIED = 0;
  LOCALITY_PRIORITIZATION_MODE_NONE = 1;
  LOCALITY_PRIORITIZATION_MODE_FAILOVER = 2;
}

// LoadBalancer determines the load balancing policy and configuration
// for services issuing requests to this upstream service.
//
message LoadBalancer {
  // Policy is the load balancing policy used to select a host
  LoadBalancerPolicy policy = 1;

  // HashPolicies is a list of hash policies to use for hashing load balancing
  // algorithms. Hash policies are evaluated individually and combined such
  // that identical lists result in the same hash.
  //
  // If no hash policies are present, or none are successfully evaluated,
  // then a random backend host will be selected.
  repeated HashPolicy hash_policies = 2;

  oneof config {
    // RingHashConfig contains configuration for the "ring_hash" policy type
    RingHashConfig ring_hash_config = 3;

    // LeastRequestConfig contains configuration for the "least_request" policy type
    LeastRequestConfig least_request_config = 4;
  }
}

// +kubebuilder:validation:Enum=LOAD_BALANCER_POLICY_UNSPECIFIED;LOAD_BALANCER_POLICY_RANDOM;LOAD_BALANCER_POLICY_ROUND_ROBIN;LOAD_BALANCER_POLICY_LEAST_REQUEST;LOAD_BALANCER_POLICY_MAGLEV;LOAD_BALANCER_POLICY_RING_HASH
// +kubebuilder:validation:Type=string
enum LoadBalancerPolicy {
  LOAD_BALANCER_POLICY_UNSPECIFIED = 0;
  LOAD_BALANCER_POLICY_RANDOM = 1;
  LOAD_BALANCER_POLICY_ROUND_ROBIN = 2;
  LOAD_BALANCER_POLICY_LEAST_REQUEST = 3;
  LOAD_BALANCER_POLICY_MAGLEV = 4;
  LOAD_BALANCER_POLICY_RING_HASH = 5;
}

// RingHashConfig contains configuration for the "ring_hash" policy type
message RingHashConfig {
  // MinimumRingSize determines the minimum number of entries in the hash ring
  uint64 minimum_ring_size = 1;

  // MaximumRingSize determines the maximum number of entries in the hash ring
  uint64 maximum_ring_size = 2;
}

// LeastRequestConfig contains configuration for the "least_request" policy type
message LeastRequestConfig {
  // ChoiceCount determines the number of random healthy hosts from which to select the one with the least requests.
  uint32 choice_count = 1;
}

// HashPolicy defines which attributes will be hashed by hash-based LB algorithms
message HashPolicy {
  // Field is the attribute type to hash on.
  // Must be one of "header","cookie", or "query_parameter".
  // Cannot be specified along with SourceIP.
  HashPolicyField field = 1;

  // FieldValue is the value to hash.
  // ie. header name, cookie name, URL query parameter name
  // Cannot be specified along with SourceIP.
  string field_value = 2;

  // CookieConfig contains configuration for the "cookie" hash policy type.
  CookieConfig cookie_config = 3;

  // SourceIP determines whether the hash should be of the source IP rather than of a field and field value.
  // Cannot be specified along with Field or FieldValue.
  bool source_ip = 4;

  // Terminal will short circuit the computation of the hash when multiple hash policies are present.
  // If a hash is computed when a Terminal policy is evaluated,
  // then that hash will be used and subsequent hash policies will be ignored.
  bool terminal = 5;
}

// +kubebuilder:validation:Enum=HASH_POLICY_FIELD_UNSPECIFIED;HASH_POLICY_FIELD_HEADER;HASH_POLICY_FIELD_COOKIE;HASH_POLICY_FIELD_QUERY_PARAMETER
// +kubebuilder:validation:Type=string
enum HashPolicyField {
  HASH_POLICY_FIELD_UNSPECIFIED = 0;
  HASH_POLICY_FIELD_HEADER = 1;
  HASH_POLICY_FIELD_COOKIE = 2;
  HASH_POLICY_FIELD_QUERY_PARAMETER = 3;
}

// CookieConfig contains configuration for the "cookie" hash policy type.
// This is specified to have Envoy generate a cookie for a client on its first request.
message CookieConfig {
  // Generates a session cookie with no expiration.
  bool session = 1;

  // TTL for generated cookies. Cannot be specified for session cookies.
  // +kubebuilder:validation:Format=duration
  google.protobuf.Duration ttl = 2;

  // The path to set for the cookie
  string path = 3;
}
