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.
1004 lines
26 KiB
1004 lines
26 KiB
// Copyright (c) HashiCorp, Inc. |
|
// 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", |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: api, |
|
CAFile: "ca.cert.pem", |
|
CertFile: "api.cert.pem", |
|
KeyFile: "api.key.pem", |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: db, |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: cache, |
|
AutoHostRewrite: true, |
|
}, |
|
) |
|
|
|
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, |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: externalHostnameTCP, |
|
ServiceKind: structs.GatewayServiceKindDestination, |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: externalIPHTTP, |
|
ServiceKind: structs.GatewayServiceKindDestination, |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: externalHostnameHTTP, |
|
ServiceKind: structs.GatewayServiceKindDestination, |
|
AutoHostRewrite: true, |
|
}, |
|
&structs.GatewayService{ |
|
Service: externalHostnameWithSNI, |
|
ServiceKind: structs.GatewayServiceKindDestination, |
|
CAFile: "cert.pem", |
|
SNI: "api.test.com", |
|
AutoHostRewrite: true, |
|
}, |
|
) |
|
|
|
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, nil) |
|
} |
|
func TestConfigSnapshotTerminatingGatewayServiceSubsetsWebAndCache(t testing.T, nsFn func(ns *structs.NodeService)) *ConfigSnapshot { |
|
return testConfigSnapshotTerminatingGatewayServiceSubsets(t, true, nsFn) |
|
} |
|
func testConfigSnapshotTerminatingGatewayServiceSubsets(t testing.T, alsoAdjustCache bool, nsFn func(ns *structs.NodeService)) *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, nsFn, 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", |
|
AutoHostRewrite: true, |
|
}, |
|
{ |
|
Service: structs.NewServiceName("api", nil), |
|
CAFile: "ca.cert.pem", |
|
CertFile: "api.cert.pem", |
|
KeyFile: "api.key.pem", |
|
SNI: "bar.com", |
|
AutoHostRewrite: true, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
} |
|
|
|
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", |
|
AutoHostRewrite: true, |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
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", |
|
AutoHostRewrite: true, |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
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": {}, |
|
}, |
|
}, |
|
}, |
|
}) |
|
}
|
|
|