mirror of https://github.com/hashicorp/consul
392 lines
10 KiB
Go
392 lines
10 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package proxycfg
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/mitchellh/go-testing-interface"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/hashicorp/consul/acl"
|
|
"github.com/hashicorp/consul/agent/connect"
|
|
"github.com/hashicorp/consul/agent/consul/discoverychain"
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
"github.com/hashicorp/consul/api"
|
|
"github.com/hashicorp/consul/types"
|
|
)
|
|
|
|
// TestConfigSnapshot returns a fully populated snapshot
|
|
func TestConfigSnapshot(t testing.T, nsFn func(ns *structs.NodeService), extraUpdates []UpdateEvent) *ConfigSnapshot {
|
|
roots, leaf := TestCerts(t)
|
|
|
|
// no entries implies we'll get a default chain
|
|
dbChain := discoverychain.TestCompileConfigEntries(t, "db", "default", "default", "dc1", connect.TestClusterID+".consul", nil, nil)
|
|
assert.True(t, dbChain.Default)
|
|
|
|
var (
|
|
upstreams = structs.TestUpstreams(t, false)
|
|
dbUpstream = upstreams[0]
|
|
geoUpstream = upstreams[1]
|
|
|
|
dbUID = NewUpstreamID(&dbUpstream)
|
|
geoUID = NewUpstreamID(&geoUpstream)
|
|
|
|
webSN = structs.ServiceIDString("web", nil)
|
|
)
|
|
|
|
baseEvents := []UpdateEvent{
|
|
{
|
|
CorrelationID: rootsWatchID,
|
|
Result: roots,
|
|
},
|
|
{
|
|
CorrelationID: leafWatchID,
|
|
Result: leaf,
|
|
},
|
|
{
|
|
CorrelationID: intentionsWatchID,
|
|
Result: structs.SimplifiedIntentions{}, // no intentions defined
|
|
},
|
|
{
|
|
CorrelationID: svcChecksWatchIDPrefix + webSN,
|
|
Result: []structs.CheckType{},
|
|
},
|
|
{
|
|
CorrelationID: "upstream:" + geoUID.String(),
|
|
Result: &structs.PreparedQueryExecuteResponse{
|
|
Nodes: TestPreparedQueryNodes(t, "geo-cache"),
|
|
},
|
|
},
|
|
{
|
|
CorrelationID: "discovery-chain:" + dbUID.String(),
|
|
Result: &structs.DiscoveryChainResponse{
|
|
Chain: dbChain,
|
|
},
|
|
},
|
|
{
|
|
CorrelationID: "upstream-target:" + dbChain.ID() + ":" + dbUID.String(),
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
Nodes: TestUpstreamNodes(t, "db"),
|
|
},
|
|
},
|
|
}
|
|
|
|
return testConfigSnapshotFixture(t, &structs.NodeService{
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
Service: "web-sidecar-proxy",
|
|
Port: 9999,
|
|
Proxy: structs.ConnectProxyConfig{
|
|
DestinationServiceID: "web",
|
|
DestinationServiceName: "web",
|
|
LocalServiceAddress: "127.0.0.1",
|
|
LocalServicePort: 8080,
|
|
Config: map[string]interface{}{
|
|
"foo": "bar",
|
|
},
|
|
Upstreams: upstreams,
|
|
},
|
|
Meta: nil,
|
|
TaggedAddresses: nil,
|
|
}, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates))
|
|
}
|
|
|
|
// TestConfigSnapshotDiscoveryChain returns a fully populated snapshot using a discovery chain
|
|
func TestConfigSnapshotDiscoveryChain(
|
|
t testing.T,
|
|
variation string,
|
|
enterprise bool,
|
|
nsFn func(ns *structs.NodeService),
|
|
extraUpdates []UpdateEvent,
|
|
additionalEntries ...structs.ConfigEntry,
|
|
) *ConfigSnapshot {
|
|
roots, leaf := TestCerts(t)
|
|
|
|
var entMeta acl.EnterpriseMeta
|
|
if enterprise {
|
|
entMeta = acl.NewEnterpriseMetaWithPartition("ap1", "ns1")
|
|
}
|
|
|
|
var (
|
|
upstreams = structs.TestUpstreams(t, enterprise)
|
|
geoUpstream = upstreams[1]
|
|
|
|
geoUID = NewUpstreamID(&geoUpstream)
|
|
|
|
webSN = structs.ServiceIDString("web", &entMeta)
|
|
)
|
|
|
|
baseEvents := testSpliceEvents([]UpdateEvent{
|
|
{
|
|
CorrelationID: rootsWatchID,
|
|
Result: roots,
|
|
},
|
|
{
|
|
CorrelationID: leafWatchID,
|
|
Result: leaf,
|
|
},
|
|
{
|
|
CorrelationID: intentionsWatchID,
|
|
Result: structs.SimplifiedIntentions{}, // no intentions defined
|
|
},
|
|
{
|
|
CorrelationID: meshConfigEntryID,
|
|
Result: &structs.ConfigEntryResponse{
|
|
Entry: nil,
|
|
},
|
|
},
|
|
{
|
|
CorrelationID: svcChecksWatchIDPrefix + webSN,
|
|
Result: []structs.CheckType{},
|
|
},
|
|
{
|
|
CorrelationID: "upstream:" + geoUID.String(),
|
|
Result: &structs.PreparedQueryExecuteResponse{
|
|
Nodes: TestPreparedQueryNodes(t, "geo-cache"),
|
|
},
|
|
},
|
|
}, setupTestVariationConfigEntriesAndSnapshot(
|
|
t, variation, enterprise, upstreams, additionalEntries...,
|
|
))
|
|
|
|
return testConfigSnapshotFixture(t, &structs.NodeService{
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
Service: "web-sidecar-proxy",
|
|
Port: 9999,
|
|
Proxy: structs.ConnectProxyConfig{
|
|
DestinationServiceID: "web",
|
|
DestinationServiceName: "web",
|
|
LocalServiceAddress: "127.0.0.1",
|
|
LocalServicePort: 8080,
|
|
Config: map[string]interface{}{
|
|
"foo": "bar",
|
|
},
|
|
Upstreams: upstreams,
|
|
},
|
|
Meta: nil,
|
|
TaggedAddresses: nil,
|
|
EnterpriseMeta: entMeta,
|
|
}, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates))
|
|
}
|
|
|
|
func TestConfigSnapshotExposeConfig(t testing.T, nsFn func(ns *structs.NodeService)) *ConfigSnapshot {
|
|
roots, leaf := TestCerts(t)
|
|
|
|
var (
|
|
webSN = structs.ServiceIDString("web", nil)
|
|
)
|
|
|
|
baseEvents := []UpdateEvent{
|
|
{
|
|
CorrelationID: rootsWatchID,
|
|
Result: roots,
|
|
},
|
|
{
|
|
CorrelationID: leafWatchID, Result: leaf,
|
|
},
|
|
{
|
|
CorrelationID: intentionsWatchID,
|
|
Result: structs.SimplifiedIntentions{}, // no intentions defined
|
|
},
|
|
{
|
|
CorrelationID: svcChecksWatchIDPrefix + webSN,
|
|
Result: []structs.CheckType{},
|
|
},
|
|
}
|
|
|
|
return testConfigSnapshotFixture(t, &structs.NodeService{
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
Service: "web-sidecar-proxy",
|
|
Address: "1.2.3.4",
|
|
Port: 8080,
|
|
Proxy: structs.ConnectProxyConfig{
|
|
DestinationServiceID: "web",
|
|
DestinationServiceName: "web",
|
|
LocalServicePort: 8080,
|
|
Expose: structs.ExposeConfig{
|
|
Checks: false,
|
|
Paths: []structs.ExposePath{
|
|
{
|
|
LocalPathPort: 8080,
|
|
Path: "/health1",
|
|
ListenerPort: 21500,
|
|
},
|
|
{
|
|
LocalPathPort: 8080,
|
|
Path: "/health2",
|
|
ListenerPort: 21501,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Meta: nil,
|
|
TaggedAddresses: nil,
|
|
}, nsFn, nil, baseEvents)
|
|
}
|
|
|
|
func TestConfigSnapshotExposeChecks(t testing.T) *ConfigSnapshot {
|
|
return testConfigSnapshotExposedChecks(t, false)
|
|
}
|
|
|
|
func TestConfigSnapshotExposeChecksWithBindOverride(t testing.T) *ConfigSnapshot {
|
|
return testConfigSnapshotExposedChecks(t, true)
|
|
}
|
|
|
|
func testConfigSnapshotExposedChecks(t testing.T, overrideBind bool) *ConfigSnapshot {
|
|
return TestConfigSnapshot(t,
|
|
func(ns *structs.NodeService) {
|
|
ns.Address = "1.2.3.4"
|
|
ns.Port = 8080
|
|
ns.Proxy.Upstreams = nil
|
|
ns.Proxy.Expose = structs.ExposeConfig{
|
|
Checks: true,
|
|
}
|
|
if overrideBind {
|
|
if ns.Proxy.Config == nil {
|
|
ns.Proxy.Config = map[string]any{}
|
|
}
|
|
ns.Proxy.Config["bind_address"] = "6.7.8.9"
|
|
}
|
|
},
|
|
[]UpdateEvent{
|
|
{
|
|
CorrelationID: svcChecksWatchIDPrefix + structs.ServiceIDString("web", nil),
|
|
Result: []structs.CheckType{{
|
|
CheckID: types.CheckID("http"),
|
|
Name: "http",
|
|
HTTP: "http://127.0.0.1:8181/debug",
|
|
ProxyHTTP: "http://:21500/debug",
|
|
Method: "GET",
|
|
Interval: 10 * time.Second,
|
|
Timeout: 1 * time.Second,
|
|
}},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestConfigSnapshotExposeChecksGRPC(t testing.T) *ConfigSnapshot {
|
|
return TestConfigSnapshot(t,
|
|
func(ns *structs.NodeService) {
|
|
ns.Address = "1.2.3.4"
|
|
ns.Port = 9090
|
|
ns.Proxy.Upstreams = nil
|
|
ns.Proxy.Expose = structs.ExposeConfig{
|
|
Checks: true,
|
|
}
|
|
},
|
|
[]UpdateEvent{
|
|
{
|
|
CorrelationID: svcChecksWatchIDPrefix + structs.ServiceIDString("web", nil),
|
|
Result: []structs.CheckType{{
|
|
CheckID: types.CheckID("grpc"),
|
|
Name: "grpc",
|
|
GRPC: "localhost:9090/v1.Health",
|
|
ProxyGRPC: "localhost:21501/myservice",
|
|
Interval: 10 * time.Second,
|
|
Timeout: 1 * time.Second,
|
|
}},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestConfigSnapshotGRPCExposeHTTP1(t testing.T) *ConfigSnapshot {
|
|
roots, leaf := TestCerts(t)
|
|
|
|
return testConfigSnapshotFixture(t, &structs.NodeService{
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
Service: "grpc-proxy",
|
|
Address: "1.2.3.4",
|
|
Port: 8080,
|
|
Proxy: structs.ConnectProxyConfig{
|
|
DestinationServiceName: "grpc",
|
|
DestinationServiceID: "grpc",
|
|
LocalServicePort: 8080,
|
|
Config: map[string]interface{}{
|
|
"protocol": "grpc",
|
|
},
|
|
Expose: structs.ExposeConfig{
|
|
Checks: false,
|
|
Paths: []structs.ExposePath{
|
|
{
|
|
LocalPathPort: 8090,
|
|
Path: "/healthz",
|
|
ListenerPort: 21500,
|
|
Protocol: "http",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Meta: nil,
|
|
TaggedAddresses: nil,
|
|
}, nil, nil, []UpdateEvent{
|
|
{
|
|
CorrelationID: rootsWatchID,
|
|
Result: roots,
|
|
},
|
|
{
|
|
CorrelationID: leafWatchID,
|
|
Result: leaf,
|
|
},
|
|
{
|
|
CorrelationID: intentionsWatchID,
|
|
Result: structs.SimplifiedIntentions{}, // no intentions defined
|
|
},
|
|
{
|
|
CorrelationID: svcChecksWatchIDPrefix + structs.ServiceIDString("grpc", nil),
|
|
Result: []structs.CheckType{},
|
|
},
|
|
})
|
|
}
|
|
|
|
// TestConfigSnapshotTelemetryCollector returns a fully populated snapshot using a discovery chain
|
|
func TestConfigSnapshotTelemetryCollector(t testing.T) *ConfigSnapshot {
|
|
// DiscoveryChain without an UpstreamConfig should yield a
|
|
// filter chain when in transparent proxy mode
|
|
var (
|
|
collector = structs.NewServiceName(api.TelemetryCollectorName, nil)
|
|
collectorUID = NewUpstreamIDFromServiceName(collector)
|
|
collectorChain = discoverychain.TestCompileConfigEntries(t, api.TelemetryCollectorName, "default", "default", "dc1", connect.TestClusterID+".consul", nil, nil)
|
|
)
|
|
|
|
return TestConfigSnapshot(t, func(ns *structs.NodeService) {
|
|
ns.Proxy.Config = map[string]interface{}{
|
|
"envoy_telemetry_collector_bind_socket_dir": "/tmp/consul/telemetry-collector",
|
|
}
|
|
}, []UpdateEvent{
|
|
{
|
|
CorrelationID: meshConfigEntryID,
|
|
Result: &structs.ConfigEntryResponse{
|
|
Entry: nil,
|
|
},
|
|
},
|
|
{
|
|
CorrelationID: "discovery-chain:" + collectorUID.String(),
|
|
Result: &structs.DiscoveryChainResponse{
|
|
Chain: collectorChain,
|
|
},
|
|
},
|
|
{
|
|
CorrelationID: fmt.Sprintf("upstream-target:%s.default.default.dc1:", api.TelemetryCollectorName) + collectorUID.String(),
|
|
Result: &structs.IndexedCheckServiceNodes{
|
|
Nodes: []structs.CheckServiceNode{
|
|
{
|
|
Node: &structs.Node{
|
|
Address: "8.8.8.8",
|
|
Datacenter: "dc1",
|
|
},
|
|
Service: &structs.NodeService{
|
|
Service: api.TelemetryCollectorName,
|
|
Address: "9.9.9.9",
|
|
Port: 9090,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|