Skip to content

Commit

Permalink
mesh: compute more of the xRoute features into ComputedRoutes (#18980)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rboyer authored Sep 22, 2023
1 parent d3bb5ff commit 9e48607
Show file tree
Hide file tree
Showing 16 changed files with 880 additions and 335 deletions.
171 changes: 97 additions & 74 deletions internal/mesh/internal/controllers/routes/controller_test.go

Large diffs are not rendered by default.

92 changes: 92 additions & 0 deletions internal/mesh/internal/controllers/routes/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
114 changes: 65 additions & 49 deletions internal/mesh/internal/controllers/routes/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_TCP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("api", "tcp"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "tcp", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "tcp", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -282,9 +283,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: protocol,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("api", protoName): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, protoName, ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, protoName, ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -334,9 +336,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_GRPC,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("api", "grpc"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "grpc", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "grpc", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -443,9 +446,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_TCP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "tcp"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "tcp", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand All @@ -472,9 +476,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand All @@ -501,9 +506,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP2,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "http2"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http2", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand All @@ -530,9 +536,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_GRPC,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "grpc"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "grpc", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -612,9 +619,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: protocol,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", portName): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, portName, ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, portName, ""),
DestinationConfig: defaultDestConfig(),
},
},
}
Expand Down Expand Up @@ -721,9 +729,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("api", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "http", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -803,9 +812,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("api", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "http", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(apiServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -910,9 +920,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -1062,14 +1073,16 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
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", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(barServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -1155,9 +1168,10 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down Expand Up @@ -1648,15 +1662,17 @@ func TestGenerateComputedRoutes(t *testing.T) {
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
Targets: map[string]*pbmesh.BackendTargetDetails{
backendName("foo", "http"): {
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(fooServiceRef, "http", ""),
FailoverConfig: portFailoverConfig,
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT,
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", ""),
Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_INDIRECT,
MeshPort: "mesh",
BackendRef: newBackendRef(barServiceRef, "http", ""),
DestinationConfig: defaultDestConfig(),
},
},
},
Expand Down
15 changes: 6 additions & 9 deletions internal/mesh/internal/controllers/routes/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Loading

0 comments on commit 9e48607

Please sign in to comment.