consul/agent/proxycfg/testing_terminating_gateway.go

992 lines
26 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
[COMPLIANCE] License changes (#18443) * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at <Blog URL>, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-08-11 13:12:13 +00:00
// SPDX-License-Identifier: BUSL-1.1
package proxycfg
import (
"time"
"github.com/mitchellh/go-testing-interface"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/api"
)
func TestConfigSnapshotTerminatingGateway(t testing.T, populateServices bool, nsFn func(ns *structs.NodeService), extraUpdates []UpdateEvent) *ConfigSnapshot {
roots, _ := TestCerts(t)
var (
web = structs.NewServiceName("web", nil)
api = structs.NewServiceName("api", nil)
db = structs.NewServiceName("db", nil)
cache = structs.NewServiceName("cache", nil)
)
baseEvents := []UpdateEvent{
{
CorrelationID: rootsWatchID,
Result: roots,
},
{
CorrelationID: gatewayServicesWatchID,
Result: &structs.IndexedGatewayServices{
Services: nil,
},
},
}
tgtwyServices := []*structs.GatewayService{}
if populateServices {
webNodes := TestUpstreamNodes(t, web.Name)
webNodes[0].Service.Meta = map[string]string{"version": "1"}
webNodes[1].Service.Meta = map[string]string{"version": "2"}
apiNodes := structs.CheckServiceNodes{
structs.CheckServiceNode{
Node: &structs.Node{
ID: "api",
Node: "test1",
Address: "10.10.1.1",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "api",
Address: "api.mydomain",
Port: 8081,
},
Checks: structs.HealthChecks{
{Status: "critical"},
},
},
structs.CheckServiceNode{
Node: &structs.Node{
ID: "test2",
Node: "test2",
Address: "10.10.1.2",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "api",
Address: "api.altdomain",
Port: 8081,
Meta: map[string]string{
"domain": "alt",
},
},
},
structs.CheckServiceNode{
Node: &structs.Node{
ID: "test3",
Node: "test3",
Address: "10.10.1.3",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "api",
Address: "10.10.1.3",
Port: 8081,
},
},
structs.CheckServiceNode{
Node: &structs.Node{
ID: "test4",
Node: "test4",
Address: "10.10.1.4",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "api",
Address: "api.thirddomain",
Port: 8081,
},
},
}
// Has failing instance
dbNodes := structs.CheckServiceNodes{
structs.CheckServiceNode{
Node: &structs.Node{
ID: "db",
Node: "test4",
Address: "10.10.1.4",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "db",
Address: "db.mydomain",
Port: 8081,
},
Checks: structs.HealthChecks{
{Status: "critical"},
},
},
}
// Has passing instance but failing subset
cacheNodes := structs.CheckServiceNodes{
{
Node: &structs.Node{
ID: "cache",
Node: "test5",
Address: "10.10.1.5",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "cache",
Address: "cache.mydomain",
Port: 8081,
},
},
{
Node: &structs.Node{
ID: "cache",
Node: "test5",
Address: "10.10.1.5",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "cache",
Address: "cache.mydomain",
Port: 8081,
Meta: map[string]string{
"Env": "prod",
},
},
Checks: structs.HealthChecks{
{Status: "critical"},
},
},
}
tgtwyServices = append(tgtwyServices,
&structs.GatewayService{
Service: web,
CAFile: "ca.cert.pem",
},
&structs.GatewayService{
Service: api,
CAFile: "ca.cert.pem",
CertFile: "api.cert.pem",
KeyFile: "api.key.pem",
},
&structs.GatewayService{
Service: db,
},
&structs.GatewayService{
Service: cache,
},
)
baseEvents = testSpliceEvents(baseEvents, []UpdateEvent{
{
CorrelationID: gatewayServicesWatchID,
Result: &structs.IndexedGatewayServices{
Services: tgtwyServices,
},
},
{
CorrelationID: externalServiceIDPrefix + web.String(),
Result: &structs.IndexedCheckServiceNodes{
Nodes: webNodes,
},
},
{
CorrelationID: externalServiceIDPrefix + api.String(),
Result: &structs.IndexedCheckServiceNodes{
Nodes: apiNodes,
},
},
{
CorrelationID: externalServiceIDPrefix + db.String(),
Result: &structs.IndexedCheckServiceNodes{
Nodes: dbNodes,
},
},
{
CorrelationID: externalServiceIDPrefix + cache.String(),
Result: &structs.IndexedCheckServiceNodes{
Nodes: cacheNodes,
},
},
// ========
// no intentions defined for these services
{
CorrelationID: serviceIntentionsIDPrefix + web.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + api.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + db.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + cache.String(),
Result: structs.SimplifiedIntentions{},
},
// ========
{
CorrelationID: serviceLeafIDPrefix + web.String(),
Result: &structs.IssuedCert{
CertPEM: golden(t, "test-leaf-cert"),
PrivateKeyPEM: golden(t, "test-leaf-key"),
},
},
{
CorrelationID: serviceLeafIDPrefix + api.String(),
Result: &structs.IssuedCert{
CertPEM: golden(t, "alt-test-leaf-cert"),
PrivateKeyPEM: golden(t, "alt-test-leaf-key"),
},
},
{
CorrelationID: serviceLeafIDPrefix + db.String(),
Result: &structs.IssuedCert{
CertPEM: golden(t, "db-test-leaf-cert"),
PrivateKeyPEM: golden(t, "db-test-leaf-key"),
},
},
{
CorrelationID: serviceLeafIDPrefix + cache.String(),
Result: &structs.IssuedCert{
CertPEM: golden(t, "cache-test-leaf-cert"),
PrivateKeyPEM: golden(t, "cache-test-leaf-key"),
},
},
// ========
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
},
},
{
CorrelationID: serviceConfigIDPrefix + api.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
},
},
{
CorrelationID: serviceConfigIDPrefix + db.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
},
},
{
CorrelationID: serviceConfigIDPrefix + cache.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
},
},
// ========
{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
},
},
},
{
CorrelationID: serviceResolverIDPrefix + api.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
},
},
},
{
CorrelationID: serviceResolverIDPrefix + db.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
},
},
},
{
CorrelationID: serviceResolverIDPrefix + cache.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
},
},
},
})
}
return testConfigSnapshotFixture(t, &structs.NodeService{
Kind: structs.ServiceKindTerminatingGateway,
Service: "terminating-gateway",
Address: "1.2.3.4",
Port: 8443,
TaggedAddresses: map[string]structs.ServiceAddress{
structs.TaggedAddressWAN: {
Address: "198.18.0.1",
Port: 443,
},
},
}, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates))
}
func TestConfigSnapshotTerminatingGatewayDestinations(t testing.T, populateDestinations bool, extraUpdates []UpdateEvent) *ConfigSnapshot {
roots, _ := TestCerts(t)
var (
externalIPTCP = structs.NewServiceName("external-IP-TCP", nil)
externalHostnameTCP = structs.NewServiceName("external-hostname-TCP", nil)
externalIPHTTP = structs.NewServiceName("external-IP-HTTP", nil)
externalHostnameHTTP = structs.NewServiceName("external-hostname-HTTP", nil)
externalHostnameWithSNI = structs.NewServiceName("external-hostname-with-SNI", nil)
)
baseEvents := []UpdateEvent{
{
CorrelationID: rootsWatchID,
Result: roots,
},
{
CorrelationID: gatewayServicesWatchID,
Result: &structs.IndexedGatewayServices{
Services: nil,
},
},
}
tgtwyServices := []*structs.GatewayService{}
if populateDestinations {
tgtwyServices = append(tgtwyServices,
&structs.GatewayService{
Service: externalIPTCP,
ServiceKind: structs.GatewayServiceKindDestination,
},
&structs.GatewayService{
Service: externalHostnameTCP,
ServiceKind: structs.GatewayServiceKindDestination,
},
&structs.GatewayService{
Service: externalIPHTTP,
ServiceKind: structs.GatewayServiceKindDestination,
},
&structs.GatewayService{
Service: externalHostnameHTTP,
ServiceKind: structs.GatewayServiceKindDestination,
},
&structs.GatewayService{
Service: externalHostnameWithSNI,
ServiceKind: structs.GatewayServiceKindDestination,
CAFile: "cert.pem",
SNI: "api.test.com",
},
)
baseEvents = testSpliceEvents(baseEvents, []UpdateEvent{
{
CorrelationID: gatewayServicesWatchID,
Result: &structs.IndexedGatewayServices{
Services: tgtwyServices,
},
},
// no intentions defined for these services
{
CorrelationID: serviceIntentionsIDPrefix + externalIPTCP.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + externalHostnameTCP.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + externalIPHTTP.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + externalHostnameHTTP.String(),
Result: structs.SimplifiedIntentions{},
},
{
CorrelationID: serviceIntentionsIDPrefix + externalHostnameWithSNI.String(),
Result: structs.SimplifiedIntentions{},
},
// ========
{
CorrelationID: serviceLeafIDPrefix + externalIPTCP.String(),
Result: &structs.IssuedCert{
CertPEM: "placeholder.crt",
PrivateKeyPEM: "placeholder.key",
},
},
{
CorrelationID: serviceLeafIDPrefix + externalHostnameTCP.String(),
Result: &structs.IssuedCert{
CertPEM: "placeholder.crt",
PrivateKeyPEM: "placeholder.key",
},
},
{
CorrelationID: serviceLeafIDPrefix + externalIPHTTP.String(),
Result: &structs.IssuedCert{
CertPEM: "placeholder.crt",
PrivateKeyPEM: "placeholder.key",
},
},
{
CorrelationID: serviceLeafIDPrefix + externalHostnameHTTP.String(),
Result: &structs.IssuedCert{
CertPEM: "placeholder.crt",
PrivateKeyPEM: "placeholder.key",
},
},
{
CorrelationID: serviceLeafIDPrefix + externalHostnameWithSNI.String(),
Result: &structs.IssuedCert{
CertPEM: "placeholder.crt",
PrivateKeyPEM: "placeholder.key",
},
},
// ========
{
CorrelationID: serviceConfigIDPrefix + externalIPTCP.String(),
Result: &structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
Destination: structs.DestinationConfig{
Addresses: []string{
"192.168.0.1",
"192.168.0.2",
"192.168.0.3",
},
Port: 80,
},
},
},
{
CorrelationID: serviceConfigIDPrefix + externalHostnameTCP.String(),
Result: &structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
Destination: structs.DestinationConfig{
Addresses: []string{
"api.hashicorp.com",
"web.hashicorp.com",
},
Port: 8089,
},
},
},
{
CorrelationID: serviceConfigIDPrefix + externalIPHTTP.String(),
Result: &structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
ProxyConfig: map[string]interface{}{"protocol": "http"},
Destination: structs.DestinationConfig{
Addresses: []string{"192.168.0.2"},
Port: 80,
},
},
},
{
CorrelationID: serviceConfigIDPrefix + externalHostnameHTTP.String(),
Result: &structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
ProxyConfig: map[string]interface{}{"protocol": "http"},
Destination: structs.DestinationConfig{
Addresses: []string{"httpbin.org"},
Port: 80,
},
},
},
{
CorrelationID: serviceConfigIDPrefix + externalHostnameWithSNI.String(),
Result: &structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
ProxyConfig: map[string]interface{}{"protocol": "tcp"},
Destination: structs.DestinationConfig{
Addresses: []string{"api.test.com"},
Port: 80,
},
},
},
})
}
return testConfigSnapshotFixture(t, &structs.NodeService{
Kind: structs.ServiceKindTerminatingGateway,
Service: "terminating-gateway",
Address: "1.2.3.4",
Port: 8443,
Proxy: structs.ConnectProxyConfig{
Mode: structs.ProxyModeTransparent,
},
TaggedAddresses: map[string]structs.ServiceAddress{
structs.TaggedAddressWAN: {
Address: "198.18.0.1",
Port: 443,
},
},
}, nil, nil, testSpliceEvents(baseEvents, extraUpdates))
}
func TestConfigSnapshotTerminatingGatewayServiceSubsets(t testing.T) *ConfigSnapshot {
return testConfigSnapshotTerminatingGatewayServiceSubsets(t, false)
}
func TestConfigSnapshotTerminatingGatewayServiceSubsetsWebAndCache(t testing.T) *ConfigSnapshot {
return testConfigSnapshotTerminatingGatewayServiceSubsets(t, true)
}
func testConfigSnapshotTerminatingGatewayServiceSubsets(t testing.T, alsoAdjustCache bool) *ConfigSnapshot {
var (
web = structs.NewServiceName("web", nil)
cache = structs.NewServiceName("cache", nil)
)
events := []UpdateEvent{
{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "web",
Subsets: map[string]structs.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.version == 1",
},
"v2": {
Filter: "Service.Meta.version == 2",
OnlyPassing: true,
},
},
},
},
},
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
}
if alsoAdjustCache {
events = testSpliceEvents(events, []UpdateEvent{
{
CorrelationID: serviceResolverIDPrefix + cache.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "cache",
Subsets: map[string]structs.ServiceResolverSubset{
"prod": {
Filter: "Service.Meta.Env == prod",
},
},
},
},
},
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
})
}
return TestConfigSnapshotTerminatingGateway(t, true, nil, events)
}
func TestConfigSnapshotTerminatingGatewayDefaultServiceSubset(t testing.T) *ConfigSnapshot {
web := structs.NewServiceName("web", nil)
return TestConfigSnapshotTerminatingGateway(t, true, nil, []UpdateEvent{
{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "web",
DefaultSubset: "v2",
Subsets: map[string]structs.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.version == 1",
},
"v2": {
Filter: "Service.Meta.version == 2",
OnlyPassing: true,
},
},
},
},
},
// {
// CorrelationID: serviceConfigIDPrefix + web.String(),
// Result: &structs.ServiceConfigResponse{
// ProxyConfig: map[string]interface{}{"protocol": "http"},
// },
// },
})
}
func TestConfigSnapshotTerminatingGatewayLBConfig(t testing.T) *ConfigSnapshot {
return testConfigSnapshotTerminatingGatewayLBConfig(t, "default")
}
func TestConfigSnapshotTerminatingGatewayLBConfigNoHashPolicies(t testing.T) *ConfigSnapshot {
return testConfigSnapshotTerminatingGatewayLBConfig(t, "no-hash-policies")
}
func testConfigSnapshotTerminatingGatewayLBConfig(t testing.T, variant string) *ConfigSnapshot {
web := structs.NewServiceName("web", nil)
entry := &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "web",
DefaultSubset: "v2",
Subsets: map[string]structs.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.Version == 1",
},
"v2": {
Filter: "Service.Meta.Version == 2",
OnlyPassing: true,
},
},
RequestTimeout: 200 * time.Millisecond,
LoadBalancer: &structs.LoadBalancer{
Policy: "ring_hash",
RingHashConfig: &structs.RingHashConfig{
MinimumRingSize: 20,
MaximumRingSize: 50,
},
HashPolicies: []structs.HashPolicy{
{
Field: structs.HashPolicyCookie,
FieldValue: "chocolate-chip",
Terminal: true,
},
{
Field: structs.HashPolicyHeader,
FieldValue: "x-user-id",
},
{
SourceIP: true,
Terminal: true,
},
},
},
}
switch variant {
case "default":
case "no-hash-policies":
entry.LoadBalancer.HashPolicies = nil
default:
t.Fatalf("unknown variant %q", variant)
return nil
}
return TestConfigSnapshotTerminatingGateway(t, true, nil, []UpdateEvent{
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: entry,
},
},
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
})
}
func TestConfigSnapshotTerminatingGatewaySNI(t testing.T) *ConfigSnapshot {
return TestConfigSnapshotTerminatingGateway(t, true, nil, []UpdateEvent{
{
CorrelationID: "gateway-services",
Result: &structs.IndexedGatewayServices{
Services: []*structs.GatewayService{
{
Service: structs.NewServiceName("web", nil),
CAFile: "ca.cert.pem",
SNI: "foo.com",
},
{
Service: structs.NewServiceName("api", nil),
CAFile: "ca.cert.pem",
CertFile: "api.cert.pem",
KeyFile: "api.key.pem",
SNI: "bar.com",
},
},
},
},
})
}
func TestConfigSnapshotTerminatingGatewayHTTP2(t testing.T) *ConfigSnapshot {
web := structs.NewServiceName("web", nil)
return TestConfigSnapshotTerminatingGateway(t, false, nil, []UpdateEvent{
{
CorrelationID: gatewayServicesWatchID,
Result: &structs.IndexedGatewayServices{
Services: []*structs.GatewayService{
{
Service: web,
CAFile: "ca.cert.pem",
},
},
},
},
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http2"},
},
},
{
CorrelationID: externalServiceIDPrefix + web.String(),
Result: &structs.IndexedCheckServiceNodes{
Nodes: []structs.CheckServiceNode{
{
Node: &structs.Node{
ID: "external",
Node: "external",
Address: "web.external.service",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "web",
Port: 9090,
},
},
},
},
},
})
}
func TestConfigSnapshotTerminatingGatewaySubsetsHTTP2(t testing.T) *ConfigSnapshot {
web := structs.NewServiceName("web", nil)
return TestConfigSnapshotTerminatingGateway(t, false, nil, []UpdateEvent{
{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "web",
Subsets: map[string]structs.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.version == 1",
},
"v2": {
Filter: "Service.Meta.version == 2",
},
},
},
},
},
{
CorrelationID: gatewayServicesWatchID,
Result: &structs.IndexedGatewayServices{
Services: []*structs.GatewayService{
{
Service: web,
CAFile: "ca.cert.pem",
},
},
},
},
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http2"},
},
},
{
CorrelationID: externalServiceIDPrefix + web.String(),
Result: &structs.IndexedCheckServiceNodes{
Nodes: []structs.CheckServiceNode{
{
Node: &structs.Node{
ID: "external",
Node: "external",
Address: "web.external.service",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "web",
Port: 9090,
Meta: map[string]string{"version": "1"},
},
},
{
Node: &structs.Node{
ID: "external2",
Node: "external2",
Address: "web.external2.service",
Datacenter: "dc1",
},
Service: &structs.NodeService{
Service: "web",
Port: 9091,
Meta: map[string]string{"version": "2"},
},
},
},
},
},
})
}
func TestConfigSnapshotTerminatingGatewayHostnameSubsets(t testing.T) *ConfigSnapshot {
var (
api = structs.NewServiceName("api", nil)
cache = structs.NewServiceName("cache", nil)
)
return TestConfigSnapshotTerminatingGateway(t, true, nil, []UpdateEvent{
{
CorrelationID: serviceResolverIDPrefix + api.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "api",
Subsets: map[string]structs.ServiceResolverSubset{
"alt": {
Filter: "Service.Meta.domain == alt",
},
},
},
},
},
{
CorrelationID: serviceResolverIDPrefix + cache.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "cache",
Subsets: map[string]structs.ServiceResolverSubset{
"prod": {
Filter: "Service.Meta.Env == prod",
},
},
},
},
},
{
CorrelationID: serviceConfigIDPrefix + api.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
{
CorrelationID: serviceConfigIDPrefix + cache.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
})
}
func TestConfigSnapshotTerminatingGatewayIgnoreExtraResolvers(t testing.T) *ConfigSnapshot {
var (
web = structs.NewServiceName("web", nil)
notfound = structs.NewServiceName("notfound", nil)
)
return TestConfigSnapshotTerminatingGateway(t, true, nil, []UpdateEvent{
{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "web",
DefaultSubset: "v2",
Subsets: map[string]structs.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.Version == 1",
},
"v2": {
Filter: "Service.Meta.Version == 2",
OnlyPassing: true,
},
},
},
},
},
{
CorrelationID: serviceResolverIDPrefix + notfound.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "notfound",
DefaultSubset: "v2",
Subsets: map[string]structs.ServiceResolverSubset{
"v1": {
Filter: "Service.Meta.Version == 1",
},
"v2": {
Filter: "Service.Meta.Version == 2",
OnlyPassing: true,
},
},
},
},
},
{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
},
},
})
}
func TestConfigSnapshotTerminatingGatewayWithLambdaService(t testing.T, extraUpdateEvents ...UpdateEvent) *ConfigSnapshot {
web := structs.NewServiceName("web", nil)
updateEvents := append(extraUpdateEvents, UpdateEvent{
CorrelationID: serviceConfigIDPrefix + web.String(),
Result: &structs.ServiceConfigResponse{
ProxyConfig: map[string]interface{}{"protocol": "http"},
EnvoyExtensions: []structs.EnvoyExtension{
{
Name: api.BuiltinAWSLambdaExtension,
Arguments: map[string]interface{}{
"ARN": "arn:aws:lambda:us-east-1:111111111111:function:lambda-1234",
"PayloadPassthrough": true,
},
},
},
},
})
return TestConfigSnapshotTerminatingGateway(t, true, nil, updateEvents)
}
func TestConfigSnapshotTerminatingGatewayWithLambdaServiceAndServiceResolvers(t testing.T) *ConfigSnapshot {
web := structs.NewServiceName("web", nil)
return TestConfigSnapshotTerminatingGatewayWithLambdaService(t,
UpdateEvent{
CorrelationID: serviceResolverIDPrefix + web.String(),
Result: &structs.ConfigEntryResponse{
Entry: &structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: web.String(),
Subsets: map[string]structs.ServiceResolverSubset{
"canary1": {},
"canary2": {},
},
},
},
})
}