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

syntax = "proto3";

package hashicorp.consul.mesh.v2beta1;

import "pbmesh/v2beta1/common.proto";
import "pbmesh/v2beta1/http_route.proto";
import "pbmesh/v2beta1/http_route_retries.proto";
import "pbmesh/v2beta1/http_route_timeouts.proto";
import "pbresource/annotations.proto";

// NOTE: this should align to the GAMMA/gateway-api version, or at least be
// easily translatable.
//
// https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1alpha2.GRPCRoute
//
// This is a Resource type.
message GRPCRoute {
  option (hashicorp.consul.resource.spec) = {scope: SCOPE_NAMESPACE};

  // ParentRefs references the resources (usually Services) that a Route wants
  // to be attached to.
  //
  // It is invalid to reference an identical parent more than once. It is valid
  // to reference multiple distinct sections within the same parent resource.
  repeated ParentReference parent_refs = 1;

  // Hostnames are the hostnames for which this GRPCRoute should respond to requests.
  //
  // This is only valid for north/south.
  repeated string hostnames = 2;

  // Rules are a list of GRPC matchers, filters and actions.
  repeated GRPCRouteRule rules = 3;
}

message GRPCRouteRule {
  repeated GRPCRouteMatch matches = 1;
  repeated GRPCRouteFilter filters = 2;

  // BackendRefs defines the backend(s) where matching requests should be sent.
  // Failure behavior here depends on how many BackendRefs are specified and
  // how many are invalid.
  //
  // If all entries in BackendRefs are invalid, and there are also no filters
  // specified in this route rule, all traffic which matches this rule MUST
  // receive a 500 status code.
  //
  // See the GRPCBackendRef definition for the rules about what makes a single
  // GRPCBackendRef invalid.
  //
  // When a GRPCBackendRef is invalid, 500 status codes MUST be returned for
  // requests that would have otherwise been routed to an invalid backend. If
  // multiple backends are specified, and some are invalid, the proportion of
  // requests that would otherwise have been routed to an invalid backend MUST
  // receive a 500 status code.
  //
  // For example, if two backends are specified with equal weights, and one is
  // invalid, 50 percent of traffic must receive a 500. Implementations may
  // choose how that 50 percent is determined.
  repeated GRPCBackendRef backend_refs = 3;

  HTTPRouteTimeouts timeouts = 4;
  HTTPRouteRetries retries = 5;
}

message GRPCRouteMatch {
  // Method specifies a gRPC request service/method matcher. If this field is
  // not specified, all services and methods will match.
  GRPCMethodMatch method = 1;

  // Headers specifies gRPC request header matchers. Multiple match values are
  // ANDed together, meaning, a request MUST match all the specified headers to
  // select the route.
  repeated GRPCHeaderMatch headers = 2;
}

message GRPCMethodMatch {
  // Type specifies how to match against the service and/or method. Support:
  // Core (Exact with service and method specified)
  GRPCMethodMatchType type = 1;

  // Value of the service to match against. If left empty or omitted, will
  // match any service.
  //
  // At least one of Service and Method MUST be a non-empty string.
  string service = 2;

  // Value of the method to match against. If left empty or omitted, will match
  // all services.
  //
  // At least one of Service and Method MUST be a non-empty string.}
  string method = 3;
}

// +kubebuilder:validation:Enum=GRPC_METHOD_MATCH_TYPE_UNSPECIFIED;GRPC_METHOD_MATCH_TYPE_EXACT;GRPC_METHOD_MATCH_TYPE_REGEX
// +kubebuilder:validation:Type=string
enum GRPCMethodMatchType {
  GRPC_METHOD_MATCH_TYPE_UNSPECIFIED = 0;
  GRPC_METHOD_MATCH_TYPE_EXACT = 1;
  GRPC_METHOD_MATCH_TYPE_REGEX = 2;
}

message GRPCHeaderMatch {
  HeaderMatchType type = 1;
  string name = 2;
  string value = 3;
}

message GRPCRouteFilter {
  // RequestHeaderModifier defines a schema for a filter that modifies request
  // headers.
  HTTPHeaderFilter request_header_modifier = 1;

  // ResponseHeaderModifier defines a schema for a filter that modifies
  // response headers.
  HTTPHeaderFilter response_header_modifier = 2;

  // URLRewrite defines a schema for a filter that modifies a request during
  // forwarding.
  HTTPURLRewriteFilter url_rewrite = 5;
}

message GRPCBackendRef {
  BackendReference backend_ref = 1;

  // Weight specifies the proportion of requests forwarded to the referenced
  // backend. This is computed as weight/(sum of all weights in this
  // BackendRefs list). For non-zero values, there may be some epsilon from the
  // exact proportion defined here depending on the precision an implementation
  // supports. Weight is not a percentage and the sum of weights does not need
  // to equal 100.
  //
  //If only one backend is specified and it has a weight greater than 0, 100%
  //of the traffic is forwarded to that backend. If weight is set to 0, no
  //traffic should be forwarded for this entry. If unspecified, weight defaults
  //to 1.
  uint32 weight = 2;

  // Filters defined at this level should be executed if and only if the
  // request is being forwarded to the backend defined here.
  repeated GRPCRouteFilter filters = 3;
}