diff --git a/internal/bootstrap/bootstrap_config.go b/internal/bootstrap/bootstrap_config.go index f9c8ccda..54fa73de 100644 --- a/internal/bootstrap/bootstrap_config.go +++ b/internal/bootstrap/bootstrap_config.go @@ -1,8 +1,13 @@ // Code generated by make copy-bootstrap-config. DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package bootstrap import ( "bytes" + "crypto/sha1" + "encoding/base64" "encoding/json" "fmt" "net" @@ -50,9 +55,9 @@ type BootstrapConfig struct { 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"` + // 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 : on which the Envoy will listen // and expose a single /metrics HTTP endpoint for Prometheus to scrape. It @@ -806,11 +811,28 @@ func (c *BootstrapConfig) generateListenerConfig(args *BootstrapTplArgs, bindAdd return nil } -// appendHCPMetricsConfig generates config to enable a socket at path: /_.sock -// or /.sock, if namespace is empty. +// appendHCPMetricsConfig generates config to enable a socket at path: /.sock +// We take the hash of the compound proxy ID for a few reasons: +// +// - The proxy ID is included because this socket path must be unique per proxy. Each Envoy proxy will ship +// its metrics to HCP using its own loopback listener at this path. +// +// - The hash is needed because UNIX domain socket paths must be less than 104 characters. By using a b64 encoded +// SHA1 hash we end up with 27 chars for the name, 5 chars for the extension, and the remainder is saved for +// the configurable socket dir. The length of the directory's path is validated on writes to avoid going over. func appendHCPMetricsConfig(args *BootstrapTplArgs, hcpMetricsBindSocketDir string) { - sock := fmt.Sprintf("%s_%s.sock",args.Namespace,args.ProxyID) - path := path.Join(hcpMetricsBindSocketDir, sock) + // 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. + ns := args.Namespace + if ns == "" { + ns = "default" + } + id := ns + "_" + args.ProxyID + + h := sha1.New() + h.Write([]byte(id)) + hash := base64.RawURLEncoding.EncodeToString(h.Sum(nil)) + path := path.Join(hcpMetricsBindSocketDir, hash+".sock") if args.StatsSinksJSON != "" { args.StatsSinksJSON += ",\n" diff --git a/internal/bootstrap/bootstrap_config_test.go b/internal/bootstrap/bootstrap_config_test.go index c486fad4..df4772d7 100644 --- a/internal/bootstrap/bootstrap_config_test.go +++ b/internal/bootstrap/bootstrap_config_test.go @@ -1,4 +1,7 @@ // Code generated by make copy-bootstrap-config. DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package bootstrap import ( @@ -91,19 +94,6 @@ 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 - } - } - } -}` expectedPromListener = `{ "name": "envoy_prometheus_metrics_listener", "address": { @@ -528,7 +518,33 @@ expectedStatsdSink = `{ ] }` -expectedHCPMetricsCluster = `{ + 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": {}, @@ -541,7 +557,7 @@ expectedHCPMetricsCluster = `{ "endpoint": { "address": { "pipe": { - "path": "/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock" + "path": "/tmp/consul/hcp-metrics/gqmuzdHCUPAEY5mbF8vgkZCNI14.sock" } } } @@ -551,19 +567,6 @@ expectedHCPMetricsCluster = `{ ] } }` - - 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" - } - } - } - }` ) func TestBootstrapConfig_ConfigureArgs(t *testing.T) { @@ -620,14 +623,12 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { name: "hcp-metrics-sink", baseArgs: BootstrapTplArgs{ ProxyID: "web-sidecar-proxy", - Namespace: "default", }, input: BootstrapConfig{ HCPMetricsBindSocketDir: "/tmp/consul/hcp-metrics", }, wantArgs: BootstrapTplArgs{ - ProxyID: "web-sidecar-proxy", - Namespace: "default", + ProxyID: "web-sidecar-proxy", StatsConfigJSON: defaultStatsConfigJSON, StatsSinksJSON: `{ "name": "envoy.stat_sinks.metrics_service", @@ -654,7 +655,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { "endpoint": { "address": { "pipe": { - "path": "/tmp/consul/hcp-metrics/default_web-sidecar-proxy.sock" + "path": "/tmp/consul/hcp-metrics/gqmuzdHCUPAEY5mbF8vgkZCNI14.sock" } } } @@ -674,18 +675,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, }, @@ -731,7 +721,18 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { env: []string{"MY_STATSD_URL=udp://127.0.0.1:9125"}, wantArgs: BootstrapTplArgs{ StatsConfigJSON: defaultStatsConfigJSON, - StatsSinksJSON: expectedStatsdSink, + 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 + } + } + } + }`, }, wantErr: false, }, @@ -1631,51 +1632,44 @@ func TestConsulTagSpecifiers(t *testing.T) { } } - -func TestAppendHCPMetrics(t *testing.T){ - tests := map[string]struct{ - inputArgs *BootstrapTplArgs +func TestAppendHCPMetrics(t *testing.T) { + tests := map[string]struct { + inputArgs *BootstrapTplArgs bindSocketDir string - wantArgs *BootstrapTplArgs + wantArgs *BootstrapTplArgs }{ - "dir-without-trailing-slash":{ + "dir-without-trailing-slash": { inputArgs: &BootstrapTplArgs{ - Namespace: "default", ProxyID: "web-sidecar-proxy", }, bindSocketDir: "/tmp/consul/hcp-metrics", wantArgs: &BootstrapTplArgs{ - Namespace: "default", - ProxyID: "web-sidecar-proxy", - StatsSinksJSON: expectedHCPMetricsStatsSink, + ProxyID: "web-sidecar-proxy", + StatsSinksJSON: expectedHCPMetricsStatsSink, StaticClustersJSON: expectedHCPMetricsCluster, }, }, - "dir-with-trailing-slash":{ + "dir-with-trailing-slash": { inputArgs: &BootstrapTplArgs{ - Namespace: "default", ProxyID: "web-sidecar-proxy", }, bindSocketDir: "/tmp/consul/hcp-metrics", wantArgs: &BootstrapTplArgs{ - Namespace: "default", - ProxyID: "web-sidecar-proxy", - StatsSinksJSON: expectedHCPMetricsStatsSink, + ProxyID: "web-sidecar-proxy", + StatsSinksJSON: expectedHCPMetricsStatsSink, StaticClustersJSON: expectedHCPMetricsCluster, }, }, "append-clusters-and-stats-sink": { inputArgs: &BootstrapTplArgs{ - Namespace: "default", - ProxyID: "web-sidecar-proxy", - StatsSinksJSON: expectedStatsdSink, + ProxyID: "web-sidecar-proxy", + StatsSinksJSON: expectedStatsdSink, StaticClustersJSON: expectedSelfAdminCluster, }, bindSocketDir: "/tmp/consul/hcp-metrics", wantArgs: &BootstrapTplArgs{ - Namespace: "default", - ProxyID: "web-sidecar-proxy", - StatsSinksJSON: expectedStatsdSink + ",\n" + expectedHCPMetricsStatsSink , + ProxyID: "web-sidecar-proxy", + StatsSinksJSON: expectedStatsdSink + ",\n" + expectedHCPMetricsStatsSink, StaticClustersJSON: expectedSelfAdminCluster + ",\n" + expectedHCPMetricsCluster, }, }, @@ -1683,19 +1677,19 @@ func TestAppendHCPMetrics(t *testing.T){ for name, tt := range tests { t.Run(name, func(t *testing.T) { - appendHCPMetricsConfig(tt.inputArgs,tt.bindSocketDir) + 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+ "]" + wantStatsSink := "[" + tt.wantArgs.StatsSinksJSON + "]" gotStatsSink := "[" + tt.inputArgs.StatsSinksJSON + "]" - require.JSONEq(t, wantStatsSink, gotStatsSink,"field StatsSinksJSON should be equivalent JSON") - - wantClusters := "[" + tt.wantArgs.StaticClustersJSON+ "]" + 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") }) } -} \ No newline at end of file +} diff --git a/internal/bootstrap/bootstrap_tpl.go b/internal/bootstrap/bootstrap_tpl.go index 553a5b24..dc374f5a 100644 --- a/internal/bootstrap/bootstrap_tpl.go +++ b/internal/bootstrap/bootstrap_tpl.go @@ -1,4 +1,7 @@ // Code generated by make copy-bootstrap-config. DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package bootstrap // BootstrapTplArgs is the set of arguments that may be interpolated into the diff --git a/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden b/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden index 360512fa..4f6d2c9a 100644 --- a/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden +++ b/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden @@ -68,7 +68,7 @@ "endpoint": { "address": { "pipe": { - "path": "/tmp/consul/hcp-metrics/default_web-proxy.sock" + "path": "/tmp/consul/hcp-metrics/0UZwF69tP4X7LqMgNbB_v_R6Sjk.sock" } } }