mirror of https://github.com/hashicorp/consul
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
821 lines
25 KiB
821 lines
25 KiB
package xds |
|
|
|
import ( |
|
"bytes" |
|
"path/filepath" |
|
"sort" |
|
"testing" |
|
"text/template" |
|
|
|
envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" |
|
|
|
"github.com/golang/protobuf/ptypes/wrappers" |
|
testinf "github.com/mitchellh/go-testing-interface" |
|
"github.com/stretchr/testify/require" |
|
|
|
"github.com/hashicorp/consul/agent/proxycfg" |
|
"github.com/hashicorp/consul/agent/structs" |
|
"github.com/hashicorp/consul/agent/xds/proxysupport" |
|
"github.com/hashicorp/consul/agent/xds/xdscommon" |
|
"github.com/hashicorp/consul/sdk/testutil" |
|
"github.com/hashicorp/consul/types" |
|
) |
|
|
|
func TestClustersFromSnapshot(t *testing.T) { |
|
if testing.Short() { |
|
t.Skip("too slow for testing.Short") |
|
} |
|
|
|
tests := []struct { |
|
name string |
|
create func(t testinf.T) *proxycfg.ConfigSnapshot |
|
overrideGoldenName string |
|
}{ |
|
{ |
|
name: "defaults", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-peered-upstreams", |
|
create: proxycfg.TestConfigSnapshotPeering, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tls-outgoing-min-version-auto", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
TLSMinVersion: types.TLSVersionAuto, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tls-outgoing-min-version", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
TLSMinVersion: types.TLSv1_3, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tls-outgoing-max-version", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
TLSMaxVersion: types.TLSv1_2, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tls-outgoing-cipher-suites", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
CipherSuites: []types.TLSCipherSuite{ |
|
types.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
|
types.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "custom-local-app", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
ns.Proxy.Config["envoy_local_cluster_json"] = |
|
customAppClusterJSON(t, customClusterJSONOptions{ |
|
Name: "mylocal", |
|
}) |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-upstream", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = |
|
customAppClusterJSON(t, customClusterJSONOptions{ |
|
Name: "myservice", |
|
}) |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-upstream-default-chain", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", func(ns *structs.NodeService) { |
|
ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = |
|
customAppClusterJSON(t, customClusterJSONOptions{ |
|
Name: "myservice", |
|
}) |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-upstream-ignores-tls", |
|
overrideGoldenName: "custom-upstream", // should be the same |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = |
|
customAppClusterJSON(t, customClusterJSONOptions{ |
|
Name: "myservice", |
|
// Attempt to override the TLS context should be ignored |
|
TLSContext: `"allowRenegotiation": false`, |
|
}) |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-timeouts", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
ns.Proxy.Config["local_connect_timeout_ms"] = 1234 |
|
ns.Proxy.Upstreams[0].Config["connect_timeout_ms"] = 2345 |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-max-inbound-connections", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
ns.Proxy.Config["max_inbound_connections"] = 3456 |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-limits-max-connections-only", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
for i := range ns.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 ns.Proxy.Upstreams[i].Config == nil { |
|
ns.Proxy.Upstreams[i].Config = map[string]interface{}{} |
|
} |
|
|
|
ns.Proxy.Upstreams[i].Config["limits"] = map[string]interface{}{ |
|
"max_connections": 500, |
|
} |
|
} |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-limits-set-to-zero", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
for i := range ns.Proxy.Upstreams { |
|
if ns.Proxy.Upstreams[i].Config == nil { |
|
ns.Proxy.Upstreams[i].Config = map[string]interface{}{} |
|
} |
|
|
|
ns.Proxy.Upstreams[i].Config["limits"] = map[string]interface{}{ |
|
"max_connections": 0, |
|
"max_pending_requests": 0, |
|
"max_concurrent_requests": 0, |
|
} |
|
} |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "custom-limits", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
for i := range ns.Proxy.Upstreams { |
|
if ns.Proxy.Upstreams[i].Config == nil { |
|
ns.Proxy.Upstreams[i].Config = map[string]interface{}{} |
|
} |
|
|
|
ns.Proxy.Upstreams[i].Config["limits"] = map[string]interface{}{ |
|
"max_connections": 500, |
|
"max_pending_requests": 600, |
|
"max_concurrent_requests": 700, |
|
} |
|
} |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-chain", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-chain-external-sni", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-chain-and-overrides", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-chain-and-failover", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway-triggered", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway-triggered", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway-triggered", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway-triggered", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "splitter-with-resolver-redirect", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "connect-proxy-lb-in-resolver", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "lb-resolver", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "expose-paths-local-app-paths", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotExposeConfig(t, nil) |
|
}, |
|
}, |
|
{ |
|
name: "downstream-service-with-unix-sockets", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshot(t, func(ns *structs.NodeService) { |
|
ns.Address = "" |
|
ns.Port = 0 |
|
ns.Proxy.LocalServiceAddress = "" |
|
ns.Proxy.LocalServicePort = 0 |
|
ns.Proxy.LocalServiceSocketPath = "/tmp/downstream_proxy.sock" |
|
}, nil) |
|
}, |
|
}, |
|
{ |
|
name: "expose-paths-new-cluster-http2", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotExposeConfig(t, func(ns *structs.NodeService) { |
|
ns.Proxy.Expose.Paths[1] = structs.ExposePath{ |
|
LocalPathPort: 9090, |
|
Path: "/grpc.health.v1.Health/Check", |
|
ListenerPort: 21501, |
|
Protocol: "http2", |
|
} |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "expose-paths-grpc-new-cluster-http1", |
|
create: proxycfg.TestConfigSnapshotGRPCExposeHTTP1, |
|
}, |
|
{ |
|
name: "mesh-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "default", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-using-federation-states", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "federation-states", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-no-services", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "no-services", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-service-subsets", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "service-subsets", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-ignore-extra-resolvers", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "ignore-extra-resolvers", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-service-timeouts", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "service-timeouts", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-non-hash-lb-injected", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "non-hash-lb-injected", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "mesh-gateway-hash-lb-ignored", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotMeshGateway(t, "hash-lb-ignored", nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"default", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-gateway-with-tls-outgoing-min-version", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
TLSMinVersion: types.TLSv1_3, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-gateway-with-tls-outgoing-max-version", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
TLSMaxVersion: types.TLSv1_2, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-gateway-with-tls-outgoing-cipher-suites", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", "default", nil, nil, []proxycfg.UpdateEvent{ |
|
{ |
|
CorrelationID: "mesh", |
|
Result: &structs.ConfigEntryResponse{ |
|
Entry: &structs.MeshConfigEntry{ |
|
TLS: &structs.MeshTLSConfig{ |
|
Outgoing: &structs.MeshDirectionalTLSConfig{ |
|
CipherSuites: []types.TLSCipherSuite{ |
|
types.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
|
types.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-gateway-no-services", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, false, "tcp", |
|
"default", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-chain", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"simple", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-chain-external-sni", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"external-sni", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-chain-and-failover", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-failover-through-remote-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-remote-gateway", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-failover-through-remote-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-remote-gateway-triggered", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-double-failover-through-remote-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-double-remote-gateway", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-double-failover-through-remote-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-double-remote-gateway-triggered", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-failover-through-local-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-local-gateway", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-failover-through-local-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-local-gateway-triggered", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-double-failover-through-local-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-double-local-gateway", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-with-tcp-chain-double-failover-through-local-gateway-triggered", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "tcp", |
|
"failover-through-double-local-gateway-triggered", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-splitter-with-resolver-redirect", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "http", |
|
"splitter-with-resolver-redirect-multidc", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "ingress-lb-in-resolver", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotIngressGateway(t, true, "http", |
|
"lb-resolver", nil, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "terminating-gateway", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotTerminatingGateway(t, true, false, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "terminating-gateway-no-services", |
|
create: func(t testinf.T) *proxycfg.ConfigSnapshot { |
|
return proxycfg.TestConfigSnapshotTerminatingGateway(t, false, false, nil, nil) |
|
}, |
|
}, |
|
{ |
|
name: "terminating-gateway-service-subsets", |
|
create: proxycfg.TestConfigSnapshotTerminatingGatewayServiceSubsetsWebAndCache, |
|
}, |
|
{ |
|
name: "terminating-gateway-hostname-service-subsets", |
|
create: proxycfg.TestConfigSnapshotTerminatingGatewayHostnameSubsets, |
|
}, |
|
{ |
|
name: "terminating-gateway-sni", |
|
create: proxycfg.TestConfigSnapshotTerminatingGatewaySNI, |
|
}, |
|
{ |
|
name: "terminating-gateway-ignore-extra-resolvers", |
|
create: proxycfg.TestConfigSnapshotTerminatingGatewayIgnoreExtraResolvers, |
|
}, |
|
{ |
|
name: "terminating-gateway-lb-config", |
|
create: proxycfg.TestConfigSnapshotTerminatingGatewayLBConfigNoHashPolicies, |
|
}, |
|
{ |
|
name: "ingress-multiple-listeners-duplicate-service", |
|
create: proxycfg.TestConfigSnapshotIngress_MultipleListenersDuplicateService, |
|
}, |
|
{ |
|
name: "transparent-proxy", |
|
create: proxycfg.TestConfigSnapshotTransparentProxy, |
|
}, |
|
{ |
|
name: "transparent-proxy-catalog-destinations-only", |
|
create: proxycfg.TestConfigSnapshotTransparentProxyCatalogDestinationsOnly, |
|
}, |
|
{ |
|
name: "transparent-proxy-dial-instances-directly", |
|
create: proxycfg.TestConfigSnapshotTransparentProxyDialDirectly, |
|
}, |
|
} |
|
|
|
latestEnvoyVersion := proxysupport.EnvoyVersions[0] |
|
for _, envoyVersion := range proxysupport.EnvoyVersions { |
|
sf, err := determineSupportedProxyFeaturesFromString(envoyVersion) |
|
require.NoError(t, err) |
|
t.Run("envoy-"+envoyVersion, func(t *testing.T) { |
|
for _, tt := range tests { |
|
t.Run(tt.name, func(t *testing.T) { |
|
// Sanity check default with no overrides first |
|
snap := tt.create(t) |
|
|
|
// We need to replace the TLS certs with deterministic ones to make golden |
|
// files workable. Note we don't update these otherwise they'd change |
|
// golder files for every test case and so not be any use! |
|
setupTLSRootsAndLeaf(t, snap) |
|
|
|
// Need server just for logger dependency |
|
g := newResourceGenerator(testutil.Logger(t), nil, nil, false) |
|
g.ProxyFeatures = sf |
|
|
|
clusters, err := g.clustersFromSnapshot(snap) |
|
require.NoError(t, err) |
|
|
|
sort.Slice(clusters, func(i, j int) bool { |
|
return clusters[i].(*envoy_cluster_v3.Cluster).Name < clusters[j].(*envoy_cluster_v3.Cluster).Name |
|
}) |
|
|
|
r, err := createResponse(xdscommon.ClusterType, "00000001", "00000001", clusters) |
|
require.NoError(t, err) |
|
|
|
t.Run("current", func(t *testing.T) { |
|
gotJSON := protoToJSON(t, r) |
|
|
|
gName := tt.name |
|
if tt.overrideGoldenName != "" { |
|
gName = tt.overrideGoldenName |
|
} |
|
|
|
require.JSONEq(t, goldenEnvoy(t, filepath.Join("clusters", gName), envoyVersion, latestEnvoyVersion, gotJSON), gotJSON) |
|
}) |
|
}) |
|
} |
|
}) |
|
} |
|
} |
|
|
|
type customClusterJSONOptions struct { |
|
Name string |
|
TLSContext string |
|
} |
|
|
|
var customAppClusterJSONTpl = `{ |
|
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", |
|
{{ if .TLSContext -}} |
|
"transport_socket": { |
|
"name": "tls", |
|
"typed_config": { |
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", |
|
{{ .TLSContext }} |
|
} |
|
}, |
|
{{- end }} |
|
"name": "{{ .Name }}", |
|
"connectTimeout": "15s", |
|
"loadAssignment": { |
|
"clusterName": "{{ .Name }}", |
|
"endpoints": [ |
|
{ |
|
"lbEndpoints": [ |
|
{ |
|
"endpoint": { |
|
"address": { |
|
"socketAddress": { |
|
"address": "127.0.0.1", |
|
"portValue": 8080 |
|
} |
|
} |
|
} |
|
} |
|
] |
|
} |
|
] |
|
} |
|
}` |
|
|
|
var customAppClusterJSONTemplate = template.Must(template.New("").Parse(customAppClusterJSONTpl)) |
|
|
|
func customAppClusterJSON(t testinf.T, opts customClusterJSONOptions) string { |
|
t.Helper() |
|
var buf bytes.Buffer |
|
err := customAppClusterJSONTemplate.Execute(&buf, opts) |
|
require.NoError(t, err) |
|
return buf.String() |
|
} |
|
|
|
func setupTLSRootsAndLeaf(t *testing.T, snap *proxycfg.ConfigSnapshot) { |
|
if snap.Leaf() != nil { |
|
switch snap.Kind { |
|
case structs.ServiceKindConnectProxy: |
|
snap.ConnectProxy.Leaf.CertPEM = loadTestResource(t, "test-leaf-cert") |
|
snap.ConnectProxy.Leaf.PrivateKeyPEM = loadTestResource(t, "test-leaf-key") |
|
case structs.ServiceKindIngressGateway: |
|
snap.IngressGateway.Leaf.CertPEM = loadTestResource(t, "test-leaf-cert") |
|
snap.IngressGateway.Leaf.PrivateKeyPEM = loadTestResource(t, "test-leaf-key") |
|
} |
|
} |
|
if snap.Roots != nil { |
|
snap.Roots.Roots[0].RootCert = loadTestResource(t, "test-root-cert") |
|
} |
|
} |
|
|
|
func TestEnvoyLBConfig_InjectToCluster(t *testing.T) { |
|
var tests = []struct { |
|
name string |
|
lb *structs.LoadBalancer |
|
expected *envoy_cluster_v3.Cluster |
|
}{ |
|
{ |
|
name: "skip empty", |
|
lb: &structs.LoadBalancer{ |
|
Policy: "", |
|
}, |
|
expected: &envoy_cluster_v3.Cluster{}, |
|
}, |
|
{ |
|
name: "round robin", |
|
lb: &structs.LoadBalancer{ |
|
Policy: structs.LBPolicyRoundRobin, |
|
}, |
|
expected: &envoy_cluster_v3.Cluster{LbPolicy: envoy_cluster_v3.Cluster_ROUND_ROBIN}, |
|
}, |
|
{ |
|
name: "random", |
|
lb: &structs.LoadBalancer{ |
|
Policy: structs.LBPolicyRandom, |
|
}, |
|
expected: &envoy_cluster_v3.Cluster{LbPolicy: envoy_cluster_v3.Cluster_RANDOM}, |
|
}, |
|
{ |
|
name: "maglev", |
|
lb: &structs.LoadBalancer{ |
|
Policy: structs.LBPolicyMaglev, |
|
}, |
|
expected: &envoy_cluster_v3.Cluster{LbPolicy: envoy_cluster_v3.Cluster_MAGLEV}, |
|
}, |
|
{ |
|
name: "ring_hash", |
|
lb: &structs.LoadBalancer{ |
|
Policy: structs.LBPolicyRingHash, |
|
RingHashConfig: &structs.RingHashConfig{ |
|
MinimumRingSize: 3, |
|
MaximumRingSize: 7, |
|
}, |
|
}, |
|
expected: &envoy_cluster_v3.Cluster{ |
|
LbPolicy: envoy_cluster_v3.Cluster_RING_HASH, |
|
LbConfig: &envoy_cluster_v3.Cluster_RingHashLbConfig_{ |
|
RingHashLbConfig: &envoy_cluster_v3.Cluster_RingHashLbConfig{ |
|
MinimumRingSize: &wrappers.UInt64Value{Value: 3}, |
|
MaximumRingSize: &wrappers.UInt64Value{Value: 7}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "least_request", |
|
lb: &structs.LoadBalancer{ |
|
Policy: "least_request", |
|
LeastRequestConfig: &structs.LeastRequestConfig{ |
|
ChoiceCount: 3, |
|
}, |
|
}, |
|
expected: &envoy_cluster_v3.Cluster{ |
|
LbPolicy: envoy_cluster_v3.Cluster_LEAST_REQUEST, |
|
LbConfig: &envoy_cluster_v3.Cluster_LeastRequestLbConfig_{ |
|
LeastRequestLbConfig: &envoy_cluster_v3.Cluster_LeastRequestLbConfig{ |
|
ChoiceCount: &wrappers.UInt32Value{Value: 3}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
} |
|
|
|
for _, tc := range tests { |
|
t.Run(tc.name, func(t *testing.T) { |
|
var c envoy_cluster_v3.Cluster |
|
err := injectLBToCluster(tc.lb, &c) |
|
require.NoError(t, err) |
|
|
|
require.Equal(t, tc.expected, &c) |
|
}) |
|
} |
|
} |
|
|
|
// UID is just a convenience function to aid in writing tests less verbosely. |
|
func UID(input string) proxycfg.UpstreamID { |
|
return proxycfg.UpstreamIDFromString(input) |
|
}
|
|
|