agent/xds: Update mesh gateway to use service router timeout (#7444)

* website/connect/proxy/envoy: specify timeout precedence for services behind mesh gateway
pull/7464/head
Kim Ngo 2020-03-17 14:50:14 -05:00 committed by GitHub
parent 5c7b3762e3
commit bef693df9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 7 deletions

View File

@ -159,20 +159,28 @@ func (s *Server) clustersFromSnapshotMeshGateway(cfgSnap *proxycfg.ConfigSnapsho
// generate the per-service clusters // generate the per-service clusters
for svc, _ := range cfgSnap.MeshGateway.ServiceGroups { for svc, _ := range cfgSnap.MeshGateway.ServiceGroups {
clusterName := connect.ServiceSNI(svc.ID, "", svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName := connect.ServiceSNI(svc.ID, "", svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
resolver, hasResolver := cfgSnap.MeshGateway.ServiceResolvers[svc]
cluster, err := s.makeMeshGatewayCluster(clusterName, cfgSnap) // Create the cluster for default/unnamed services
var cluster *envoy.Cluster
var err error
if hasResolver {
cluster, err = s.makeMeshGatewayClusterWithConnectTimeout(clusterName, cfgSnap, resolver.ConnectTimeout)
} else {
cluster, err = s.makeMeshGatewayCluster(clusterName, cfgSnap)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
clusters = append(clusters, cluster) clusters = append(clusters, cluster)
// if there is a service-resolver for this service then also setup subset clusters for it // if there is a service-resolver for this service then also setup subset clusters for it
if resolver, ok := cfgSnap.MeshGateway.ServiceResolvers[svc]; ok { if hasResolver {
// generate 1 cluster for each service subset // generate 1 cluster for each service subset
for subsetName, _ := range resolver.Subsets { for subsetName := range resolver.Subsets {
clusterName := connect.ServiceSNI(svc.ID, subsetName, svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain) clusterName := connect.ServiceSNI(svc.ID, subsetName, svc.NamespaceOrDefault(), cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain)
cluster, err := s.makeMeshGatewayCluster(clusterName, cfgSnap) cluster, err := s.makeMeshGatewayClusterWithConnectTimeout(clusterName, cfgSnap, resolver.ConnectTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -464,6 +472,14 @@ func makeClusterFromUserConfig(configJSON string) (*envoy.Cluster, error) {
} }
func (s *Server) makeMeshGatewayCluster(clusterName string, cfgSnap *proxycfg.ConfigSnapshot) (*envoy.Cluster, error) { func (s *Server) makeMeshGatewayCluster(clusterName string, cfgSnap *proxycfg.ConfigSnapshot) (*envoy.Cluster, error) {
return s.makeMeshGatewayClusterWithConnectTimeout(clusterName, cfgSnap, 0)
}
// makeMeshGatewayClusterWithConnectTimeout initializes a mesh gateway cluster
// with the specified connect timeout. If the timeout is 0, the connect timeout
// defaults to use the mesh gateway timeout.
func (s *Server) makeMeshGatewayClusterWithConnectTimeout(clusterName string, cfgSnap *proxycfg.ConfigSnapshot,
connectTimeout time.Duration) (*envoy.Cluster, error) {
cfg, err := ParseMeshGatewayConfig(cfgSnap.Proxy.Config) cfg, err := ParseMeshGatewayConfig(cfgSnap.Proxy.Config)
if err != nil { if err != nil {
// Don't hard fail on a config typo, just warn. The parse func returns // Don't hard fail on a config typo, just warn. The parse func returns
@ -471,9 +487,13 @@ func (s *Server) makeMeshGatewayCluster(clusterName string, cfgSnap *proxycfg.Co
s.Logger.Warn("failed to parse mesh gateway config", "error", err) s.Logger.Warn("failed to parse mesh gateway config", "error", err)
} }
if connectTimeout <= 0 {
connectTimeout = time.Duration(cfg.ConnectTimeoutMs) * time.Millisecond
}
return &envoy.Cluster{ return &envoy.Cluster{
Name: clusterName, Name: clusterName,
ConnectTimeout: time.Duration(cfg.ConnectTimeoutMs) * time.Millisecond, ConnectTimeout: connectTimeout,
ClusterDiscoveryType: &envoy.Cluster_Type{Type: envoy.Cluster_EDS}, ClusterDiscoveryType: &envoy.Cluster_Type{Type: envoy.Cluster_EDS},
EdsClusterConfig: &envoy.Cluster_EdsClusterConfig{ EdsClusterConfig: &envoy.Cluster_EdsClusterConfig{
EdsConfig: &envoycore.ConfigSource{ EdsConfig: &envoycore.ConfigSource{

View File

@ -6,6 +6,7 @@ import (
"sort" "sort"
"testing" "testing"
"text/template" "text/template"
"time"
envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2" envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
@ -316,6 +317,28 @@ func TestClustersFromSnapshot(t *testing.T) {
} }
}, },
}, },
{
name: "mesh-gateway-service-timeouts",
create: proxycfg.TestConfigSnapshotMeshGateway,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.MeshGateway.ServiceResolvers = map[structs.ServiceID]*structs.ServiceResolverConfigEntry{
structs.NewServiceID("bar", nil): &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "bar",
ConnectTimeout: 10 * time.Second,
Subsets: map[string]structs.ServiceResolverSubset{
"v1": structs.ServiceResolverSubset{
Filter: "Service.Meta.Version == 1",
},
"v2": structs.ServiceResolverSubset{
Filter: "Service.Meta.Version == 2",
OnlyPassing: true,
},
},
},
}
},
},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@ -0,0 +1,87 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.api.v2.Cluster",
"name": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {
}
}
},
"connectTimeout": "10s",
"outlierDetection": {
}
},
{
"@type": "type.googleapis.com/envoy.api.v2.Cluster",
"name": "dc2.internal.11111111-2222-3333-4444-555555555555.consul",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {
}
}
},
"connectTimeout": "5s",
"outlierDetection": {
}
},
{
"@type": "type.googleapis.com/envoy.api.v2.Cluster",
"name": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {
}
}
},
"connectTimeout": "5s",
"outlierDetection": {
}
},
{
"@type": "type.googleapis.com/envoy.api.v2.Cluster",
"name": "v1.bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {
}
}
},
"connectTimeout": "10s",
"outlierDetection": {
}
},
{
"@type": "type.googleapis.com/envoy.api.v2.Cluster",
"name": "v2.bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {
}
}
},
"connectTimeout": "10s",
"outlierDetection": {
}
}
],
"typeUrl": "type.googleapis.com/envoy.api.v2.Cluster",
"nonce": "00000001"
}

View File

@ -288,8 +288,11 @@ entry](/docs/agent/config_entries.html#proxy-defaults-proxy-defaults) to act as
defaults that are inherited by all services. defaults that are inherited by all services.
- `connect_timeout_ms` - The number of milliseconds to allow when making upstream - `connect_timeout_ms` - The number of milliseconds to allow when making upstream
connections before timing out. Defaults to 5000 connections before timing out. Defaults to 5000 (5 seconds). If the upstream
(5 seconds). service has the configuration option
[`connect_timeout_ms`](/docs/agent/config-entries/service-resolver.html#connecttimeout)
set for the `service-resolver`, that timeout value will take precedence over
this mesh gateway option.
- `envoy_mesh_gateway_bind_tagged_addresses` - Indicates that the mesh gateway - `envoy_mesh_gateway_bind_tagged_addresses` - Indicates that the mesh gateway
services tagged addresses should be bound to listeners in addition to the services tagged addresses should be bound to listeners in addition to the