diff --git a/agent/xds/clusters.go b/agent/xds/clusters.go index 38479f1979be..b1abf633bfa6 100644 --- a/agent/xds/clusters.go +++ b/agent/xds/clusters.go @@ -234,6 +234,9 @@ func (s *Server) makeUpstreamClusterForPreparedQuery(upstream structs.Upstream, }, }, }, + CircuitBreakers: &envoycluster.CircuitBreakers{ + Thresholds: makeThresholdsIfNeeded(cfg.Limits), + }, // Having an empty config enables outlier detection with default config. OutlierDetection: &envoycluster.OutlierDetection{}, } @@ -339,6 +342,9 @@ func (s *Server) makeUpstreamClustersForDiscoveryChain( }, }, }, + CircuitBreakers: &envoycluster.CircuitBreakers{ + Thresholds: makeThresholdsIfNeeded(cfg.Limits), + }, // Having an empty config enables outlier detection with default config. OutlierDetection: &envoycluster.OutlierDetection{}, } @@ -449,3 +455,27 @@ func (s *Server) makeMeshGatewayCluster(clusterName string, cfgSnap *proxycfg.Co OutlierDetection: &envoycluster.OutlierDetection{}, }, nil } + +func makeThresholdsIfNeeded(limits UpstreamLimits) []*envoycluster.CircuitBreakers_Thresholds { + var empty UpstreamLimits + // Make sure to not create any thresholds when passed the zero-value in order + // to rely on Envoy defaults + if limits == empty { + return nil + } + + threshold := &envoycluster.CircuitBreakers_Thresholds{} + // Likewise, make sure to not set any threshold values on the zero-value in + // order to rely on Envoy defaults + if limits.MaxConnections != nil { + threshold.MaxConnections = makeUint32Value(*limits.MaxConnections) + } + if limits.MaxPendingRequests != nil { + threshold.MaxPendingRequests = makeUint32Value(*limits.MaxPendingRequests) + } + if limits.MaxConcurrentRequests != nil { + threshold.MaxRequests = makeUint32Value(*limits.MaxConcurrentRequests) + } + + return []*envoycluster.CircuitBreakers_Thresholds{threshold} +} diff --git a/agent/xds/clusters_test.go b/agent/xds/clusters_test.go index 62f9a8037335..11dc7ebe2f62 100644 --- a/agent/xds/clusters_test.go +++ b/agent/xds/clusters_test.go @@ -111,6 +111,59 @@ func TestClustersFromSnapshot(t *testing.T) { snap.Proxy.Upstreams[0].Config["connect_timeout_ms"] = 2345 }, }, + { + name: "custom-limits-max-connections-only", + create: proxycfg.TestConfigSnapshot, + setup: func(snap *proxycfg.ConfigSnapshot) { + for i := range snap.Proxy.Upstreams { + // We check if Config is nil because the prepared_query upstream is + // initialized without a Config map. Use Upstreams[i] syntax to + // modify the actual ConfigSnapshot instead of copying the Upstream + // in the range. + if snap.Proxy.Upstreams[i].Config == nil { + snap.Proxy.Upstreams[i].Config = map[string]interface{}{} + } + + snap.Proxy.Upstreams[i].Config["limits"] = map[string]interface{}{ + "max_connections": 500, + } + } + }, + }, + { + name: "custom-limits-set-to-zero", + create: proxycfg.TestConfigSnapshot, + setup: func(snap *proxycfg.ConfigSnapshot) { + for i := range snap.Proxy.Upstreams { + if snap.Proxy.Upstreams[i].Config == nil { + snap.Proxy.Upstreams[i].Config = map[string]interface{}{} + } + + snap.Proxy.Upstreams[i].Config["limits"] = map[string]interface{}{ + "max_connections": 0, + "max_pending_requests": 0, + "max_concurrent_requests": 0, + } + } + }, + }, + { + name: "custom-limits", + create: proxycfg.TestConfigSnapshot, + setup: func(snap *proxycfg.ConfigSnapshot) { + for i := range snap.Proxy.Upstreams { + if snap.Proxy.Upstreams[i].Config == nil { + snap.Proxy.Upstreams[i].Config = map[string]interface{}{} + } + + snap.Proxy.Upstreams[i].Config["limits"] = map[string]interface{}{ + "max_connections": 500, + "max_pending_requests": 600, + "max_concurrent_requests": 700, + } + } + }, + }, { name: "connect-proxy-with-chain", create: proxycfg.TestConfigSnapshotDiscoveryChain, @@ -312,6 +365,9 @@ func expectClustersJSONResources(t *testing.T, snap *proxycfg.ConfigSnapshot, to }, "outlierDetection": { + }, + "circuitBreakers": { + }, "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", "commonLbConfig": { @@ -334,6 +390,9 @@ func expectClustersJSONResources(t *testing.T, snap *proxycfg.ConfigSnapshot, to }, "outlierDetection": { + }, + "circuitBreakers": { + }, "connectTimeout": "5s", "tlsContext": ` + expectedUpstreamTLSContextJSON(t, snap, "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul") + ` diff --git a/agent/xds/config.go b/agent/xds/config.go index b3df755cd6cd..146e561b1f4d 100644 --- a/agent/xds/config.go +++ b/agent/xds/config.go @@ -104,6 +104,25 @@ func ParseMeshGatewayConfig(m map[string]interface{}) (MeshGatewayConfig, error) return cfg, err } +// UpstreamLimits describes the limits that are associated with a specific +// upstream of a service instance. +type UpstreamLimits struct { + // MaxConnections is the maximum number of connections the local proxy can + // make to the upstream service. + MaxConnections *int `mapstructure:"max_connections"` + + // MaxPendingRequests is the maximum number of requests that will be queued + // waiting for an available connection. This is mostly applicable to HTTP/1.1 + // clusters since all HTTP/2 requests are streamed over a single + // connection. + MaxPendingRequests *int `mapstructure:"max_pending_requests"` + + // MaxConcurrentRequests is the maximum number of in-flight requests that will be allowed + // to the upstream cluster at a point in time. This is mostly applicable to HTTP/2 + // clusters since all HTTP/1.1 requests are limited by MaxConnections. + MaxConcurrentRequests *int `mapstructure:"max_concurrent_requests"` +} + // UpstreamConfig describes the keys we understand from // Connect.Proxy.Upstream[*].Config. type UpstreamConfig struct { @@ -131,6 +150,10 @@ type UpstreamConfig struct { // ConnectTimeoutMs is the number of milliseconds to timeout making a new // connection to this upstream. Defaults to 5000 (5 seconds) if not set. ConnectTimeoutMs int `mapstructure:"connect_timeout_ms"` + + // Limits are the set of limits that are applied to the proxy for a specific upstream of a + // service instance. + Limits UpstreamLimits `mapstructure:"limits"` } func ParseUpstreamConfigNoDefaults(m map[string]interface{}) (UpstreamConfig, error) { diff --git a/agent/xds/config_test.go b/agent/xds/config_test.go index 9df5202b9d5a..ddb3b08cbce3 100644 --- a/agent/xds/config_test.go +++ b/agent/xds/config_test.go @@ -205,6 +205,44 @@ func TestParseUpstreamConfig(t *testing.T) { Protocol: "tcp", }, }, + { + name: "connect limits map", + input: map[string]interface{}{ + "limits": map[string]interface{}{ + "max_connections": 50, + "max_pending_requests": 60, + "max_concurrent_requests": 70, + }, + }, + want: UpstreamConfig{ + ConnectTimeoutMs: 5000, + Protocol: "tcp", + Limits: UpstreamLimits{ + MaxConnections: intPointer(50), + MaxPendingRequests: intPointer(60), + MaxConcurrentRequests: intPointer(70), + }, + }, + }, + { + name: "connect limits map zero", + input: map[string]interface{}{ + "limits": map[string]interface{}{ + "max_connections": 0, + "max_pending_requests": 0, + "max_concurrent_requests": 0, + }, + }, + want: UpstreamConfig{ + ConnectTimeoutMs: 5000, + Protocol: "tcp", + Limits: UpstreamLimits{ + MaxConnections: intPointer(0), + MaxPendingRequests: intPointer(0), + MaxConcurrentRequests: intPointer(0), + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -214,3 +252,7 @@ func TestParseUpstreamConfig(t *testing.T) { }) } } + +func intPointer(i int) *int { + return &i +} diff --git a/agent/xds/testdata/clusters/connect-proxy-with-chain-and-failover.golden b/agent/xds/testdata/clusters/connect-proxy-with-chain-and-failover.golden index 316e7780ff0c..f806b01162d3 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-chain-and-failover.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-chain-and-failover.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden b/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden index c97b21eecec4..3e5bf3b4a0df 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-chain-and-overrides.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "66s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -61,6 +64,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-chain-external-sni.golden b/agent/xds/testdata/clusters/connect-proxy-with-chain-external-sni.golden index 28f0f1fc2b78..8a08ba5c93ee 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-chain-external-sni.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-chain-external-sni.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-chain.golden b/agent/xds/testdata/clusters/connect-proxy-with-chain.golden index 316e7780ff0c..f806b01162d3 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-chain.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-chain.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden index aacd258621c8..2951a3865450 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden index 316e7780ff0c..f806b01162d3 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-local-gateway.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden index aacd258621c8..2951a3865450 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden index 316e7780ff0c..f806b01162d3 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-double-failover-through-remote-gateway.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden index 29d573108f5d..e41110b28cb7 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden index 316e7780ff0c..f806b01162d3 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-local-gateway.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden index 29d573108f5d..e41110b28cb7 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden index 316e7780ff0c..f806b01162d3 100644 --- a/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden +++ b/agent/xds/testdata/clusters/connect-proxy-with-tcp-chain-failover-through-remote-gateway.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "33s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/custom-limits-max-connections-only.golden b/agent/xds/testdata/clusters/custom-limits-max-connections-only.golden new file mode 100644 index 000000000000..6645aea54ea6 --- /dev/null +++ b/agent/xds/testdata/clusters/custom-limits-max-connections-only.golden @@ -0,0 +1,130 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + "thresholds": [ + { + "maxConnections": 500 + } + ] + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + "thresholds": [ + { + "maxConnections": 500 + } + ] + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/custom-limits-set-to-zero.golden b/agent/xds/testdata/clusters/custom-limits-set-to-zero.golden new file mode 100644 index 000000000000..06d8e813f237 --- /dev/null +++ b/agent/xds/testdata/clusters/custom-limits-set-to-zero.golden @@ -0,0 +1,134 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + "thresholds": [ + { + "maxConnections": 0, + "maxPendingRequests": 0, + "maxRequests": 0 + } + ] + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + "thresholds": [ + { + "maxConnections": 0, + "maxPendingRequests": 0, + "maxRequests": 0 + } + ] + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/custom-limits.golden b/agent/xds/testdata/clusters/custom-limits.golden new file mode 100644 index 000000000000..0fc85c46a03f --- /dev/null +++ b/agent/xds/testdata/clusters/custom-limits.golden @@ -0,0 +1,134 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + "thresholds": [ + { + "maxConnections": 500, + "maxPendingRequests": 600, + "maxRequests": 700 + } + ] + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + }, + "commonLbConfig": { + "healthyPanicThreshold": { + + } + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + } + }, + "connectTimeout": "5s", + "circuitBreakers": { + "thresholds": [ + { + "maxConnections": 500, + "maxPendingRequests": 600, + "maxRequests": 700 + } + ] + }, + "tlsContext": { + "commonTlsContext": { + "tlsParams": { + + }, + "tlsCertificates": [ + { + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + }, + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + } + } + ], + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + } + } + }, + "sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + }, + "outlierDetection": { + + } + }, + { + "@type": "type.googleapis.com/envoy.api.v2.Cluster", + "name": "local_app", + "type": "STATIC", + "connectTimeout": "5s", + "loadAssignment": { + "clusterName": "local_app", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 8080 + } + } + } + } + ] + } + ] + } + } + ], + "typeUrl": "type.googleapis.com/envoy.api.v2.Cluster", + "nonce": "00000001" +} \ No newline at end of file diff --git a/agent/xds/testdata/clusters/custom-local-app.golden b/agent/xds/testdata/clusters/custom-local-app.golden index 5f6c6fabc33a..0aff744581ea 100644 --- a/agent/xds/testdata/clusters/custom-local-app.golden +++ b/agent/xds/testdata/clusters/custom-local-app.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/custom-timeouts.golden b/agent/xds/testdata/clusters/custom-timeouts.golden index 9bfc84a9c107..f181d7525f62 100644 --- a/agent/xds/testdata/clusters/custom-timeouts.golden +++ b/agent/xds/testdata/clusters/custom-timeouts.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/custom-upstream-default-chain.golden b/agent/xds/testdata/clusters/custom-upstream-default-chain.golden index 3b83c1aa797f..806e808e562b 100644 --- a/agent/xds/testdata/clusters/custom-upstream-default-chain.golden +++ b/agent/xds/testdata/clusters/custom-upstream-default-chain.golden @@ -13,6 +13,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/custom-upstream.golden b/agent/xds/testdata/clusters/custom-upstream.golden index 3b83c1aa797f..806e808e562b 100644 --- a/agent/xds/testdata/clusters/custom-upstream.golden +++ b/agent/xds/testdata/clusters/custom-upstream.golden @@ -13,6 +13,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/defaults.golden b/agent/xds/testdata/clusters/defaults.golden index bf98f0386f43..62f11f66f461 100644 --- a/agent/xds/testdata/clusters/defaults.golden +++ b/agent/xds/testdata/clusters/defaults.golden @@ -14,6 +14,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -58,6 +61,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/agent/xds/testdata/clusters/splitter-with-resolver-redirect.golden b/agent/xds/testdata/clusters/splitter-with-resolver-redirect.golden index 99c93b187082..71adafea57f7 100644 --- a/agent/xds/testdata/clusters/splitter-with-resolver-redirect.golden +++ b/agent/xds/testdata/clusters/splitter-with-resolver-redirect.golden @@ -13,6 +13,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -78,6 +81,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { @@ -123,6 +129,9 @@ } }, "connectTimeout": "5s", + "circuitBreakers": { + + }, "tlsContext": { "commonTlsContext": { "tlsParams": { diff --git a/test/integration/connect/envoy/case-upstream-connection-limits/s1.hcl b/test/integration/connect/envoy/case-upstream-connection-limits/s1.hcl new file mode 100644 index 000000000000..3bdf91c05878 --- /dev/null +++ b/test/integration/connect/envoy/case-upstream-connection-limits/s1.hcl @@ -0,0 +1,23 @@ +services { + name = "s1" + port = 8080 + connect { + sidecar_service { + proxy { + upstreams = [ + { + destination_name = "s2" + local_bind_port = 5000 + config { + limits { + max_connections = 3 + max_pending_requests = 4 + max_concurrent_requests = 5 + } + } + } + ] + } + } + } +} diff --git a/test/integration/connect/envoy/case-upstream-connection-limits/s2.hcl b/test/integration/connect/envoy/case-upstream-connection-limits/s2.hcl new file mode 100644 index 000000000000..9c23e79c7267 --- /dev/null +++ b/test/integration/connect/envoy/case-upstream-connection-limits/s2.hcl @@ -0,0 +1,5 @@ +services { + name = "s2" + port = 8181 + connect { sidecar_service {} } +} diff --git a/test/integration/connect/envoy/case-upstream-connection-limits/setup.sh b/test/integration/connect/envoy/case-upstream-connection-limits/setup.sh new file mode 100644 index 000000000000..a74435b3b1b5 --- /dev/null +++ b/test/integration/connect/envoy/case-upstream-connection-limits/setup.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -eEuo pipefail + +gen_envoy_bootstrap s1 19000 primary +gen_envoy_bootstrap s2 19001 primary diff --git a/test/integration/connect/envoy/case-upstream-connection-limits/verify.bats b/test/integration/connect/envoy/case-upstream-connection-limits/verify.bats new file mode 100644 index 000000000000..116f78cc176a --- /dev/null +++ b/test/integration/connect/envoy/case-upstream-connection-limits/verify.bats @@ -0,0 +1,44 @@ +#!/usr/bin/env bats + +load helpers + +@test "s1 proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "s2 proxy admin is up on :19001" { + retry_default curl -f -s localhost:19001/stats -o /dev/null +} + +@test "s1 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21000 s1 +} + +@test "s2 proxy listener should be up and have right cert" { + assert_proxy_presents_cert_uri localhost:21001 s2 +} + +@test "s2 proxy should be healthy" { + assert_service_has_healthy_instances s2 1 +} + +@test "s1 upstream should have healthy endpoints for s2" { + assert_upstream_has_endpoints_in_status 127.0.0.1:19000 s2.default.primary HEALTHY 1 +} + +@test "s1 proxy should have been configured with max_connections on the cluster" { + CLUSTER_THRESHOLD=$(get_envoy_cluster_threshold localhost:19000 s2.default.primary) + echo $CLUSTER_THRESHOLD + + MAX_CONNS=$(echo $CLUSTER_THRESHOLD | jq --raw-output '.max_connections') + MAX_PENDING_REQS=$(echo $CLUSTER_THRESHOLD | jq --raw-output '.max_pending_requests') + MAX_REQS=$(echo $CLUSTER_THRESHOLD | jq --raw-output '.max_requests') + + echo "MAX_CONNS = $MAX_CONNS" + echo "MAX_PENDING_REQS = $MAX_PENDING_REQS" + echo "MAX_REQS = $MAX_REQS" + + [ "$MAX_CONNS" = "3" ] + [ "$MAX_PENDING_REQS" = "4" ] + [ "$MAX_REQS" = "5" ] +} diff --git a/test/integration/connect/envoy/helpers.bash b/test/integration/connect/envoy/helpers.bash index c230b4bd67e4..700be55f4b8f 100755 --- a/test/integration/connect/envoy/helpers.bash +++ b/test/integration/connect/envoy/helpers.bash @@ -146,6 +146,18 @@ function get_envoy_listener_filters { echo "$output" | jq --raw-output '.configs[2].dynamic_active_listeners[].listener | "\(.name) \( .filter_chains[0].filters | map(.name) | join(","))"' } +function get_envoy_cluster_threshold { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " + .configs[1].dynamic_active_clusters[] + | select(.cluster.name|startswith(\"${CLUSTER_NAME}\")) + | .cluster.circuit_breakers.thresholds[0] + " +} + function get_envoy_stats_flush_interval { local HOSTPORT=$1 run retry_default curl -s -f $HOSTPORT/config_dump diff --git a/website/source/docs/connect/proxies/envoy.md b/website/source/docs/connect/proxies/envoy.md index 7ff90a154218..4c47474273fb 100644 --- a/website/source/docs/connect/proxies/envoy.md +++ b/website/source/docs/connect/proxies/envoy.md @@ -256,6 +256,21 @@ definition](/docs/connect/registration/service-registration.html) or proxy upstream config will override any values defined in config entries. It is supported here for backwards compatibility with Consul versions prior to 1.6.0. +- `limits` - A set of limits to apply when connecting to the upstream service. + These limits are applied on a per-service-instance basis. The following + limits are respected: + + - `max_connections` - The maximum number of connections a service instance + will be allowed to establish against the given upstream. Use this to limit + HTTP/1.1 traffic, since HTTP/1.1 has a request per connection. + - `max_pending_requests` - The maximum number of requests that will be queued + while waiting for a connection to be established. For this configuration to + be respected, a L7 protocol must be defined in the `protocol` field. + - `max_concurrent_requests` - The maximum number of concurrent requests that + will be allowed at a single point in time. Use this to limit HTTP/2 traffic, + since HTTP/2 has many requests per connection. For this configuration to be + respected, a L7 protocol must be defined in the `protocol` field. + ### Mesh Gateway Options These fields may also be overridden explicitly in the [proxy service diff --git a/website/source/docs/connect/registration/service-registration.html.md b/website/source/docs/connect/registration/service-registration.html.md index 279f1a8ba8d2..db6b966107a7 100644 --- a/website/source/docs/connect/registration/service-registration.html.md +++ b/website/source/docs/connect/registration/service-registration.html.md @@ -184,10 +184,10 @@ followed by documentation for each attribute. any valid JSON object. This might be used to configure proxy-specific features like timeouts or retries for the given upstream. See the [built-in proxy configuration - reference](/docs/connect/configuration.html#built-in-proxy-options) for + reference](/docs/connect/proxies/built-in.html#proxy-upstream-config-key-reference) for options available when using the built-in proxy. If using Envoy as a proxy, see [Envoy configuration - reference](/docs/connect/configuration.html#envoy-options) + reference](/docs/connect/proxies/envoy.html#proxy-upstream-config-options) * `mesh_gateway` `(object: {})` - Specifies the mesh gateway configuration for this proxy. The format is defined in the [Mesh Gateway Configuration Reference](#mesh-gateway-configuration-reference). * `expose` `(object: {})` - Specifies the configuration to expose HTTP paths through this proxy.