mirror of https://github.com/status-im/consul.git
Allow HCP metrics collection for Envoy proxies
Co-authored-by: Ashvitha Sridharan <ashvitha.sridharan@hashicorp.com> Co-authored-by: Freddy <freddygv@users.noreply.github.com> Add a new envoy flag: "envoy_hcp_metrics_bind_socket_dir", a directory where a unix socket will be created with the name `<namespace>_<proxy_id>.sock` to forward Envoy metrics. If set, this will configure: - In bootstrap configuration a local stats_sink and static cluster. These will forward metrics to a loopback listener sent over xDS. - A dynamic listener listening at the socket path that the previously defined static cluster is sending metrics to. - A dynamic cluster that will forward traffic received at this listener to the hcp-metrics-collector service. Reasons for having a static cluster pointing at a dynamic listener: - We want to secure the metrics stream using TLS, but the stats sink can only be defined in bootstrap config. With dynamic listeners/clusters we can use the proxy's leaf certificate issued by the Connect CA, which isn't available at bootstrap time. - We want to intelligently route to the HCP collector. Configuring its addreess at bootstrap time limits our flexibility routing-wise. More on this below. Reasons for defining the collector as an upstream in `proxycfg`: - The HCP collector will be deployed as a mesh service. - Certificate management is taken care of, as mentioned above. - Service discovery and routing logic is automatically taken care of, meaning that no code changes are required in the xds package. - Custom routing rules can be added for the collector using discovery chain config entries. Initially the collector is expected to be deployed to each admin partition, but in the future could be deployed centrally in the default partition. These config entries could even be managed by HCP itself.
This commit is contained in:
parent
726c97b2bd
commit
f95ffe0355
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
xds: Allow for configuring connect proxies to send service mesh telemetry to an HCP metrics collection service.
|
||||
```
|
|
@ -3,12 +3,16 @@ package proxycfg
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
"github.com/hashicorp/consul/agent/proxycfg/internal/watch"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/proto/private/pbpeering"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
type handlerConnectProxy struct {
|
||||
|
@ -103,6 +107,10 @@ func (s *handlerConnectProxy) initialize(ctx context.Context) (ConfigSnapshot, e
|
|||
return snap, err
|
||||
}
|
||||
|
||||
if err := s.maybeInitializeHCPMetricsWatches(ctx, snap); err != nil {
|
||||
return snap, fmt.Errorf("failed to initialize HCP metrics watches: %w", err)
|
||||
}
|
||||
|
||||
if s.proxyCfg.Mode == structs.ProxyModeTransparent {
|
||||
// When in transparent proxy we will infer upstreams from intentions with this source
|
||||
err := s.dataSources.IntentionUpstreams.Notify(ctx, &structs.ServiceSpecificRequest{
|
||||
|
@ -614,3 +622,66 @@ func (s *handlerConnectProxy) handleUpdate(ctx context.Context, u UpdateEvent, s
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// hcpMetricsConfig represents the basic opaque config values for pushing telemetry to HCP.
|
||||
type hcpMetricsConfig struct {
|
||||
// HCPMetricsBindSocketDir is a string that configures the directory for a
|
||||
// unix socket where Envoy will forward metrics. These metrics get pushed to
|
||||
// the HCP Metrics collector to show service mesh metrics on HCP.
|
||||
HCPMetricsBindSocketDir string `mapstructure:"envoy_hcp_metrics_bind_socket_dir"`
|
||||
}
|
||||
|
||||
func parseHCPMetricsConfig(m map[string]interface{}) (hcpMetricsConfig, error) {
|
||||
var cfg hcpMetricsConfig
|
||||
err := mapstructure.WeakDecode(m, &cfg)
|
||||
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("failed to decode: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// maybeInitializeHCPMetricsWatches will initialize a synthetic upstream and discovery chain
|
||||
// watch for the HCP metrics collector, if metrics collection is enabled on the proxy registration.
|
||||
func (s *handlerConnectProxy) maybeInitializeHCPMetricsWatches(ctx context.Context, snap ConfigSnapshot) error {
|
||||
hcpCfg, err := parseHCPMetricsConfig(s.proxyCfg.Config)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to parse connect.proxy.config", "error", err)
|
||||
}
|
||||
|
||||
if hcpCfg.HCPMetricsBindSocketDir == "" {
|
||||
// Metrics collection is not enabled, return early.
|
||||
return nil
|
||||
}
|
||||
|
||||
// The path includes the proxy ID so that when multiple proxies are on the same host
|
||||
// they each have a distinct path to send their metrics.
|
||||
sock := fmt.Sprintf("%s_%s.sock", s.proxyID.NamespaceOrDefault(), s.proxyID.ID)
|
||||
path := path.Join(hcpCfg.HCPMetricsBindSocketDir, sock)
|
||||
|
||||
upstream := structs.Upstream{
|
||||
DestinationNamespace: acl.DefaultNamespaceName,
|
||||
DestinationPartition: s.proxyID.PartitionOrDefault(),
|
||||
DestinationName: api.HCPMetricsCollectorName,
|
||||
LocalBindSocketPath: path,
|
||||
Config: map[string]interface{}{
|
||||
"protocol": "grpc",
|
||||
},
|
||||
}
|
||||
uid := NewUpstreamID(&upstream)
|
||||
snap.ConnectProxy.UpstreamConfig[uid] = &upstream
|
||||
|
||||
err = s.dataSources.CompiledDiscoveryChain.Notify(ctx, &structs.DiscoveryChainRequest{
|
||||
Datacenter: s.source.Datacenter,
|
||||
QueryOptions: structs.QueryOptions{Token: s.token},
|
||||
Name: upstream.DestinationName,
|
||||
EvaluateInDatacenter: s.source.Datacenter,
|
||||
EvaluateInNamespace: uid.NamespaceOrDefault(),
|
||||
EvaluateInPartition: uid.PartitionOrDefault(),
|
||||
}, "discovery-chain:"+uid.String(), s.ch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to watch discovery chain for %s: %v", uid.String(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,14 +7,16 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
||||
|
||||
"github.com/hashicorp/consul/agent/consul/discoverychain"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
apimod "github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/proto/private/pbpeering"
|
||||
"github.com/hashicorp/consul/proto/private/prototest"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
|
@ -455,16 +457,18 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
|||
|
||||
// Used to account for differences in OSS/ent implementations of ServiceID.String()
|
||||
var (
|
||||
db = structs.NewServiceName("db", nil)
|
||||
billing = structs.NewServiceName("billing", nil)
|
||||
api = structs.NewServiceName("api", nil)
|
||||
apiA = structs.NewServiceName("api-a", nil)
|
||||
db = structs.NewServiceName("db", nil)
|
||||
billing = structs.NewServiceName("billing", nil)
|
||||
api = structs.NewServiceName("api", nil)
|
||||
apiA = structs.NewServiceName("api-a", nil)
|
||||
hcpCollector = structs.NewServiceName(apimod.HCPMetricsCollectorName, nil)
|
||||
|
||||
apiUID = NewUpstreamIDFromServiceName(api)
|
||||
dbUID = NewUpstreamIDFromServiceName(db)
|
||||
pqUID = UpstreamIDFromString("prepared_query:query")
|
||||
extApiUID = NewUpstreamIDFromServiceName(apiA)
|
||||
extDBUID = NewUpstreamIDFromServiceName(db)
|
||||
apiUID = NewUpstreamIDFromServiceName(api)
|
||||
dbUID = NewUpstreamIDFromServiceName(db)
|
||||
pqUID = UpstreamIDFromString("prepared_query:query")
|
||||
extApiUID = NewUpstreamIDFromServiceName(apiA)
|
||||
extDBUID = NewUpstreamIDFromServiceName(db)
|
||||
hcpCollectorUID = NewUpstreamIDFromServiceName(hcpCollector)
|
||||
)
|
||||
// TODO(peering): NewUpstreamIDFromServiceName should take a PeerName
|
||||
extApiUID.Peer = "peer-a"
|
||||
|
@ -3623,6 +3627,164 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"hcp-metrics": {
|
||||
ns: structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Address: "10.0.1.1",
|
||||
Port: 443,
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "web",
|
||||
Config: map[string]interface{}{
|
||||
"envoy_hcp_metrics_bind_socket_dir": "/tmp/consul/hcp-metrics/",
|
||||
},
|
||||
},
|
||||
},
|
||||
sourceDC: "dc1",
|
||||
stages: []verificationStage{
|
||||
{
|
||||
requiredWatches: map[string]verifyWatchRequest{
|
||||
fmt.Sprintf("discovery-chain:%s", hcpCollectorUID.String()): genVerifyDiscoveryChainWatch(&structs.DiscoveryChainRequest{
|
||||
Name: hcpCollector.Name,
|
||||
EvaluateInDatacenter: "dc1",
|
||||
EvaluateInNamespace: "default",
|
||||
EvaluateInPartition: "default",
|
||||
Datacenter: "dc1",
|
||||
QueryOptions: structs.QueryOptions{
|
||||
Token: aclToken,
|
||||
},
|
||||
}),
|
||||
},
|
||||
verifySnapshot: func(t testing.TB, snap *ConfigSnapshot) {
|
||||
require.False(t, snap.Valid(), "should not be valid")
|
||||
|
||||
require.Len(t, snap.ConnectProxy.DiscoveryChain, 0, "%+v", snap.ConnectProxy.DiscoveryChain)
|
||||
require.Len(t, snap.ConnectProxy.WatchedDiscoveryChains, 0, "%+v", snap.ConnectProxy.WatchedDiscoveryChains)
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreams, 0, "%+v", snap.ConnectProxy.WatchedUpstreams)
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreamEndpoints, 0, "%+v", snap.ConnectProxy.WatchedUpstreamEndpoints)
|
||||
},
|
||||
},
|
||||
{
|
||||
events: []UpdateEvent{
|
||||
rootWatchEvent(),
|
||||
{
|
||||
CorrelationID: peeringTrustBundlesWatchID,
|
||||
Result: peerTrustBundles,
|
||||
},
|
||||
{
|
||||
CorrelationID: leafWatchID,
|
||||
Result: issuedCert,
|
||||
Err: nil,
|
||||
},
|
||||
{
|
||||
CorrelationID: intentionsWatchID,
|
||||
Result: TestIntentions(),
|
||||
Err: nil,
|
||||
},
|
||||
{
|
||||
CorrelationID: meshConfigEntryID,
|
||||
Result: &structs.ConfigEntryResponse{},
|
||||
},
|
||||
{
|
||||
CorrelationID: fmt.Sprintf("discovery-chain:%s", hcpCollectorUID.String()),
|
||||
Result: &structs.DiscoveryChainResponse{
|
||||
Chain: discoverychain.TestCompileConfigEntries(t, hcpCollector.Name, "default", "default", "dc1", "trustdomain.consul", nil),
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
},
|
||||
verifySnapshot: func(t testing.TB, snap *ConfigSnapshot) {
|
||||
require.True(t, snap.Valid())
|
||||
require.Equal(t, indexedRoots, snap.Roots)
|
||||
require.Equal(t, issuedCert, snap.ConnectProxy.Leaf)
|
||||
|
||||
// An event was received with the HCP collector's discovery chain, which sets up some bookkeeping in the snapshot.
|
||||
require.Len(t, snap.ConnectProxy.DiscoveryChain, 1, "%+v", snap.ConnectProxy.DiscoveryChain)
|
||||
require.Contains(t, snap.ConnectProxy.DiscoveryChain, hcpCollectorUID)
|
||||
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreams, 1, "%+v", snap.ConnectProxy.WatchedUpstreams)
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreamEndpoints, 1, "%+v", snap.ConnectProxy.WatchedUpstreamEndpoints)
|
||||
require.Contains(t, snap.ConnectProxy.WatchedUpstreamEndpoints, hcpCollectorUID)
|
||||
|
||||
expectUpstream := structs.Upstream{
|
||||
DestinationNamespace: "default",
|
||||
DestinationPartition: "default",
|
||||
DestinationName: apimod.HCPMetricsCollectorName,
|
||||
LocalBindSocketPath: "/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock",
|
||||
Config: map[string]interface{}{
|
||||
"protocol": "grpc",
|
||||
},
|
||||
}
|
||||
uid := NewUpstreamID(&expectUpstream)
|
||||
|
||||
require.Contains(t, snap.ConnectProxy.UpstreamConfig, uid)
|
||||
require.Equal(t, &expectUpstream, snap.ConnectProxy.UpstreamConfig[uid])
|
||||
|
||||
// No endpoints have arrived yet.
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreamEndpoints[hcpCollectorUID], 0, "%+v", snap.ConnectProxy.WatchedUpstreamEndpoints)
|
||||
},
|
||||
},
|
||||
{
|
||||
requiredWatches: map[string]verifyWatchRequest{
|
||||
fmt.Sprintf("upstream-target:%s.default.default.dc1:", apimod.HCPMetricsCollectorName) + hcpCollectorUID.String(): genVerifyServiceSpecificRequest(apimod.HCPMetricsCollectorName, "", "dc1", true),
|
||||
},
|
||||
events: []UpdateEvent{
|
||||
{
|
||||
CorrelationID: fmt.Sprintf("upstream-target:%s.default.default.dc1:", apimod.HCPMetricsCollectorName) + hcpCollectorUID.String(),
|
||||
Result: &structs.IndexedCheckServiceNodes{
|
||||
Nodes: structs.CheckServiceNodes{
|
||||
{
|
||||
Node: &structs.Node{
|
||||
Node: "node1",
|
||||
Address: "10.0.0.1",
|
||||
},
|
||||
Service: &structs.NodeService{
|
||||
ID: apimod.HCPMetricsCollectorName,
|
||||
Service: apimod.HCPMetricsCollectorName,
|
||||
Port: 8080,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Err: nil,
|
||||
},
|
||||
},
|
||||
verifySnapshot: func(t testing.TB, snap *ConfigSnapshot) {
|
||||
require.True(t, snap.Valid())
|
||||
require.Equal(t, indexedRoots, snap.Roots)
|
||||
require.Equal(t, issuedCert, snap.ConnectProxy.Leaf)
|
||||
|
||||
// Discovery chain for the HCP collector should still be stored in the snapshot.
|
||||
require.Len(t, snap.ConnectProxy.DiscoveryChain, 1, "%+v", snap.ConnectProxy.DiscoveryChain)
|
||||
require.Contains(t, snap.ConnectProxy.DiscoveryChain, hcpCollectorUID)
|
||||
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreams, 1, "%+v", snap.ConnectProxy.WatchedUpstreams)
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreamEndpoints, 1, "%+v", snap.ConnectProxy.WatchedUpstreamEndpoints)
|
||||
require.Contains(t, snap.ConnectProxy.WatchedUpstreamEndpoints, hcpCollectorUID)
|
||||
|
||||
// An endpoint arrived for the HCP collector, so it should be present in the snapshot.
|
||||
require.Len(t, snap.ConnectProxy.WatchedUpstreamEndpoints[hcpCollectorUID], 1, "%+v", snap.ConnectProxy.WatchedUpstreamEndpoints)
|
||||
|
||||
nodes := structs.CheckServiceNodes{
|
||||
{
|
||||
Node: &structs.Node{
|
||||
Node: "node1",
|
||||
Address: "10.0.0.1",
|
||||
},
|
||||
Service: &structs.NodeService{
|
||||
ID: apimod.HCPMetricsCollectorName,
|
||||
Service: apimod.HCPMetricsCollectorName,
|
||||
Port: 8080,
|
||||
},
|
||||
},
|
||||
}
|
||||
target := fmt.Sprintf("%s.default.default.dc1", apimod.HCPMetricsCollectorName)
|
||||
require.Equal(t, nodes, snap.ConnectProxy.WatchedUpstreamEndpoints[hcpCollectorUID][target])
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package proxycfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
"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"
|
||||
)
|
||||
|
||||
|
@ -288,3 +290,51 @@ func TestConfigSnapshotGRPCExposeHTTP1(t testing.T) *ConfigSnapshot {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
// TestConfigSnapshotDiscoveryChain returns a fully populated snapshot using a discovery chain
|
||||
func TestConfigSnapshotHCPMetrics(t testing.T) *ConfigSnapshot {
|
||||
// DiscoveryChain without an UpstreamConfig should yield a
|
||||
// filter chain when in transparent proxy mode
|
||||
var (
|
||||
collector = structs.NewServiceName(api.HCPMetricsCollectorName, nil)
|
||||
collectorUID = NewUpstreamIDFromServiceName(collector)
|
||||
collectorChain = discoverychain.TestCompileConfigEntries(t, api.HCPMetricsCollectorName, "default", "default", "dc1", connect.TestClusterID+".consul", nil)
|
||||
)
|
||||
|
||||
return TestConfigSnapshot(t, func(ns *structs.NodeService) {
|
||||
ns.Proxy.Config = map[string]interface{}{
|
||||
"envoy_hcp_metrics_bind_socket_dir": "/tmp/consul/hcp-metrics",
|
||||
}
|
||||
}, []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.HCPMetricsCollectorName) + collectorUID.String(),
|
||||
Result: &structs.IndexedCheckServiceNodes{
|
||||
Nodes: []structs.CheckServiceNode{
|
||||
{
|
||||
Node: &structs.Node{
|
||||
Address: "8.8.8.8",
|
||||
Datacenter: "dc1",
|
||||
},
|
||||
Service: &structs.NodeService{
|
||||
Service: api.HCPMetricsCollectorName,
|
||||
Address: "9.9.9.9",
|
||||
Port: 9090,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -166,6 +166,10 @@ func TestAllResourcesFromSnapshot(t *testing.T) {
|
|||
name: "local-mesh-gateway-with-peered-upstreams",
|
||||
create: proxycfg.TestConfigSnapshotPeeringLocalMeshGateway,
|
||||
},
|
||||
{
|
||||
name: "hcp-metrics",
|
||||
create: proxycfg.TestConfigSnapshotHCPMetrics,
|
||||
},
|
||||
}
|
||||
tests = append(tests, getConnectProxyTransparentProxyGoldenTestCases()...)
|
||||
tests = append(tests, getMeshGatewayPeeringGoldenTestCases()...)
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"commonLbConfig": {
|
||||
"healthyPanicThreshold": {}
|
||||
},
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"validationContext": {
|
||||
"trustedCa": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"matchSubjectAltNames": [
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/db"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"outlierDetection": {},
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"validationContext": {
|
||||
"trustedCa": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"matchSubjectAltNames": [
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/geo-cache-target"
|
||||
},
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc2/svc/geo-cache-target"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "hcp-metrics-collector.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"altStatName": "hcp-metrics-collector.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"type": "EDS",
|
||||
"edsClusterConfig": {
|
||||
"edsConfig": {
|
||||
"ads": {},
|
||||
"resourceApiVersion": "V3"
|
||||
}
|
||||
},
|
||||
"connectTimeout": "5s",
|
||||
"circuitBreakers": {},
|
||||
"typedExtensionProtocolOptions": {
|
||||
"envoy.extensions.upstreams.http.v3.HttpProtocolOptions": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions",
|
||||
"explicitHttpConfig": {
|
||||
"http2ProtocolOptions": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"outlierDetection": {},
|
||||
"commonLbConfig": {
|
||||
"healthyPanicThreshold": {}
|
||||
},
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"validationContext": {
|
||||
"trustedCa": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"matchSubjectAltNames": [
|
||||
{
|
||||
"exact": "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/dc1/svc/hcp-metrics-collector"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"sni": "hcp-metrics-collector.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"name": "local_app",
|
||||
"type": "STATIC",
|
||||
"connectTimeout": "5s",
|
||||
"loadAssignment": {
|
||||
"clusterName": "local_app",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.10.1.1",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
},
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "10.20.1.2",
|
||||
"portValue": 8080
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"clusterName": "hcp-metrics-collector.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "9.9.9.9",
|
||||
"portValue": 9090
|
||||
}
|
||||
}
|
||||
},
|
||||
"healthStatus": "HEALTHY",
|
||||
"loadBalancingWeight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"resources": [
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "db:127.0.0.1:9191",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.0.0.1",
|
||||
"portValue": 9191
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.db.default.default.dc1",
|
||||
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "hcp-metrics-collector:/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock",
|
||||
"address": {
|
||||
"pipe": {
|
||||
"path": "/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock"
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.http_connection_manager",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
|
||||
"statPrefix": "upstream.hcp-metrics-collector.default.default.dc1",
|
||||
"routeConfig": {
|
||||
"name": "hcp-metrics-collector",
|
||||
"virtualHosts": [
|
||||
{
|
||||
"name": "hcp-metrics-collector.default.default.dc1",
|
||||
"domains": [
|
||||
"*"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"prefix": "/"
|
||||
},
|
||||
"route": {
|
||||
"cluster": "hcp-metrics-collector.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "127.10.10.10",
|
||||
"portValue": 8181
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trafficDirection": "OUTBOUND"
|
||||
},
|
||||
{
|
||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"name": "public_listener:0.0.0.0:9999",
|
||||
"address": {
|
||||
"socketAddress": {
|
||||
"address": "0.0.0.0",
|
||||
"portValue": 9999
|
||||
}
|
||||
},
|
||||
"filterChains": [
|
||||
{
|
||||
"filters": [
|
||||
{
|
||||
"name": "envoy.filters.network.rbac",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC",
|
||||
"rules": {},
|
||||
"statPrefix": "connect_authz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "envoy.filters.network.tcp_proxy",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||
"statPrefix": "public_listener",
|
||||
"cluster": "local_app"
|
||||
}
|
||||
}
|
||||
],
|
||||
"transportSocket": {
|
||||
"name": "tls",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||
"commonTlsContext": {
|
||||
"tlsParams": {},
|
||||
"tlsCertificates": [
|
||||
{
|
||||
"certificateChain": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||
},
|
||||
"privateKey": {
|
||||
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"validationContext": {
|
||||
"trustedCa": {
|
||||
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requireClientCertificate": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"trafficDirection": "INBOUND"
|
||||
}
|
||||
],
|
||||
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"versionInfo": "00000001",
|
||||
"typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
|
||||
"nonce": "00000001"
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
package api
|
||||
|
||||
// HCPMetricsCollectorName is the service name for the HCP Metrics Collector
|
||||
const HCPMetricsCollectorName string = "hcp-metrics-collector"
|
||||
|
||||
// Connect can be used to work with endpoints related to Connect, the
|
||||
// feature for securely connecting services within Consul.
|
||||
type Connect struct {
|
||||
|
|
|
@ -7,9 +7,11 @@ import (
|
|||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/api"
|
||||
)
|
||||
|
||||
|
@ -49,6 +51,11 @@ type BootstrapConfig struct {
|
|||
// stats_config.stats_tags can be made by overriding envoy_stats_config_json.
|
||||
StatsTags []string `mapstructure:"envoy_stats_tags"`
|
||||
|
||||
// HCPMetricsBindSocketDir is a string that configures the directory for a
|
||||
// unix socket where Envoy will forward metrics. These metrics get pushed to
|
||||
// the HCP Metrics collector to show service mesh metrics on HCP.
|
||||
HCPMetricsBindSocketDir string `mapstructure:"envoy_hcp_metrics_bind_socket_dir"`
|
||||
|
||||
// PrometheusBindAddr configures an <ip>:<port> on which the Envoy will listen
|
||||
// and expose a single /metrics HTTP endpoint for Prometheus to scrape. It
|
||||
// does this by proxying that URL to the internal admin server's prometheus
|
||||
|
@ -238,6 +245,11 @@ func (c *BootstrapConfig) ConfigureArgs(args *BootstrapTplArgs, omitDeprecatedTa
|
|||
args.StatsFlushInterval = c.StatsFlushInterval
|
||||
}
|
||||
|
||||
// Setup HCP Metrics if needed. This MUST happen after the Static*JSON is set above
|
||||
if c.HCPMetricsBindSocketDir != "" {
|
||||
appendHCPMetricsConfig(args, c.HCPMetricsBindSocketDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -271,7 +283,7 @@ func (c *BootstrapConfig) generateStatsSinks(args *BootstrapTplArgs) error {
|
|||
}
|
||||
|
||||
if len(stats_sinks) > 0 {
|
||||
args.StatsSinksJSON = "[\n" + strings.Join(stats_sinks, ",\n") + "\n]"
|
||||
args.StatsSinksJSON = strings.Join(stats_sinks, ",\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -796,6 +808,58 @@ func (c *BootstrapConfig) generateListenerConfig(args *BootstrapTplArgs, bindAdd
|
|||
return nil
|
||||
}
|
||||
|
||||
// appendHCPMetricsConfig generates config to enable a socket at path: <hcpMetricsBindSocketDir>/<namespace>_<proxy_id>.sock
|
||||
// or <hcpMetricsBindSocketDir>/<proxy_id>.sock, if namespace is empty.
|
||||
func appendHCPMetricsConfig(args *BootstrapTplArgs, hcpMetricsBindSocketDir string) {
|
||||
// Normalize namespace to "default". This ensures we match the namespace behaviour in proxycfg package,
|
||||
// where a dynamic listener will be created at the same socket path via xDS.
|
||||
sock := fmt.Sprintf("%s_%s.sock", acl.NamespaceOrDefault(args.Namespace), args.ProxyID)
|
||||
path := path.Join(hcpMetricsBindSocketDir, sock)
|
||||
|
||||
if args.StatsSinksJSON != "" {
|
||||
args.StatsSinksJSON += ",\n"
|
||||
}
|
||||
args.StatsSinksJSON += `{
|
||||
"name": "envoy.stat_sinks.metrics_service",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig",
|
||||
"transport_api_version": "V3",
|
||||
"grpc_service": {
|
||||
"envoy_grpc": {
|
||||
"cluster_name": "hcp_metrics_collector"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
if args.StaticClustersJSON != "" {
|
||||
args.StaticClustersJSON += ",\n"
|
||||
}
|
||||
args.StaticClustersJSON += fmt.Sprintf(`{
|
||||
"name": "hcp_metrics_collector",
|
||||
"type": "STATIC",
|
||||
"http2_protocol_options": {},
|
||||
"loadAssignment": {
|
||||
"clusterName": "hcp_metrics_collector",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"pipe": {
|
||||
"path": "%s"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}`, path)
|
||||
}
|
||||
|
||||
func containsSelfAdminCluster(clustersJSON string) (bool, error) {
|
||||
clusterNames := []struct {
|
||||
Name string
|
||||
|
|
|
@ -513,6 +513,56 @@ const (
|
|||
}
|
||||
]
|
||||
}`
|
||||
|
||||
expectedStatsdSink = `{
|
||||
"name": "envoy.stat_sinks.statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.StatsdSink",
|
||||
"address": {
|
||||
"socket_address": {
|
||||
"address": "127.0.0.1",
|
||||
"port_value": 9125
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
expectedHCPMetricsStatsSink = `{
|
||||
"name": "envoy.stat_sinks.metrics_service",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig",
|
||||
"transport_api_version": "V3",
|
||||
"grpc_service": {
|
||||
"envoy_grpc": {
|
||||
"cluster_name": "hcp_metrics_collector"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
expectedHCPMetricsCluster = `{
|
||||
"name": "hcp_metrics_collector",
|
||||
"type": "STATIC",
|
||||
"http2_protocol_options": {},
|
||||
"loadAssignment": {
|
||||
"clusterName": "hcp_metrics_collector",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"pipe": {
|
||||
"path": "/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
)
|
||||
|
||||
func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
||||
|
@ -557,14 +607,63 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.custom_exciting_sink",
|
||||
"config": {
|
||||
"foo": "bar"
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hcp-metrics-sink",
|
||||
baseArgs: BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
},
|
||||
input: BootstrapConfig{
|
||||
HCPMetricsBindSocketDir: "/tmp/consul/hcp-metrics",
|
||||
},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.metrics_service",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig",
|
||||
"transport_api_version": "V3",
|
||||
"grpc_service": {
|
||||
"envoy_grpc": {
|
||||
"cluster_name": "hcp_metrics_collector"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
StaticClustersJSON: `{
|
||||
"name": "hcp_metrics_collector",
|
||||
"type": "STATIC",
|
||||
"http2_protocol_options": {},
|
||||
"loadAssignment": {
|
||||
"clusterName": "hcp_metrics_collector",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"pipe": {
|
||||
"path": "/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "simple-statsd-sink",
|
||||
input: BootstrapConfig{
|
||||
|
@ -572,18 +671,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
"name": "envoy.stat_sinks.statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.StatsdSink",
|
||||
"address": {
|
||||
"socket_address": {
|
||||
"address": "127.0.0.1",
|
||||
"port_value": 9125
|
||||
}
|
||||
}
|
||||
}
|
||||
}]`,
|
||||
StatsSinksJSON: expectedStatsdSink,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -600,7 +688,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.StatsdSink",
|
||||
|
@ -617,7 +705,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
"config": {
|
||||
"foo": "bar"
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -629,7 +717,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
env: []string{"MY_STATSD_URL=udp://127.0.0.1:9125"},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.StatsdSink",
|
||||
|
@ -640,7 +728,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -652,7 +740,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
env: []string{"HOST_IP=127.0.0.1"},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.StatsdSink",
|
||||
|
@ -663,7 +751,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -685,7 +773,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.dog_statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.DogStatsdSink",
|
||||
|
@ -696,7 +784,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -707,7 +795,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.dog_statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.DogStatsdSink",
|
||||
|
@ -717,7 +805,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -730,7 +818,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
env: []string{"MY_STATSD_URL=udp://127.0.0.1:9125"},
|
||||
wantArgs: BootstrapTplArgs{
|
||||
StatsConfigJSON: defaultStatsConfigJSON,
|
||||
StatsSinksJSON: `[{
|
||||
StatsSinksJSON: `{
|
||||
"name": "envoy.stat_sinks.dog_statsd",
|
||||
"typedConfig": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.DogStatsdSink",
|
||||
|
@ -741,7 +829,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}]`,
|
||||
}`,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
|
@ -1539,3 +1627,65 @@ func TestConsulTagSpecifiers(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendHCPMetrics(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
inputArgs *BootstrapTplArgs
|
||||
bindSocketDir string
|
||||
wantArgs *BootstrapTplArgs
|
||||
}{
|
||||
"dir-without-trailing-slash": {
|
||||
inputArgs: &BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
},
|
||||
bindSocketDir: "/tmp/consul/hcp-metrics",
|
||||
wantArgs: &BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
StatsSinksJSON: expectedHCPMetricsStatsSink,
|
||||
StaticClustersJSON: expectedHCPMetricsCluster,
|
||||
},
|
||||
},
|
||||
"dir-with-trailing-slash": {
|
||||
inputArgs: &BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
},
|
||||
bindSocketDir: "/tmp/consul/hcp-metrics",
|
||||
wantArgs: &BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
StatsSinksJSON: expectedHCPMetricsStatsSink,
|
||||
StaticClustersJSON: expectedHCPMetricsCluster,
|
||||
},
|
||||
},
|
||||
"append-clusters-and-stats-sink": {
|
||||
inputArgs: &BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
StatsSinksJSON: expectedStatsdSink,
|
||||
StaticClustersJSON: expectedSelfAdminCluster,
|
||||
},
|
||||
bindSocketDir: "/tmp/consul/hcp-metrics",
|
||||
wantArgs: &BootstrapTplArgs{
|
||||
ProxyID: "web-sidecar-proxy",
|
||||
StatsSinksJSON: expectedStatsdSink + ",\n" + expectedHCPMetricsStatsSink,
|
||||
StaticClustersJSON: expectedSelfAdminCluster + ",\n" + expectedHCPMetricsCluster,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appendHCPMetricsConfig(tt.inputArgs, tt.bindSocketDir)
|
||||
|
||||
// Some of our JSON strings are comma separated objects to be
|
||||
// insertedinto an array which is not valid JSON on it's own so wrap
|
||||
// them all in an array. For simple values this is still valid JSON
|
||||
// too.
|
||||
wantStatsSink := "[" + tt.wantArgs.StatsSinksJSON + "]"
|
||||
gotStatsSink := "[" + tt.inputArgs.StatsSinksJSON + "]"
|
||||
require.JSONEq(t, wantStatsSink, gotStatsSink, "field StatsSinksJSON should be equivalent JSON")
|
||||
|
||||
wantClusters := "[" + tt.wantArgs.StaticClustersJSON + "]"
|
||||
gotClusters := "[" + tt.inputArgs.StaticClustersJSON + "]"
|
||||
require.JSONEq(t, wantClusters, gotClusters, "field StaticClustersJSON should be equivalent JSON")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -262,7 +262,9 @@ const bootstrapTemplate = `{
|
|||
{{- end }}
|
||||
},
|
||||
{{- if .StatsSinksJSON }}
|
||||
"stats_sinks": {{ .StatsSinksJSON }},
|
||||
"stats_sinks": [
|
||||
{{ .StatsSinksJSON }}
|
||||
],
|
||||
{{- end }}
|
||||
{{- if .StatsConfigJSON }}
|
||||
"stats_config": {{ .StatsConfigJSON }},
|
||||
|
|
|
@ -195,6 +195,29 @@ func TestGenerateConfig(t *testing.T) {
|
|||
PrometheusScrapePath: "/metrics",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "hcp-metrics",
|
||||
Flags: []string{"-proxy-id", "test-proxy"},
|
||||
ProxyConfig: map[string]interface{}{
|
||||
"envoy_hcp_metrics_bind_socket_dir": "/tmp/consul/hcp-metrics",
|
||||
},
|
||||
WantArgs: BootstrapTplArgs{
|
||||
ProxyCluster: "test-proxy",
|
||||
ProxyID: "test-proxy",
|
||||
// We don't know this til after the lookup so it will be empty in the
|
||||
// initial args call we are testing here.
|
||||
ProxySourceService: "",
|
||||
GRPC: GRPC{
|
||||
AgentAddress: "127.0.0.1",
|
||||
AgentPort: "8502",
|
||||
},
|
||||
AdminAccessLogPath: "/dev/null",
|
||||
AdminBindAddress: "127.0.0.1",
|
||||
AdminBindPort: "19000",
|
||||
LocalAgentClusterName: xds.LocalAgentClusterName,
|
||||
PrometheusScrapePath: "/metrics",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "prometheus-metrics",
|
||||
Flags: []string{"-proxy-id", "test-proxy",
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
{
|
||||
"admin": {
|
||||
"access_log_path": "/dev/null",
|
||||
"address": {
|
||||
"socket_address": {
|
||||
"address": "127.0.0.1",
|
||||
"port_value": 19000
|
||||
}
|
||||
}
|
||||
},
|
||||
"node": {
|
||||
"cluster": "test",
|
||||
"id": "test-proxy",
|
||||
"metadata": {
|
||||
"namespace": "default",
|
||||
"partition": "default"
|
||||
}
|
||||
},
|
||||
"layered_runtime": {
|
||||
"layers": [
|
||||
{
|
||||
"name": "base",
|
||||
"static_layer": {
|
||||
"re2.max_program_size.error_level": 1048576
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"static_resources": {
|
||||
"clusters": [
|
||||
{
|
||||
"name": "local_agent",
|
||||
"ignore_health_on_host_removal": false,
|
||||
"connect_timeout": "1s",
|
||||
"type": "STATIC",
|
||||
"http2_protocol_options": {},
|
||||
"loadAssignment": {
|
||||
"clusterName": "local_agent",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"socket_address": {
|
||||
"address": "127.0.0.1",
|
||||
"port_value": 8502
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hcp_metrics_collector",
|
||||
"type": "STATIC",
|
||||
"http2_protocol_options": {},
|
||||
"loadAssignment": {
|
||||
"clusterName": "hcp_metrics_collector",
|
||||
"endpoints": [
|
||||
{
|
||||
"lbEndpoints": [
|
||||
{
|
||||
"endpoint": {
|
||||
"address": {
|
||||
"pipe": {
|
||||
"path": "/tmp/consul/hcp-metrics/default_test-proxy.sock"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"stats_sinks": [
|
||||
{
|
||||
"name": "envoy.stat_sinks.metrics_service",
|
||||
"typed_config": {
|
||||
"@type": "type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig",
|
||||
"transport_api_version": "V3",
|
||||
"grpc_service": {
|
||||
"envoy_grpc": {
|
||||
"cluster_name": "hcp_metrics_collector"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"stats_config": {
|
||||
"stats_tags": [
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:([^.]+)~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.custom_hash"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:([^.]+)\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.service_subset"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?([^.]+)\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.service"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.namespace"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:([^.]+)\\.)?[^.]+\\.internal[^.]*\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.partition"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?([^.]+)\\.internal[^.]*\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.datacenter"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.([^.]+\\.(?:[^.]+\\.)?([^.]+)\\.external\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.peer"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.routing_type"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.([^.]+)\\.consul\\.)",
|
||||
"tag_name": "consul.destination.trust_domain"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+)\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.destination.target"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(?:passthrough~)?(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+)\\.consul\\.)",
|
||||
"tag_name": "consul.destination.full_target"
|
||||
},
|
||||
{
|
||||
"regex": "^(?:tcp|http)\\.upstream(?:_peered)?\\.(([^.]+)(?:\\.[^.]+)?(?:\\.[^.]+)?\\.[^.]+\\.)",
|
||||
"tag_name": "consul.upstream.service"
|
||||
},
|
||||
{
|
||||
"regex": "^(?:tcp|http)\\.upstream\\.([^.]+(?:\\.[^.]+)?(?:\\.[^.]+)?\\.([^.]+)\\.)",
|
||||
"tag_name": "consul.upstream.datacenter"
|
||||
},
|
||||
{
|
||||
"regex": "^(?:tcp|http)\\.upstream_peered\\.([^.]+(?:\\.[^.]+)?\\.([^.]+)\\.)",
|
||||
"tag_name": "consul.upstream.peer"
|
||||
},
|
||||
{
|
||||
"regex": "^(?:tcp|http)\\.upstream(?:_peered)?\\.([^.]+(?:\\.([^.]+))?(?:\\.[^.]+)?\\.[^.]+\\.)",
|
||||
"tag_name": "consul.upstream.namespace"
|
||||
},
|
||||
{
|
||||
"regex": "^(?:tcp|http)\\.upstream\\.([^.]+(?:\\.[^.]+)?(?:\\.([^.]+))?\\.[^.]+\\.)",
|
||||
"tag_name": "consul.upstream.partition"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:([^.]+)~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.custom_hash"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:[^.]+~)?(?:([^.]+)\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.service_subset"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?([^.]+)\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.service"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.namespace"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?([^.]+)\\.internal[^.]*\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.datacenter"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.routing_type"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.([^.]+)\\.consul\\.)",
|
||||
"tag_name": "consul.trust_domain"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+)\\.[^.]+\\.[^.]+\\.consul\\.)",
|
||||
"tag_name": "consul.target"
|
||||
},
|
||||
{
|
||||
"regex": "^cluster\\.(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+)\\.consul\\.)",
|
||||
"tag_name": "consul.full_target"
|
||||
},
|
||||
{
|
||||
"tag_name": "local_cluster",
|
||||
"fixed_value": "test"
|
||||
},
|
||||
{
|
||||
"tag_name": "consul.source.service",
|
||||
"fixed_value": "test"
|
||||
},
|
||||
{
|
||||
"tag_name": "consul.source.namespace",
|
||||
"fixed_value": "default"
|
||||
},
|
||||
{
|
||||
"tag_name": "consul.source.partition",
|
||||
"fixed_value": "default"
|
||||
},
|
||||
{
|
||||
"tag_name": "consul.source.datacenter",
|
||||
"fixed_value": "dc1"
|
||||
}
|
||||
],
|
||||
"use_all_default_tags": true
|
||||
},
|
||||
"dynamic_resources": {
|
||||
"lds_config": {
|
||||
"ads": {},
|
||||
"resource_api_version": "V3"
|
||||
},
|
||||
"cds_config": {
|
||||
"ads": {},
|
||||
"resource_api_version": "V3"
|
||||
},
|
||||
"ads_config": {
|
||||
"api_type": "DELTA_GRPC",
|
||||
"transport_api_version": "V3",
|
||||
"grpc_services": {
|
||||
"initial_metadata": [
|
||||
{
|
||||
"key": "x-consul-token",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"envoy_grpc": {
|
||||
"cluster_name": "local_agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +75,10 @@ Usage: `consul connect envoy [options] [-- pass-through options]`
|
|||
In cases where either assumption is violated this flag will prevent the
|
||||
command attempting to resolve config from the local agent.
|
||||
|
||||
- `envoy_hcp_metrics_bind_socket_dir` - Specifies the directory where Envoy creates a unix socket.
|
||||
Envoy sends metrics to the socket so that HCP collectors can connect to collect them."
|
||||
The socket is not configured by default.
|
||||
|
||||
- `-envoy-ready-bind-address` - By default the proxy does not have a readiness probe
|
||||
configured on it. This flag in conjunction with the `envoy-ready-bind-port` flag
|
||||
configures where the envoy readiness probe is configured on the proxy. A `/ready` HTTP
|
||||
|
|
Loading…
Reference in New Issue