fix: multiple grpc/http2 services for ingress listeners
This commit is contained in:
parent
13e2c81451
commit
65ca7e0bfb
|
@ -0,0 +1,3 @@
|
|||
```release-note:bug
|
||||
fix a bug that caused an error when creating `grpc` or `http2` ingress gateway listeners with multiple services
|
||||
```
|
|
@ -800,6 +800,109 @@ func TestConfigSnapshotIngress_HTTPMultipleServices(t testing.T) *ConfigSnapshot
|
|||
})
|
||||
}
|
||||
|
||||
func TestConfigSnapshotIngress_GRPCMultipleServices(t testing.T) *ConfigSnapshot {
|
||||
// We do not add baz/qux here so that we test the chain.IsDefault() case
|
||||
entries := []structs.ConfigEntry{
|
||||
&structs.ProxyConfigEntry{
|
||||
Kind: structs.ProxyDefaults,
|
||||
Name: structs.ProxyConfigGlobal,
|
||||
Config: map[string]interface{}{
|
||||
"protocol": "http",
|
||||
},
|
||||
},
|
||||
&structs.ServiceResolverConfigEntry{
|
||||
Kind: structs.ServiceResolver,
|
||||
Name: "foo",
|
||||
ConnectTimeout: 22 * time.Second,
|
||||
},
|
||||
&structs.ServiceResolverConfigEntry{
|
||||
Kind: structs.ServiceResolver,
|
||||
Name: "bar",
|
||||
ConnectTimeout: 22 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
foo = structs.NewServiceName("foo", nil)
|
||||
fooUID = NewUpstreamIDFromServiceName(foo)
|
||||
fooChain = discoverychain.TestCompileConfigEntries(t, "foo", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...)
|
||||
|
||||
bar = structs.NewServiceName("bar", nil)
|
||||
barUID = NewUpstreamIDFromServiceName(bar)
|
||||
barChain = discoverychain.TestCompileConfigEntries(t, "bar", "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...)
|
||||
)
|
||||
|
||||
require.False(t, fooChain.Default)
|
||||
require.False(t, barChain.Default)
|
||||
|
||||
return TestConfigSnapshotIngressGateway(t, false, "http", "default", nil, func(entry *structs.IngressGatewayConfigEntry) {
|
||||
entry.Listeners = []structs.IngressListener{
|
||||
{
|
||||
Port: 8080,
|
||||
Protocol: "grpc",
|
||||
Services: []structs.IngressService{
|
||||
{
|
||||
Name: "foo",
|
||||
Hosts: []string{
|
||||
"test1.example.com",
|
||||
"test2.example.com",
|
||||
"test2.example.com:8080",
|
||||
},
|
||||
},
|
||||
{Name: "bar"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}, []UpdateEvent{
|
||||
{
|
||||
CorrelationID: gatewayServicesWatchID,
|
||||
Result: &structs.IndexedGatewayServices{
|
||||
Services: []*structs.GatewayService{
|
||||
{
|
||||
Service: foo,
|
||||
Port: 8080,
|
||||
Protocol: "grpc",
|
||||
Hosts: []string{
|
||||
"test1.example.com",
|
||||
"test2.example.com",
|
||||
"test2.example.com:8080",
|
||||
},
|
||||
},
|
||||
{
|
||||
Service: bar,
|
||||
Port: 8080,
|
||||
Protocol: "grpc",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CorrelationID: "discovery-chain:" + fooUID.String(),
|
||||
Result: &structs.DiscoveryChainResponse{
|
||||
Chain: fooChain,
|
||||
},
|
||||
},
|
||||
{
|
||||
CorrelationID: "upstream-target:" + fooChain.ID() + ":" + fooUID.String(),
|
||||
Result: &structs.IndexedCheckServiceNodes{
|
||||
Nodes: TestUpstreamNodes(t, "foo"),
|
||||
},
|
||||
},
|
||||
{
|
||||
CorrelationID: "discovery-chain:" + barUID.String(),
|
||||
Result: &structs.DiscoveryChainResponse{
|
||||
Chain: barChain,
|
||||
},
|
||||
},
|
||||
{
|
||||
CorrelationID: "upstream-target:" + barChain.ID() + ":" + barUID.String(),
|
||||
Result: &structs.IndexedCheckServiceNodes{
|
||||
Nodes: TestUpstreamNodes(t, "bar"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestConfigSnapshotIngress_MultipleListenersDuplicateService(t testing.T) *ConfigSnapshot {
|
||||
var (
|
||||
foo = structs.NewServiceName("foo", nil)
|
||||
|
|
|
@ -275,8 +275,8 @@ func (e *IngressGatewayConfigEntry) Validate() error {
|
|||
}
|
||||
|
||||
// Validate that http features aren't being used with tcp or another non-supported protocol.
|
||||
if listener.Protocol != "http" && len(listener.Services) > 1 {
|
||||
return fmt.Errorf("Multiple services per listener are only supported for protocol = 'http' (listener on port %d)",
|
||||
if !IsProtocolHTTPLike(listener.Protocol) && len(listener.Services) > 1 {
|
||||
return fmt.Errorf("Multiple services per listener are only supported for L7 protocols, 'http', 'grpc' and 'http2' (listener on port %d)",
|
||||
listener.Port)
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,26 @@ func TestIngressGatewayConfigEntry(t *testing.T) {
|
|||
validateErr: "Wildcard service name is only valid for protocol",
|
||||
},
|
||||
"http features: multiple services": {
|
||||
entry: &IngressGatewayConfigEntry{
|
||||
Kind: "ingress-gateway",
|
||||
Name: "ingress-web",
|
||||
Listeners: []IngressListener{
|
||||
{
|
||||
Port: 1111,
|
||||
Protocol: "http",
|
||||
Services: []IngressService{
|
||||
{
|
||||
Name: "db1",
|
||||
},
|
||||
{
|
||||
Name: "db2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"http features: multiple services on tcp listener": {
|
||||
entry: &IngressGatewayConfigEntry{
|
||||
Kind: "ingress-gateway",
|
||||
Name: "ingress-web",
|
||||
|
@ -153,7 +173,7 @@ func TestIngressGatewayConfigEntry(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
validateErr: "Multiple services per listener are only supported for protocol",
|
||||
validateErr: "Multiple services per listener are only supported for L7",
|
||||
},
|
||||
// ==========================
|
||||
"tcp listener requires a defined service": {
|
||||
|
|
|
@ -680,6 +680,10 @@ func TestListenersFromSnapshot(t *testing.T) {
|
|||
name: "ingress-http-multiple-services",
|
||||
create: proxycfg.TestConfigSnapshotIngress_HTTPMultipleServices,
|
||||
},
|
||||
{
|
||||
name: "ingress-grpc-multiple-services",
|
||||
create: proxycfg.TestConfigSnapshotIngress_GRPCMultipleServices,
|
||||
},
|
||||
{
|
||||
name: "terminating-gateway-no-api-cert",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
|
|
|
@ -142,6 +142,10 @@ func TestRoutesFromSnapshot(t *testing.T) {
|
|||
name: "ingress-http-multiple-services",
|
||||
create: proxycfg.TestConfigSnapshotIngress_HTTPMultipleServices,
|
||||
},
|
||||
{
|
||||
name: "ingress-grpc-multiple-services",
|
||||
create: proxycfg.TestConfigSnapshotIngress_GRPCMultipleServices,
|
||||
},
|
||||
{
|
||||
name: "ingress-with-chain-and-router-header-manip",
|
||||
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "grpc:1.2.3.4:8080",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "1.2.3.4",
|
||||
"portValue": 8080
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "ingress_upstream_8080",
|
||||
"rds": {
|
||||
"configSource": {
|
||||
"ads": {
|
||||
|
||||
},
|
||||
"resourceApiVersion": "V3"
|
||||
},
|
||||
"routeConfigName": "8080"
|
||||
},
|
||||
"httpFilters": [
|
||||
{
|
||||
"name": "envoy.filters.http.grpc_stats",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig",
|
||||
"statsForAllMethods": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.grpc_http1_bridge",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.grpc_http1_bridge.v3.Config"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.http.router",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tracing": {
|
||||
"randomSampling": {}
|
||||
},
|
||||
"http2ProtocolOptions": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"name": "8080",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "foo",
|
||||
"domains": [
|
||||
"test1.example.com",
|
||||
"test2.example.com",
|
||||
"test2.example.com:8080",
|
||||
"test1.example.com:8080"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bar",
|
||||
"domains": [
|
||||
"bar.ingress.*",
|
||||
"bar.ingress.*:8080"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "bar.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"validateClusters": true
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
Loading…
Reference in New Issue