mirror of https://github.com/status-im/consul.git
mesh: compute more of the xRoute features into ComputedRoutes (#18980)
Convert more of the xRoutes features that were skipped in an earlier PR into ComputedRoutes and make them work: - DestinationPolicy defaults - more timeouts - load balancer policy - request/response header mutations - urlrewrite - GRPCRoute matches
This commit is contained in:
parent
d3bb5ff21a
commit
9e48607893
|
@ -11,8 +11,6 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1"
|
||||
|
||||
svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing"
|
||||
"github.com/hashicorp/consul/internal/catalog"
|
||||
"github.com/hashicorp/consul/internal/controller"
|
||||
|
@ -20,6 +18,7 @@ import (
|
|||
"github.com/hashicorp/consul/internal/resource"
|
||||
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
|
||||
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
|
||||
pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1"
|
||||
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||
"github.com/hashicorp/consul/proto/private/prototest"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
|
@ -115,6 +114,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -187,6 +187,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -214,6 +215,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -241,6 +243,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "http2", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -263,6 +266,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -350,6 +354,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -379,6 +384,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -408,6 +414,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -437,6 +444,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -551,6 +559,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -591,6 +600,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -632,6 +642,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -672,6 +683,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -789,6 +801,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -818,6 +831,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -847,6 +861,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -876,6 +891,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -955,6 +971,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -984,6 +1001,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1013,6 +1031,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1042,6 +1061,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1169,6 +1189,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1207,6 +1228,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1263,6 +1285,7 @@ func (suite *controllerSuite) TestController() {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(barServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,6 +5,10 @@ package routes
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
"github.com/hashicorp/consul/internal/catalog"
|
||||
"github.com/hashicorp/consul/internal/mesh/internal/controllers/routes/loader"
|
||||
|
@ -334,6 +338,72 @@ func compile(
|
|||
details.DestinationConfig = portDestConfig
|
||||
}
|
||||
}
|
||||
details.DestinationConfig = fillInDefaultDestConfig(details.DestinationConfig)
|
||||
}
|
||||
|
||||
// Pull target information up to the level of the rules.
|
||||
switch x := mc.Config.(type) {
|
||||
case *pbmesh.ComputedPortRoutes_Http:
|
||||
route := x.Http
|
||||
for _, rule := range route.Rules {
|
||||
// If there are multiple legs (split) then choose the first actually set value.
|
||||
var requestTimeoutFallback *durationpb.Duration
|
||||
for _, backendRef := range rule.BackendRefs {
|
||||
if backendRef.BackendTarget == types.NullRouteBackend {
|
||||
continue
|
||||
}
|
||||
details, ok := mc.Targets[backendRef.BackendTarget]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if details.DestinationConfig.RequestTimeout != nil {
|
||||
requestTimeoutFallback = details.DestinationConfig.RequestTimeout
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if requestTimeoutFallback == nil {
|
||||
continue // nothing to do
|
||||
}
|
||||
|
||||
if rule.Timeouts == nil {
|
||||
rule.Timeouts = &pbmesh.HTTPRouteTimeouts{}
|
||||
}
|
||||
if rule.Timeouts.Request == nil {
|
||||
rule.Timeouts.Request = requestTimeoutFallback
|
||||
}
|
||||
}
|
||||
case *pbmesh.ComputedPortRoutes_Grpc:
|
||||
route := x.Grpc
|
||||
for _, rule := range route.Rules {
|
||||
// If there are multiple legs (split) then choose the first actually set value.
|
||||
var requestTimeoutFallback *durationpb.Duration
|
||||
for _, backendRef := range rule.BackendRefs {
|
||||
if backendRef.BackendTarget == types.NullRouteBackend {
|
||||
continue
|
||||
}
|
||||
details, ok := mc.Targets[backendRef.BackendTarget]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if details.DestinationConfig.RequestTimeout != nil {
|
||||
requestTimeoutFallback = details.DestinationConfig.RequestTimeout
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if requestTimeoutFallback == nil {
|
||||
continue // nothing to do
|
||||
}
|
||||
|
||||
if rule.Timeouts == nil {
|
||||
rule.Timeouts = &pbmesh.HTTPRouteTimeouts{}
|
||||
}
|
||||
if rule.Timeouts.Request == nil {
|
||||
rule.Timeouts.Request = requestTimeoutFallback
|
||||
}
|
||||
}
|
||||
case *pbmesh.ComputedPortRoutes_Tcp:
|
||||
}
|
||||
|
||||
computedRoutes.PortedConfigs[port] = mc
|
||||
|
@ -412,6 +482,28 @@ func compileFailoverConfig(
|
|||
return cfc
|
||||
}
|
||||
|
||||
func fillInDefaultDestConfig(target *pbmesh.DestinationConfig) *pbmesh.DestinationConfig {
|
||||
base := defaultDestConfig()
|
||||
|
||||
if target == nil {
|
||||
return proto.Clone(base).(*pbmesh.DestinationConfig)
|
||||
}
|
||||
|
||||
out := proto.Clone(target).(*pbmesh.DestinationConfig)
|
||||
|
||||
if out.ConnectTimeout == nil {
|
||||
out.ConnectTimeout = base.GetConnectTimeout()
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func defaultDestConfig() *pbmesh.DestinationConfig {
|
||||
return &pbmesh.DestinationConfig{
|
||||
ConnectTimeout: durationpb.New(5 * time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
func compileHTTPRouteNode(
|
||||
port string,
|
||||
res *pbresource.Resource,
|
||||
|
|
|
@ -225,6 +225,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -285,6 +286,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, protoName, ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -337,6 +339,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -446,6 +449,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -475,6 +479,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -504,6 +509,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -533,6 +539,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -615,6 +622,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, portName, ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -724,6 +732,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -806,6 +815,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(apiServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -913,6 +923,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1065,11 +1076,13 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
backendName("bar", "http"): {
|
||||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(barServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1158,6 +1171,7 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1652,11 +1666,13 @@ func TestGenerateComputedRoutes(t *testing.T) {
|
|||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(fooServiceRef, "http", ""),
|
||||
FailoverConfig: portFailoverConfig,
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
backendName("bar", "http"): {
|
||||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_INDIRECT,
|
||||
MeshPort: "mesh",
|
||||
BackendRef: newBackendRef(barServiceRef, "http", ""),
|
||||
DestinationConfig: defaultDestConfig(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,19 +5,16 @@ package routes
|
|||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/hashicorp/consul/internal/protoutil"
|
||||
)
|
||||
|
||||
// Deprecated: see protoutil.Clone
|
||||
func protoClone[T proto.Message](v T) T {
|
||||
return proto.Clone(v).(T)
|
||||
return protoutil.Clone(v)
|
||||
}
|
||||
|
||||
// Deprecated: see protoutil.CloneSlice
|
||||
func protoSliceClone[T proto.Message](in []T) []T {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := make([]T, 0, len(in))
|
||||
for _, v := range in {
|
||||
out = append(out, protoClone[T](v))
|
||||
}
|
||||
return out
|
||||
return protoutil.CloneSlice(in)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
|
@ -15,6 +14,7 @@ import (
|
|||
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
||||
"github.com/hashicorp/consul/internal/mesh/internal/types"
|
||||
"github.com/hashicorp/consul/internal/mesh/internal/types/intermediate"
|
||||
"github.com/hashicorp/consul/internal/protoutil"
|
||||
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
|
||||
pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1"
|
||||
"github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate"
|
||||
|
@ -109,6 +109,8 @@ func (b *Builder) buildDestination(
|
|||
}
|
||||
}
|
||||
destConfig := b.makeDestinationConfiguration(routeRule.Timeouts, routeRule.Retries)
|
||||
headerMutations := applyRouteFilters(destConfig, routeRule.Filters)
|
||||
applyLoadBalancerPolicy(destConfig, cpr, routeRule.BackendRefs)
|
||||
|
||||
dest := b.makeHTTPRouteDestination(
|
||||
routeRule.BackendRefs,
|
||||
|
@ -117,17 +119,14 @@ func (b *Builder) buildDestination(
|
|||
defaultDC,
|
||||
)
|
||||
|
||||
// TODO(rb/v2): Filters []*HTTPRouteFilter
|
||||
// TODO(rb/v2): BackendRefs []*ComputedHTTPBackendRef
|
||||
|
||||
// Explode out by matches
|
||||
for _, match := range routeRule.Matches {
|
||||
routeMatch := makeHTTPRouteMatch(match)
|
||||
|
||||
proxyRouteRules = append(proxyRouteRules, &pbproxystate.RouteRule{
|
||||
Match: routeMatch,
|
||||
Destination: proto.Clone(dest).(*pbproxystate.RouteDestination),
|
||||
// TODO: mutations
|
||||
Destination: protoutil.Clone(dest),
|
||||
HeaderMutations: protoutil.CloneSlice(headerMutations),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +152,8 @@ func (b *Builder) buildDestination(
|
|||
}
|
||||
}
|
||||
destConfig := b.makeDestinationConfiguration(routeRule.Timeouts, routeRule.Retries)
|
||||
headerMutations := applyRouteFilters(destConfig, routeRule.Filters)
|
||||
applyLoadBalancerPolicy(destConfig, cpr, routeRule.BackendRefs)
|
||||
|
||||
// nolint:staticcheck
|
||||
dest := b.makeGRPCRouteDestination(
|
||||
|
@ -162,16 +163,14 @@ func (b *Builder) buildDestination(
|
|||
defaultDC,
|
||||
)
|
||||
|
||||
// TODO(rb/v2): Filters []*HTTPRouteFilter
|
||||
|
||||
// Explode out by matches
|
||||
for _, match := range routeRule.Matches {
|
||||
routeMatch := makeGRPCRouteMatch(match)
|
||||
|
||||
proxyRouteRules = append(proxyRouteRules, &pbproxystate.RouteRule{
|
||||
Match: routeMatch,
|
||||
Destination: proto.Clone(dest).(*pbproxystate.RouteDestination),
|
||||
// TODO: mutations
|
||||
Destination: protoutil.Clone(dest),
|
||||
HeaderMutations: protoutil.CloneSlice(headerMutations),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +266,8 @@ func (b *Builder) buildDestination(
|
|||
continue
|
||||
}
|
||||
|
||||
connectTimeout := durationpb.New(5 * time.Second)
|
||||
connectTimeout := details.DestinationConfig.ConnectTimeout
|
||||
loadBalancer := details.DestinationConfig.LoadBalancer
|
||||
|
||||
// NOTE: we collect both DIRECT and INDIRECT target information here.
|
||||
dc := defaultDC(details.BackendRef.Datacenter)
|
||||
|
@ -280,7 +280,7 @@ func (b *Builder) buildDestination(
|
|||
)
|
||||
clusterName := fmt.Sprintf("%s.%s", portName, sni)
|
||||
|
||||
egBase := b.newClusterEndpointGroup("", sni, portName, details.IdentityRefs, connectTimeout)
|
||||
egBase := b.newClusterEndpointGroup("", sni, portName, details.IdentityRefs, connectTimeout, loadBalancer)
|
||||
|
||||
var endpointGroups []*pbproxystate.EndpointGroup
|
||||
|
||||
|
@ -301,6 +301,9 @@ func (b *Builder) buildDestination(
|
|||
continue // not possible
|
||||
}
|
||||
|
||||
destConnectTimeout := destDetails.DestinationConfig.ConnectTimeout
|
||||
destLoadBalancer := destDetails.DestinationConfig.LoadBalancer
|
||||
|
||||
destDC := defaultDC(destDetails.BackendRef.Datacenter)
|
||||
destPortName := destDetails.BackendRef.Port
|
||||
|
||||
|
@ -311,7 +314,7 @@ func (b *Builder) buildDestination(
|
|||
)
|
||||
destClusterName := fmt.Sprintf("%s%d~%s", xdscommon.FailoverClusterNamePrefix, i, clusterName)
|
||||
|
||||
egDest := b.newClusterEndpointGroup(destClusterName, destSNI, destPortName, destDetails.IdentityRefs, connectTimeout)
|
||||
egDest := b.newClusterEndpointGroup(destClusterName, destSNI, destPortName, destDetails.IdentityRefs, destConnectTimeout, destLoadBalancer)
|
||||
|
||||
endpointGroups = append(endpointGroups, egDest)
|
||||
b.addEndpointsRef(destClusterName, destDetails.ServiceEndpointsId, destDetails.MeshPort)
|
||||
|
@ -389,7 +392,7 @@ func (b *ListenerBuilder) addL4RouterForSplit(
|
|||
},
|
||||
},
|
||||
StatPrefix: statPrefix,
|
||||
// TODO: can we use RDS for TCPRoute split?
|
||||
// TODO(rb/v2): can we use RDS for TCPRoute split?
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -565,24 +568,71 @@ func (b *Builder) newClusterEndpointGroup(
|
|||
portName string,
|
||||
destinationIdentities []*pbresource.Reference,
|
||||
connectTimeout *durationpb.Duration,
|
||||
loadBalancer *pbmesh.LoadBalancer,
|
||||
) *pbproxystate.EndpointGroup {
|
||||
var spiffeIDs []string
|
||||
for _, identity := range destinationIdentities {
|
||||
spiffeIDs = append(spiffeIDs, connect.SpiffeIDFromIdentityRef(b.trustDomain, identity))
|
||||
}
|
||||
|
||||
// TODO(v2): DestinationPolicy: connect timeout, lb policy, cluster discovery type, circuit breakers, outlier detection
|
||||
// TODO(v2): DestinationPolicy: circuit breakers, outlier detection
|
||||
|
||||
// TODO(v2): if http2/grpc then set http2protocol options
|
||||
|
||||
degConfig := &pbproxystate.DynamicEndpointGroupConfig{
|
||||
DisablePanicThreshold: true,
|
||||
ConnectTimeout: connectTimeout,
|
||||
}
|
||||
|
||||
if loadBalancer != nil {
|
||||
// enumcover:pbmesh.LoadBalancerPolicy
|
||||
switch loadBalancer.Policy {
|
||||
case pbmesh.LoadBalancerPolicy_LOAD_BALANCER_POLICY_RANDOM:
|
||||
degConfig.LbPolicy = &pbproxystate.DynamicEndpointGroupConfig_Random{}
|
||||
|
||||
case pbmesh.LoadBalancerPolicy_LOAD_BALANCER_POLICY_ROUND_ROBIN:
|
||||
degConfig.LbPolicy = &pbproxystate.DynamicEndpointGroupConfig_RoundRobin{}
|
||||
|
||||
case pbmesh.LoadBalancerPolicy_LOAD_BALANCER_POLICY_LEAST_REQUEST:
|
||||
var choiceCount uint32
|
||||
cfg, ok := loadBalancer.Config.(*pbmesh.LoadBalancer_LeastRequestConfig)
|
||||
if ok {
|
||||
choiceCount = cfg.LeastRequestConfig.GetChoiceCount()
|
||||
}
|
||||
degConfig.LbPolicy = &pbproxystate.DynamicEndpointGroupConfig_LeastRequest{
|
||||
LeastRequest: &pbproxystate.LBPolicyLeastRequest{
|
||||
ChoiceCount: wrapperspb.UInt32(choiceCount),
|
||||
},
|
||||
}
|
||||
|
||||
case pbmesh.LoadBalancerPolicy_LOAD_BALANCER_POLICY_MAGLEV:
|
||||
degConfig.LbPolicy = &pbproxystate.DynamicEndpointGroupConfig_Maglev{}
|
||||
|
||||
case pbmesh.LoadBalancerPolicy_LOAD_BALANCER_POLICY_RING_HASH:
|
||||
policy := &pbproxystate.DynamicEndpointGroupConfig_RingHash{}
|
||||
|
||||
cfg, ok := loadBalancer.Config.(*pbmesh.LoadBalancer_RingHashConfig)
|
||||
if ok {
|
||||
policy.RingHash = &pbproxystate.LBPolicyRingHash{
|
||||
MinimumRingSize: wrapperspb.UInt64(cfg.RingHashConfig.MinimumRingSize),
|
||||
MaximumRingSize: wrapperspb.UInt64(cfg.RingHashConfig.MaximumRingSize),
|
||||
}
|
||||
}
|
||||
|
||||
degConfig.LbPolicy = policy
|
||||
|
||||
case pbmesh.LoadBalancerPolicy_LOAD_BALANCER_POLICY_UNSPECIFIED:
|
||||
// fallthrough to default
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
return &pbproxystate.EndpointGroup{
|
||||
Name: clusterName,
|
||||
Group: &pbproxystate.EndpointGroup_Dynamic{
|
||||
Dynamic: &pbproxystate.DynamicEndpointGroup{
|
||||
Config: &pbproxystate.DynamicEndpointGroupConfig{
|
||||
DisablePanicThreshold: true,
|
||||
ConnectTimeout: connectTimeout,
|
||||
},
|
||||
Config: degConfig,
|
||||
OutboundTls: &pbproxystate.TransportSocket{
|
||||
ConnectionTls: &pbproxystate.TransportSocket_OutboundMesh{
|
||||
OutboundMesh: &pbproxystate.OutboundMeshMTLS{
|
||||
|
|
|
@ -5,8 +5,11 @@ package builder
|
|||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
"github.com/hashicorp/consul/internal/catalog"
|
||||
"github.com/hashicorp/consul/internal/mesh/internal/controllers/routes/routestest"
|
||||
|
@ -130,6 +133,19 @@ func TestBuildExplicitDestinations(t *testing.T) {
|
|||
Tenancy: backup1Endpoints.Id.Tenancy,
|
||||
}
|
||||
|
||||
api1DestPolicy := resourcetest.Resource(types.DestinationPolicyType, api1Service.Id.Name).
|
||||
WithTenancy(api1Service.Id.GetTenancy()).
|
||||
WithData(t, &pbmesh.DestinationPolicy{
|
||||
PortConfigs: map[string]*pbmesh.DestinationConfig{
|
||||
"http": {
|
||||
ConnectTimeout: durationpb.New(55 * time.Second),
|
||||
RequestTimeout: durationpb.New(77 * time.Second),
|
||||
// LoadBalancer *LoadBalancer `protobuf:"bytes,3,opt,name=load_balancer,json=loadBalancer,proto3" json:"load_balancer,omitempty"`
|
||||
},
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
|
||||
api1HTTPRoute := resourcetest.Resource(types.HTTPRouteType, "api-1-http-route").
|
||||
WithTenancy(resource.DefaultNamespacedTenancy()).
|
||||
WithData(t, &pbmesh.HTTPRoute{
|
||||
|
@ -137,7 +153,14 @@ func TestBuildExplicitDestinations(t *testing.T) {
|
|||
Ref: resource.Reference(api1Service.Id, ""),
|
||||
Port: "http",
|
||||
}},
|
||||
Rules: []*pbmesh.HTTPRouteRule{{
|
||||
Rules: []*pbmesh.HTTPRouteRule{
|
||||
{
|
||||
Matches: []*pbmesh.HTTPRouteMatch{{
|
||||
Path: &pbmesh.HTTPPathMatch{
|
||||
Type: pbmesh.PathMatchType_PATH_MATCH_TYPE_PREFIX,
|
||||
Value: "/split",
|
||||
},
|
||||
}},
|
||||
BackendRefs: []*pbmesh.HTTPBackendRef{
|
||||
{
|
||||
BackendRef: &pbmesh.BackendReference{
|
||||
|
@ -158,7 +181,28 @@ func TestBuildExplicitDestinations(t *testing.T) {
|
|||
Weight: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Matches: []*pbmesh.HTTPRouteMatch{{
|
||||
Path: &pbmesh.HTTPPathMatch{
|
||||
Type: pbmesh.PathMatchType_PATH_MATCH_TYPE_PREFIX,
|
||||
Value: "/",
|
||||
},
|
||||
}},
|
||||
BackendRefs: []*pbmesh.HTTPBackendRef{{
|
||||
BackendRef: &pbmesh.BackendReference{
|
||||
Ref: resource.Reference(api1Service.Id, ""),
|
||||
},
|
||||
}},
|
||||
Timeouts: &pbmesh.HTTPRouteTimeouts{
|
||||
Request: durationpb.New(606 * time.Second), // differnet than the 77s
|
||||
},
|
||||
Retries: &pbmesh.HTTPRouteRetries{
|
||||
Number: wrapperspb.UInt32(4),
|
||||
OnConnectFailure: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
resourcetest.ValidateAndNormalize(t, registry, api1HTTPRoute)
|
||||
|
@ -249,6 +293,7 @@ func TestBuildExplicitDestinations(t *testing.T) {
|
|||
resourcetest.MustDecode[*pbcatalog.Service](t, api2Service),
|
||||
resourcetest.MustDecode[*pbcatalog.Service](t, backup1Service),
|
||||
// notably we do NOT include api3Service here so we trigger a null route to be generated
|
||||
resourcetest.MustDecode[*pbmesh.DestinationPolicy](t, api1DestPolicy),
|
||||
resourcetest.MustDecode[*pbmesh.HTTPRoute](t, api1HTTPRoute),
|
||||
resourcetest.MustDecode[*pbmesh.TCPRoute](t, api1TCPRoute),
|
||||
resourcetest.MustDecode[*pbcatalog.FailoverPolicy](t, api1FailoverPolicy),
|
||||
|
|
|
@ -6,7 +6,9 @@ package builder
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
"github.com/hashicorp/consul/internal/mesh/internal/types"
|
||||
|
@ -131,8 +133,6 @@ func (b *Builder) makeDestinationConfiguration(
|
|||
timeouts *pbmesh.HTTPRouteTimeouts,
|
||||
retries *pbmesh.HTTPRouteRetries,
|
||||
) *pbproxystate.DestinationConfiguration {
|
||||
// TODO: prefix rewrite, lb config
|
||||
|
||||
cfg := &pbproxystate.DestinationConfiguration{
|
||||
TimeoutConfig: translateTimeouts(timeouts),
|
||||
RetryPolicy: translateRetries(retries),
|
||||
|
@ -144,8 +144,202 @@ func (b *Builder) makeDestinationConfiguration(
|
|||
return cfg
|
||||
}
|
||||
|
||||
func makeGRPCRouteMatch(match *pbmesh.GRPCRouteMatch) *pbproxystate.RouteMatch {
|
||||
panic("TODO")
|
||||
func applyRouteFilters[V interface {
|
||||
GetRequestHeaderModifier() *pbmesh.HTTPHeaderFilter
|
||||
GetResponseHeaderModifier() *pbmesh.HTTPHeaderFilter
|
||||
GetUrlRewrite() *pbmesh.HTTPURLRewriteFilter
|
||||
}](
|
||||
psDestConfig *pbproxystate.DestinationConfiguration,
|
||||
filters []V,
|
||||
) []*pbproxystate.HeaderMutation {
|
||||
var headerMutations []*pbproxystate.HeaderMutation
|
||||
for _, filter := range filters {
|
||||
switch {
|
||||
case filter.GetRequestHeaderModifier() != nil:
|
||||
mod := filter.GetRequestHeaderModifier()
|
||||
|
||||
for _, hdr := range mod.Set {
|
||||
headerMutations = append(headerMutations, &pbproxystate.HeaderMutation{
|
||||
Action: &pbproxystate.HeaderMutation_RequestHeaderAdd{
|
||||
RequestHeaderAdd: &pbproxystate.RequestHeaderAdd{
|
||||
Header: &pbproxystate.Header{
|
||||
Key: hdr.Name,
|
||||
Value: hdr.Value,
|
||||
},
|
||||
AppendAction: pbproxystate.AppendAction_APPEND_ACTION_OVERWRITE_IF_EXISTS_OR_ADD,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
for _, hdr := range mod.Add {
|
||||
headerMutations = append(headerMutations, &pbproxystate.HeaderMutation{
|
||||
Action: &pbproxystate.HeaderMutation_RequestHeaderAdd{
|
||||
RequestHeaderAdd: &pbproxystate.RequestHeaderAdd{
|
||||
Header: &pbproxystate.Header{
|
||||
Key: hdr.Name,
|
||||
Value: hdr.Value,
|
||||
},
|
||||
AppendAction: pbproxystate.AppendAction_APPEND_ACTION_APPEND_IF_EXISTS_OR_ADD,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(mod.Remove) > 0 {
|
||||
headerMutations = append(headerMutations, &pbproxystate.HeaderMutation{
|
||||
Action: &pbproxystate.HeaderMutation_RequestHeaderRemove{
|
||||
RequestHeaderRemove: &pbproxystate.RequestHeaderRemove{
|
||||
HeaderKeys: mod.Remove,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
case filter.GetResponseHeaderModifier() != nil:
|
||||
mod := filter.GetResponseHeaderModifier()
|
||||
|
||||
for _, hdr := range mod.Set {
|
||||
headerMutations = append(headerMutations, &pbproxystate.HeaderMutation{
|
||||
Action: &pbproxystate.HeaderMutation_ResponseHeaderAdd{
|
||||
ResponseHeaderAdd: &pbproxystate.ResponseHeaderAdd{
|
||||
Header: &pbproxystate.Header{
|
||||
Key: hdr.Name,
|
||||
Value: hdr.Value,
|
||||
},
|
||||
AppendAction: pbproxystate.AppendAction_APPEND_ACTION_OVERWRITE_IF_EXISTS_OR_ADD,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
for _, hdr := range mod.Add {
|
||||
headerMutations = append(headerMutations, &pbproxystate.HeaderMutation{
|
||||
Action: &pbproxystate.HeaderMutation_ResponseHeaderAdd{
|
||||
ResponseHeaderAdd: &pbproxystate.ResponseHeaderAdd{
|
||||
Header: &pbproxystate.Header{
|
||||
Key: hdr.Name,
|
||||
Value: hdr.Value,
|
||||
},
|
||||
AppendAction: pbproxystate.AppendAction_APPEND_ACTION_APPEND_IF_EXISTS_OR_ADD,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(mod.Remove) > 0 {
|
||||
headerMutations = append(headerMutations, &pbproxystate.HeaderMutation{
|
||||
Action: &pbproxystate.HeaderMutation_ResponseHeaderRemove{
|
||||
ResponseHeaderRemove: &pbproxystate.ResponseHeaderRemove{
|
||||
HeaderKeys: mod.Remove,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
case filter.GetUrlRewrite() != nil:
|
||||
prefix := filter.GetUrlRewrite().PathPrefix
|
||||
if prefix != "" {
|
||||
psDestConfig.PrefixRewrite = prefix
|
||||
}
|
||||
}
|
||||
}
|
||||
return headerMutations
|
||||
}
|
||||
|
||||
func applyLoadBalancerPolicy[V interface {
|
||||
GetBackendTarget() string
|
||||
}](
|
||||
psDestConfig *pbproxystate.DestinationConfiguration,
|
||||
cpr *pbmesh.ComputedPortRoutes,
|
||||
backendRefs []V,
|
||||
) {
|
||||
var lb *pbmesh.LoadBalancer
|
||||
|
||||
// If there are multiple targets, just pick the lb policy from
|
||||
// the first one configured.
|
||||
for _, backendRef := range backendRefs {
|
||||
if backendRef.GetBackendTarget() == types.NullRouteBackend {
|
||||
continue
|
||||
}
|
||||
details, ok := cpr.Targets[backendRef.GetBackendTarget()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
thisLB := details.DestinationConfig.LoadBalancer
|
||||
if thisLB != nil {
|
||||
lb = thisLB
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if lb == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, policy := range lb.HashPolicies {
|
||||
if policy.SourceIp {
|
||||
psDestConfig.HashPolicies = append(psDestConfig.HashPolicies, &pbproxystate.LoadBalancerHashPolicy{
|
||||
Policy: &pbproxystate.LoadBalancerHashPolicy_ConnectionProperties{
|
||||
ConnectionProperties: &pbproxystate.ConnectionPropertiesPolicy{
|
||||
SourceIp: true,
|
||||
Terminal: policy.Terminal,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// enumcover:pbmesh.HashPolicyField
|
||||
switch policy.Field {
|
||||
case pbmesh.HashPolicyField_HASH_POLICY_FIELD_HEADER:
|
||||
psDestConfig.HashPolicies = append(psDestConfig.HashPolicies, &pbproxystate.LoadBalancerHashPolicy{
|
||||
Policy: &pbproxystate.LoadBalancerHashPolicy_Header{
|
||||
Header: &pbproxystate.HeaderPolicy{
|
||||
Name: policy.FieldValue,
|
||||
Terminal: policy.Terminal,
|
||||
},
|
||||
},
|
||||
})
|
||||
case pbmesh.HashPolicyField_HASH_POLICY_FIELD_COOKIE:
|
||||
cookie := &pbproxystate.CookiePolicy{
|
||||
Name: policy.FieldValue,
|
||||
Terminal: policy.Terminal,
|
||||
}
|
||||
if policy.CookieConfig != nil {
|
||||
cookie.Path = policy.CookieConfig.Path
|
||||
|
||||
if policy.CookieConfig.Ttl != nil {
|
||||
if policy.CookieConfig.Ttl.AsDuration() != 0 {
|
||||
cookie.Ttl = policy.CookieConfig.Ttl
|
||||
}
|
||||
}
|
||||
|
||||
// Envoy will generate a session cookie if the ttl is present and zero.
|
||||
if policy.CookieConfig.Session {
|
||||
cookie.Ttl = durationpb.New(0 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
psDestConfig.HashPolicies = append(psDestConfig.HashPolicies, &pbproxystate.LoadBalancerHashPolicy{
|
||||
Policy: &pbproxystate.LoadBalancerHashPolicy_Cookie{
|
||||
Cookie: cookie,
|
||||
},
|
||||
})
|
||||
case pbmesh.HashPolicyField_HASH_POLICY_FIELD_QUERY_PARAMETER:
|
||||
psDestConfig.HashPolicies = append(psDestConfig.HashPolicies, &pbproxystate.LoadBalancerHashPolicy{
|
||||
Policy: &pbproxystate.LoadBalancerHashPolicy_QueryParameter{
|
||||
QueryParameter: &pbproxystate.QueryParameterPolicy{
|
||||
Name: policy.FieldValue,
|
||||
Terminal: policy.Terminal,
|
||||
},
|
||||
},
|
||||
})
|
||||
case pbmesh.HashPolicyField_HASH_POLICY_FIELD_UNSPECIFIED:
|
||||
// fallthrough to default
|
||||
default:
|
||||
// not possible from validation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeHTTPRouteMatch(match *pbmesh.HTTPRouteMatch) *pbproxystate.RouteMatch {
|
||||
|
@ -185,48 +379,7 @@ func makeHTTPRouteMatch(match *pbmesh.HTTPRouteMatch) *pbproxystate.RouteMatch {
|
|||
}
|
||||
}
|
||||
|
||||
if len(match.Headers) > 0 {
|
||||
em.HeaderMatches = make([]*pbproxystate.HeaderMatch, 0, len(match.Headers))
|
||||
for _, hdr := range match.Headers {
|
||||
eh := &pbproxystate.HeaderMatch{
|
||||
Name: hdr.Name,
|
||||
}
|
||||
|
||||
// enumcover:pbmesh.HeaderMatchType
|
||||
switch hdr.Type {
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_EXACT:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Exact{
|
||||
Exact: hdr.Value,
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_REGEX:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Regex{
|
||||
Regex: hdr.Value,
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_PREFIX:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Prefix{
|
||||
Prefix: hdr.Value,
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_SUFFIX:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Suffix{
|
||||
Suffix: hdr.Value,
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_PRESENT:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Present{
|
||||
Present: true,
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_UNSPECIFIED:
|
||||
fallthrough // to default
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown header match type: %v", hdr.Type))
|
||||
}
|
||||
|
||||
if hdr.Invert {
|
||||
eh.InvertMatch = true
|
||||
}
|
||||
|
||||
em.HeaderMatches = append(em.HeaderMatches, eh)
|
||||
}
|
||||
}
|
||||
em.HeaderMatches = translateHeaderMatches(match.Headers, (*pbmesh.HTTPHeaderMatch).GetInvert)
|
||||
|
||||
if match.Method != "" {
|
||||
em.MethodMatches = []string{match.Method}
|
||||
|
@ -267,6 +420,122 @@ func makeHTTPRouteMatch(match *pbmesh.HTTPRouteMatch) *pbproxystate.RouteMatch {
|
|||
return em
|
||||
}
|
||||
|
||||
func makeGRPCRouteMatch(match *pbmesh.GRPCRouteMatch) *pbproxystate.RouteMatch {
|
||||
em := &pbproxystate.RouteMatch{}
|
||||
|
||||
if match.Method != nil {
|
||||
mm := match.Method
|
||||
switch mm.Type {
|
||||
case pbmesh.GRPCMethodMatchType_GRPC_METHOD_MATCH_TYPE_EXACT:
|
||||
switch {
|
||||
case mm.Method == "":
|
||||
em.PathMatch = &pbproxystate.PathMatch{
|
||||
PathMatch: &pbproxystate.PathMatch_Prefix{
|
||||
Prefix: fmt.Sprintf("/%s/", mm.Service),
|
||||
},
|
||||
}
|
||||
case mm.Service == "":
|
||||
em.PathMatch = &pbproxystate.PathMatch{
|
||||
PathMatch: &pbproxystate.PathMatch_Regex{
|
||||
Regex: fmt.Sprintf("/[^/]+/%s", mm.Method),
|
||||
},
|
||||
}
|
||||
default:
|
||||
em.PathMatch = &pbproxystate.PathMatch{
|
||||
PathMatch: &pbproxystate.PathMatch_Exact{
|
||||
Exact: fmt.Sprintf("/%s/%s", mm.Service, mm.Method),
|
||||
},
|
||||
}
|
||||
}
|
||||
case pbmesh.GRPCMethodMatchType_GRPC_METHOD_MATCH_TYPE_REGEX:
|
||||
switch {
|
||||
case mm.Method == "":
|
||||
em.PathMatch = &pbproxystate.PathMatch{
|
||||
PathMatch: &pbproxystate.PathMatch_Regex{
|
||||
Regex: fmt.Sprintf("/%s/.+", mm.Service),
|
||||
},
|
||||
}
|
||||
case mm.Service == "":
|
||||
em.PathMatch = &pbproxystate.PathMatch{
|
||||
PathMatch: &pbproxystate.PathMatch_Regex{
|
||||
Regex: fmt.Sprintf("/[^/]+/%s", mm.Method),
|
||||
},
|
||||
}
|
||||
default:
|
||||
em.PathMatch = &pbproxystate.PathMatch{
|
||||
PathMatch: &pbproxystate.PathMatch_Regex{
|
||||
Regex: fmt.Sprintf("/%s/%s", mm.Service, mm.Method),
|
||||
},
|
||||
}
|
||||
}
|
||||
case pbmesh.GRPCMethodMatchType_GRPC_METHOD_MATCH_TYPE_UNSPECIFIED:
|
||||
fallthrough // to default
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown method match type: %v", match.Method.Type))
|
||||
}
|
||||
}
|
||||
|
||||
em.HeaderMatches = translateHeaderMatches(match.Headers, nil)
|
||||
|
||||
return em
|
||||
}
|
||||
|
||||
func translateHeaderMatches[V interface {
|
||||
GetType() pbmesh.HeaderMatchType
|
||||
GetName() string
|
||||
GetValue() string
|
||||
}](
|
||||
headers []V,
|
||||
getInvert func(v V) bool,
|
||||
) []*pbproxystate.HeaderMatch {
|
||||
if len(headers) == 0 {
|
||||
return nil
|
||||
}
|
||||
var out []*pbproxystate.HeaderMatch
|
||||
out = make([]*pbproxystate.HeaderMatch, 0, len(headers))
|
||||
for _, hdr := range headers {
|
||||
eh := &pbproxystate.HeaderMatch{
|
||||
Name: hdr.GetName(),
|
||||
}
|
||||
|
||||
// enumcover:pbmesh.HeaderMatchType
|
||||
switch hdr.GetType() {
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_EXACT:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Exact{
|
||||
Exact: hdr.GetValue(),
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_REGEX:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Regex{
|
||||
Regex: hdr.GetValue(),
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_PREFIX:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Prefix{
|
||||
Prefix: hdr.GetValue(),
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_SUFFIX:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Suffix{
|
||||
Suffix: hdr.GetValue(),
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_PRESENT:
|
||||
eh.Match = &pbproxystate.HeaderMatch_Present{
|
||||
Present: true,
|
||||
}
|
||||
case pbmesh.HeaderMatchType_HEADER_MATCH_TYPE_UNSPECIFIED:
|
||||
fallthrough // to default
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown header match type: %v", hdr.GetType()))
|
||||
}
|
||||
|
||||
// HTTPHeaderMatch only
|
||||
if getInvert != nil && getInvert(hdr) {
|
||||
eh.InvertMatch = true
|
||||
}
|
||||
|
||||
out = append(out, eh)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func translateTimeouts(timeouts *pbmesh.HTTPRouteTimeouts) *pbproxystate.TimeoutConfig {
|
||||
if timeouts == nil || (timeouts.Request == nil && timeouts.Idle == nil) {
|
||||
return nil
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
"altStatName": "http.api-1.default.dc1.internal.foo.consul",
|
||||
"failoverGroup": {
|
||||
"config": {
|
||||
"connectTimeout": "5s",
|
||||
"connectTimeout": "55s",
|
||||
"useAltStatName": true
|
||||
},
|
||||
"endpointGroups": [
|
||||
{
|
||||
"dynamic": {
|
||||
"config": {
|
||||
"connectTimeout": "5s",
|
||||
"connectTimeout": "55s",
|
||||
"disablePanicThreshold": true
|
||||
},
|
||||
"outboundTls": {
|
||||
|
@ -235,6 +235,11 @@
|
|||
"routeRules": [
|
||||
{
|
||||
"destination": {
|
||||
"destinationConfiguration": {
|
||||
"timeoutConfig": {
|
||||
"timeout": "77s"
|
||||
}
|
||||
},
|
||||
"weightedClusters": {
|
||||
"clusters": [
|
||||
{
|
||||
|
@ -252,6 +257,27 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"match": {
|
||||
"pathMatch": {
|
||||
"prefix": "/split"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"destination": {
|
||||
"cluster": {
|
||||
"name": "http.api-1.default.dc1.internal.foo.consul"
|
||||
},
|
||||
"destinationConfiguration": {
|
||||
"retryPolicy": {
|
||||
"numRetries": 4,
|
||||
"retryOn": "connect-failure"
|
||||
},
|
||||
"timeoutConfig": {
|
||||
"timeout": "606s"
|
||||
}
|
||||
}
|
||||
},
|
||||
"match": {
|
||||
"pathMatch": {
|
||||
"prefix": "/"
|
||||
|
|
|
@ -111,6 +111,36 @@ func ValidateComputedRoutes(res *pbresource.Resource) error {
|
|||
))
|
||||
}
|
||||
|
||||
if target.DestinationConfig == nil {
|
||||
merr = multierror.Append(merr, wrapTargetErr(resource.ErrInvalidField{
|
||||
Name: "destination_config",
|
||||
Wrapped: resource.ErrMissing,
|
||||
}))
|
||||
} else {
|
||||
wrapDestConfigErr := func(err error) error {
|
||||
return wrapTargetErr(resource.ErrInvalidField{
|
||||
Name: "destination_config",
|
||||
Wrapped: err,
|
||||
})
|
||||
}
|
||||
|
||||
destConfig := target.DestinationConfig
|
||||
if destConfig.ConnectTimeout == nil {
|
||||
merr = multierror.Append(merr, wrapDestConfigErr(resource.ErrInvalidField{
|
||||
Name: "connect_timeout",
|
||||
Wrapped: resource.ErrMissing,
|
||||
}))
|
||||
} else {
|
||||
connectTimeout := destConfig.ConnectTimeout.AsDuration()
|
||||
if connectTimeout < 0 {
|
||||
merr = multierror.Append(merr, wrapDestConfigErr(resource.ErrInvalidField{
|
||||
Name: "connect_timeout",
|
||||
Wrapped: errTimeoutCannotBeNegative(connectTimeout),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if target.MeshPort == "" {
|
||||
merr = multierror.Append(merr, wrapTargetErr(resource.ErrInvalidField{
|
||||
Name: "mesh_port",
|
||||
|
|
|
@ -5,8 +5,10 @@ package types
|
|||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
"github.com/hashicorp/consul/internal/resource/resourcetest"
|
||||
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
|
||||
|
@ -197,6 +199,9 @@ func TestValidateComputedRoutes(t *testing.T) {
|
|||
"foo": {
|
||||
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
|
||||
MeshPort: "mesh",
|
||||
DestinationConfig: &pbmesh.DestinationConfig{
|
||||
ConnectTimeout: durationpb.New(5 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -249,6 +249,10 @@ func ValidateHTTPRoute(res *pbresource.Resource) error {
|
|||
}
|
||||
}
|
||||
|
||||
var (
|
||||
hasReqMod bool
|
||||
hasUrlRewrite bool
|
||||
)
|
||||
for j, filter := range rule.Filters {
|
||||
wrapFilterErr := func(err error) error {
|
||||
return wrapRuleErr(resource.ErrInvalidListElement{
|
||||
|
@ -260,12 +264,14 @@ func ValidateHTTPRoute(res *pbresource.Resource) error {
|
|||
set := 0
|
||||
if filter.RequestHeaderModifier != nil {
|
||||
set++
|
||||
hasReqMod = true
|
||||
}
|
||||
if filter.ResponseHeaderModifier != nil {
|
||||
set++
|
||||
}
|
||||
if filter.UrlRewrite != nil {
|
||||
set++
|
||||
hasUrlRewrite = true
|
||||
if filter.UrlRewrite.PathPrefix == "" {
|
||||
merr = multierror.Append(merr, wrapFilterErr(
|
||||
resource.ErrInvalidField{
|
||||
|
@ -285,6 +291,12 @@ func ValidateHTTPRoute(res *pbresource.Resource) error {
|
|||
}
|
||||
}
|
||||
|
||||
if hasReqMod && hasUrlRewrite {
|
||||
merr = multierror.Append(merr, wrapRuleErr(
|
||||
errors.New("exactly one of request_header_modifier or url_rewrite can be set at a time"),
|
||||
))
|
||||
}
|
||||
|
||||
if len(rule.BackendRefs) == 0 {
|
||||
merr = multierror.Append(merr, wrapRuleErr(
|
||||
resource.ErrInvalidField{
|
||||
|
|
|
@ -733,6 +733,29 @@ func TestValidateHTTPRoute(t *testing.T) {
|
|||
},
|
||||
expectErr: `invalid element at index 0 of list "rules": invalid element at index 0 of list "filters": exactly one of request_header_modifier, response_header_modifier, or url_rewrite`,
|
||||
},
|
||||
"filter req+rewrite on two rules is not allowed": {
|
||||
route: &pbmesh.HTTPRoute{
|
||||
ParentRefs: []*pbmesh.ParentReference{
|
||||
newParentRef(catalog.ServiceType, "web", ""),
|
||||
},
|
||||
Rules: []*pbmesh.HTTPRouteRule{{
|
||||
Filters: []*pbmesh.HTTPRouteFilter{
|
||||
{
|
||||
RequestHeaderModifier: &pbmesh.HTTPHeaderFilter{},
|
||||
},
|
||||
{
|
||||
UrlRewrite: &pbmesh.HTTPURLRewriteFilter{
|
||||
PathPrefix: "/blah",
|
||||
},
|
||||
},
|
||||
},
|
||||
BackendRefs: []*pbmesh.HTTPBackendRef{{
|
||||
BackendRef: newBackendRef(catalog.ServiceType, "api", ""),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
expectErr: `invalid element at index 0 of list "rules": exactly one of request_header_modifier or url_rewrite can be set at a time`,
|
||||
},
|
||||
"filter req+resp+rewrite header mod is bad": {
|
||||
route: &pbmesh.HTTPRoute{
|
||||
ParentRefs: []*pbmesh.ParentReference{
|
||||
|
@ -1081,12 +1104,6 @@ func getXRouteTimeoutsTestCases() map[string]xRouteTimeoutsTestcase {
|
|||
},
|
||||
expectErr: `invalid element at index 0 of list "rules": invalid "timeouts" field: invalid "request" field: timeout cannot be negative: -1s`,
|
||||
},
|
||||
"bad backend request": {
|
||||
timeouts: &pbmesh.HTTPRouteTimeouts{
|
||||
BackendRequest: durationpb.New(-1 * time.Second),
|
||||
},
|
||||
expectErr: `invalid element at index 0 of list "rules": invalid "timeouts" field: invalid "backend_request" field: timeout cannot be negative: -1s`,
|
||||
},
|
||||
"bad idle": {
|
||||
timeouts: &pbmesh.HTTPRouteTimeouts{
|
||||
Idle: durationpb.New(-1 * time.Second),
|
||||
|
@ -1096,7 +1113,6 @@ func getXRouteTimeoutsTestCases() map[string]xRouteTimeoutsTestcase {
|
|||
"good all": {
|
||||
timeouts: &pbmesh.HTTPRouteTimeouts{
|
||||
Request: durationpb.New(1 * time.Second),
|
||||
BackendRequest: durationpb.New(2 * time.Second),
|
||||
Idle: durationpb.New(3 * time.Second),
|
||||
},
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ package types
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
@ -206,6 +207,10 @@ func validateHeaderMatchType(typ pbmesh.HeaderMatchType) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func errTimeoutCannotBeNegative(d time.Duration) error {
|
||||
return fmt.Errorf("timeout cannot be negative: %v", d)
|
||||
}
|
||||
|
||||
func validateHTTPTimeouts(timeouts *pbmesh.HTTPRouteTimeouts) []error {
|
||||
if timeouts == nil {
|
||||
return nil
|
||||
|
@ -218,16 +223,7 @@ func validateHTTPTimeouts(timeouts *pbmesh.HTTPRouteTimeouts) []error {
|
|||
if val < 0 {
|
||||
errs = append(errs, resource.ErrInvalidField{
|
||||
Name: "request",
|
||||
Wrapped: fmt.Errorf("timeout cannot be negative: %v", val),
|
||||
})
|
||||
}
|
||||
}
|
||||
if timeouts.BackendRequest != nil {
|
||||
val := timeouts.BackendRequest.AsDuration()
|
||||
if val < 0 {
|
||||
errs = append(errs, resource.ErrInvalidField{
|
||||
Name: "backend_request",
|
||||
Wrapped: fmt.Errorf("timeout cannot be negative: %v", val),
|
||||
Wrapped: errTimeoutCannotBeNegative(val),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +232,7 @@ func validateHTTPTimeouts(timeouts *pbmesh.HTTPRouteTimeouts) []error {
|
|||
if val < 0 {
|
||||
errs = append(errs, resource.ErrInvalidField{
|
||||
Name: "idle",
|
||||
Wrapped: fmt.Errorf("timeout cannot be negative: %v", val),
|
||||
Wrapped: errTimeoutCannotBeNegative(val),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package protoutil
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func Clone[T proto.Message](v T) T {
|
||||
return proto.Clone(v).(T)
|
||||
}
|
||||
|
||||
func CloneSlice[T proto.Message](in []T) []T {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := make([]T, 0, len(in))
|
||||
for _, v := range in {
|
||||
out = append(out, Clone[T](v))
|
||||
}
|
||||
return out
|
||||
}
|
|
@ -24,39 +24,18 @@ const (
|
|||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// HTTPRouteTimeouts defines timeouts that can be configured for an HTTPRoute.
|
||||
// Timeout values are formatted like 1h/1m/1s/1ms as parsed by Golang time.ParseDuration
|
||||
// and MUST BE >= 1ms.
|
||||
//
|
||||
// ALTERNATIVE: not using policy attachment semantics
|
||||
// HTTPRouteTimeouts defines timeouts that can be configured for an HTTPRoute
|
||||
// or GRPCRoute.
|
||||
type HTTPRouteTimeouts struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Request specifies the duration for processing an HTTP client request after which the
|
||||
// gateway will time out if unable to send a response.
|
||||
// Whether the gateway starts the timeout before or after the entire client request stream
|
||||
// has been received, is implementation-dependent.
|
||||
//
|
||||
// For example, setting the `rules.timeouts.request` field to the value `10s` in an
|
||||
// `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds
|
||||
// to complete.
|
||||
//
|
||||
// When this field is unspecified, request timeout behavior is implementation-dependent.
|
||||
// RequestTimeout is the total amount of time permitted for the entire
|
||||
// downstream request (and retries) to be processed.
|
||||
Request *durationpb.Duration `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"`
|
||||
// BackendRequest specifies a timeout for an individual request from the gateway
|
||||
// to a backend service. Typically used in conjuction with retry configuration,
|
||||
// if supported by an implementation.
|
||||
//
|
||||
// The value of BackendRequest defaults to and must be <= the value of Request timeout.
|
||||
//
|
||||
// Support: Extended
|
||||
//
|
||||
// TODO(rb): net-new feature
|
||||
BackendRequest *durationpb.Duration `protobuf:"bytes,2,opt,name=backend_request,json=backendRequest,proto3" json:"backend_request,omitempty"`
|
||||
// TODO(RB): this is a consul-only feature
|
||||
Idle *durationpb.Duration `protobuf:"bytes,3,opt,name=idle,proto3" json:"idle,omitempty"`
|
||||
// Idle specifies the total amount of time permitted for the request stream to be idle.
|
||||
Idle *durationpb.Duration `protobuf:"bytes,2,opt,name=idle,proto3" json:"idle,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HTTPRouteTimeouts) Reset() {
|
||||
|
@ -98,13 +77,6 @@ func (x *HTTPRouteTimeouts) GetRequest() *durationpb.Duration {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (x *HTTPRouteTimeouts) GetBackendRequest() *durationpb.Duration {
|
||||
if x != nil {
|
||||
return x.BackendRequest
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *HTTPRouteTimeouts) GetIdle() *durationpb.Duration {
|
||||
if x != nil {
|
||||
return x.Idle
|
||||
|
@ -121,37 +93,33 @@ var file_pbmesh_v2beta1_http_route_timeouts_proto_rawDesc = []byte{
|
|||
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73,
|
||||
0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbb, 0x01, 0x0a, 0x11, 0x48, 0x54,
|
||||
0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x12,
|
||||
0x33, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f,
|
||||
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e,
|
||||
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x04, 0x69, 0x64, 0x6c, 0x65,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x52, 0x04, 0x69, 0x64, 0x6c, 0x65, 0x42, 0x97, 0x02, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
|
||||
0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x16, 0x48,
|
||||
0x74, 0x74, 0x70, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73,
|
||||
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31,
|
||||
0x3b, 0x6d, 0x65, 0x73, 0x68, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48,
|
||||
0x43, 0x4d, 0xaa, 0x02, 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43,
|
||||
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x2e, 0x56, 0x32, 0x62, 0x65, 0x74,
|
||||
0x61, 0x31, 0xca, 0x02, 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43,
|
||||
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74,
|
||||
0x61, 0x31, 0xe2, 0x02, 0x29, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43,
|
||||
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74,
|
||||
0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
|
||||
0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73,
|
||||
0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61,
|
||||
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x77, 0x0a, 0x11, 0x48, 0x54, 0x54,
|
||||
0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x12, 0x33,
|
||||
0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x04, 0x69, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x64,
|
||||
0x6c, 0x65, 0x42, 0x97, 0x02, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
|
||||
0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68,
|
||||
0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x16, 0x48, 0x74, 0x74, 0x70, 0x52, 0x6f,
|
||||
0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68,
|
||||
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d,
|
||||
0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, 0x68,
|
||||
0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, 0x1d,
|
||||
0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
|
||||
0x2e, 0x4d, 0x65, 0x73, 0x68, 0x2e, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1d,
|
||||
0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
|
||||
0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x29,
|
||||
0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
|
||||
0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50,
|
||||
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x20, 0x48, 0x61, 0x73, 0x68,
|
||||
0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d,
|
||||
0x65, 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -173,13 +141,12 @@ var file_pbmesh_v2beta1_http_route_timeouts_proto_goTypes = []interface{}{
|
|||
}
|
||||
var file_pbmesh_v2beta1_http_route_timeouts_proto_depIdxs = []int32{
|
||||
1, // 0: hashicorp.consul.mesh.v2beta1.HTTPRouteTimeouts.request:type_name -> google.protobuf.Duration
|
||||
1, // 1: hashicorp.consul.mesh.v2beta1.HTTPRouteTimeouts.backend_request:type_name -> google.protobuf.Duration
|
||||
1, // 2: hashicorp.consul.mesh.v2beta1.HTTPRouteTimeouts.idle:type_name -> google.protobuf.Duration
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
1, // 1: hashicorp.consul.mesh.v2beta1.HTTPRouteTimeouts.idle:type_name -> google.protobuf.Duration
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pbmesh_v2beta1_http_route_timeouts_proto_init() }
|
||||
|
|
|
@ -7,35 +7,13 @@ package hashicorp.consul.mesh.v2beta1;
|
|||
|
||||
import "google/protobuf/duration.proto";
|
||||
|
||||
// HTTPRouteTimeouts defines timeouts that can be configured for an HTTPRoute.
|
||||
// Timeout values are formatted like 1h/1m/1s/1ms as parsed by Golang time.ParseDuration
|
||||
// and MUST BE >= 1ms.
|
||||
//
|
||||
// ALTERNATIVE: not using policy attachment semantics
|
||||
// HTTPRouteTimeouts defines timeouts that can be configured for an HTTPRoute
|
||||
// or GRPCRoute.
|
||||
message HTTPRouteTimeouts {
|
||||
// Request specifies the duration for processing an HTTP client request after which the
|
||||
// gateway will time out if unable to send a response.
|
||||
// Whether the gateway starts the timeout before or after the entire client request stream
|
||||
// has been received, is implementation-dependent.
|
||||
//
|
||||
// For example, setting the `rules.timeouts.request` field to the value `10s` in an
|
||||
// `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds
|
||||
// to complete.
|
||||
//
|
||||
// When this field is unspecified, request timeout behavior is implementation-dependent.
|
||||
// RequestTimeout is the total amount of time permitted for the entire
|
||||
// downstream request (and retries) to be processed.
|
||||
google.protobuf.Duration request = 1;
|
||||
|
||||
// BackendRequest specifies a timeout for an individual request from the gateway
|
||||
// to a backend service. Typically used in conjuction with retry configuration,
|
||||
// if supported by an implementation.
|
||||
//
|
||||
// The value of BackendRequest defaults to and must be <= the value of Request timeout.
|
||||
//
|
||||
// Support: Extended
|
||||
//
|
||||
// TODO(rb): net-new feature
|
||||
google.protobuf.Duration backend_request = 2;
|
||||
|
||||
// TODO(RB): this is a consul-only feature
|
||||
google.protobuf.Duration idle = 3;
|
||||
// Idle specifies the total amount of time permitted for the request stream to be idle.
|
||||
google.protobuf.Duration idle = 2;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue