From c6f02dfb2f4f509e64b1851c124dcd1a1eb17f20 Mon Sep 17 00:00:00 2001 From: Ashvitha Sridharan Date: Tue, 7 Mar 2023 11:27:48 -0500 Subject: [PATCH 1/4] Add HCPMetricsBindSocketDir to Envoy bootstrap config --- .changelog/90.txt | 4 + internal/bootstrap/bootstrap_config.go | 69 +++- internal/bootstrap/bootstrap_config_test.go | 318 +++++++++++++++++- internal/bootstrap/bootstrap_tpl.go | 4 +- pkg/consuldp/bootstrap_test.go | 23 ++ .../TestBootstrapConfig/hcp-metrics.golden | 207 ++++++++++++ 6 files changed, 607 insertions(+), 18 deletions(-) create mode 100644 .changelog/90.txt create mode 100644 pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden diff --git a/.changelog/90.txt b/.changelog/90.txt new file mode 100644 index 00000000..9c5a7880 --- /dev/null +++ b/.changelog/90.txt @@ -0,0 +1,4 @@ +```release-note:feature +Add envoy_hcp_metrics_bind_socket_dir flag to configure a directory where a unix socket is created. +This enables Envoy metrics collection, which will be forwarded to a HCP metrics collector. +``` \ No newline at end of file diff --git a/internal/bootstrap/bootstrap_config.go b/internal/bootstrap/bootstrap_config.go index 746a2a62..f8c129c6 100644 --- a/internal/bootstrap/bootstrap_config.go +++ b/internal/bootstrap/bootstrap_config.go @@ -48,6 +48,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 : 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 @@ -237,6 +242,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 } @@ -270,7 +280,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 } @@ -795,6 +805,63 @@ 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. +func appendHCPMetricsConfig(args *BootstrapTplArgs, hcpMetricsBindSocketDir string) { + dir := hcpMetricsBindSocketDir + if !strings.HasSuffix(dir, "/") { + dir += "/" + } + + path := fmt.Sprintf("%s%s.sock",dir,args.ProxyID) + if args.Namespace != ""{ + path = fmt.Sprintf("%s%s_%s.sock",dir,args.Namespace,args.ProxyID) + } + + 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 diff --git a/internal/bootstrap/bootstrap_config_test.go b/internal/bootstrap/bootstrap_config_test.go index 19cb0fac..847e3f6d 100644 --- a/internal/bootstrap/bootstrap_config_test.go +++ b/internal/bootstrap/bootstrap_config_test.go @@ -558,14 +558,65 @@ 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", + Namespace: "default", + }, + input: BootstrapConfig{ + HCPMetricsBindSocketDir: "/tmp/consul/hcp-metrics", + }, + wantArgs: BootstrapTplArgs{ + ProxyID: "web-sidecar-proxy", + Namespace: "default", + 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{ @@ -573,7 +624,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", @@ -584,7 +635,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { } } } - }]`, + }`, }, wantErr: false, }, @@ -601,7 +652,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", @@ -618,7 +669,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { "config": { "foo": "bar" } - }]`, + }`, }, wantErr: false, }, @@ -630,7 +681,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", @@ -641,7 +692,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { } } } - }]`, + }`, }, wantErr: false, }, @@ -653,7 +704,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", @@ -664,7 +715,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { } } } - }]`, + }`, }, wantErr: false, }, @@ -686,7 +737,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", @@ -697,7 +748,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { } } } - }]`, + }`, }, wantErr: false, }, @@ -708,7 +759,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", @@ -718,7 +769,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { } } } - }]`, + }`, }, wantErr: false, }, @@ -731,7 +782,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", @@ -742,7 +793,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { } } } - }]`, + }`, }, wantErr: false, }, @@ -1540,3 +1591,238 @@ 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{ + Namespace: "default", + ProxyID: "web-sidecar-proxy", + }, + bindSocketDir: "/tmp/consul/hcp-metrics", + wantArgs: &BootstrapTplArgs{ + Namespace: "default", + ProxyID: "web-sidecar-proxy", + 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" + } + } + } + } + ] + } + ] + } + }`, + }, + }, + "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: `{ + "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" + } + } + } + } + ] + } + ] + } + }`, + }, + }, + "path-without-namespace":{ + inputArgs: &BootstrapTplArgs{ + ProxyID: "web-sidecar-proxy", + }, + bindSocketDir: "/tmp/consul/hcp-metrics", + wantArgs: &BootstrapTplArgs{ + Namespace: "default", + ProxyID: "web-sidecar-proxy", + 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/web-sidecar-proxy.sock" + } + } + } + } + ] + } + ] + } + }`, + }, + }, + "append-clusters-and-stats-sink": { + inputArgs: &BootstrapTplArgs{ + Namespace: "default", + ProxyID: "web-sidecar-proxy", + 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 + } + } + } + }`, + StaticClustersJSON: expectedSelfAdminCluster, + }, + bindSocketDir: "/tmp/consul/hcp-metrics", + wantArgs: &BootstrapTplArgs{ + Namespace: "default", + ProxyID: "web-sidecar-proxy", + 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 + } + } + } + },{ + "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: expectedSelfAdminCluster + `, + { + "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" + } + } + } + } + ] + } + ] + } + }`, + }, + }, + } + + 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") + }) + } +} \ No newline at end of file diff --git a/internal/bootstrap/bootstrap_tpl.go b/internal/bootstrap/bootstrap_tpl.go index 02ced12d..553a5b24 100644 --- a/internal/bootstrap/bootstrap_tpl.go +++ b/internal/bootstrap/bootstrap_tpl.go @@ -263,7 +263,9 @@ const bootstrapTemplate = `{ {{- end }} }, {{- if .StatsSinksJSON }} - "stats_sinks": {{ .StatsSinksJSON }}, + "stats_sinks": [ + {{ .StatsSinksJSON }} + ], {{- end }} {{- if .StatsConfigJSON }} "stats_config": {{ .StatsConfigJSON }}, diff --git a/pkg/consuldp/bootstrap_test.go b/pkg/consuldp/bootstrap_test.go index 9d1bc413..860be316 100644 --- a/pkg/consuldp/bootstrap_test.go +++ b/pkg/consuldp/bootstrap_test.go @@ -109,6 +109,29 @@ func TestBootstrapConfig(t *testing.T) { }), }, }, + "hcp-metrics": { + cfg: &Config{ + Service: &ServiceConfig{ + ServiceID: "web-proxy", + NodeName: nodeName, + }, + Envoy: &EnvoyConfig{ + AdminBindAddress: "127.0.0.1", + AdminBindPort: 19000, + }, + Telemetry: &TelemetryConfig{ + UseCentralConfig: true, + }, + XDSServer: &XDSServer{BindAddress: "127.0.0.1", BindPort: xdsBindPort}, + }, + rsp: &pbdataplane.GetEnvoyBootstrapParamsResponse{ + Service: "web", + NodeName: nodeName, + Config: makeStruct(map[string]any{ + "envoy_hcp_metrics_bind_socket_dir": "/tmp/consul/hcp-metrics", + }), + }, + }, "custom-prometheus-scrape-path": { &Config{ Service: &ServiceConfig{ diff --git a/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden b/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden new file mode 100644 index 00000000..6a87b8b3 --- /dev/null +++ b/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden @@ -0,0 +1,207 @@ +{ + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "127.0.0.1", + "port_value": 19000 + } + } + }, + "node": { + "cluster": "web", + "id": "web-proxy", + "metadata": { + "node_name": "agentless-node", + "namespace": "default", + "partition": "default" + } + }, + "layered_runtime": { + "layers": [ + { + "name": "base", + "static_layer": { + "re2.max_program_size.error_level": 1048576 + } + } + ] + }, + "static_resources": { + "clusters": [ + { + "name": "consul-dataplane", + "ignore_health_on_host_removal": false, + "connect_timeout": "1s", + "type": "STATIC", + "http2_protocol_options": {}, + "loadAssignment": { + "clusterName": "consul-dataplane", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "socket_address": { + "address": "127.0.0.1", + "port_value": 1234 + } + } + } + } + ] + } + ] + } + }, + { + "name": "hcp_metrics_collector", + "type": "STATIC", + "http2_protocol_options": {}, + "loadAssignment": { + "clusterName": "hcp_metrics_collector", + "endpoints": [ + { + "lbEndpoints": [ + { + "endpoint": { + "address": { + "pipe": { + "path": "/tmp/consul/hcp-metrics/web-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" + }, + { + "tag_name": "local_cluster", + "fixed_value": "web" + }, + { + "tag_name": "consul.source.service", + "fixed_value": "web" + }, + { + "tag_name": "consul.source.namespace", + "fixed_value": "default" + }, + { + "tag_name": "consul.source.partition", + "fixed_value": "default" + } + ], + "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": "consul-dataplane" + } + } + } + } +} From 8f2ab52133b7b242fbc965e7d483e471d7ca623a Mon Sep 17 00:00:00 2001 From: Ashvitha Sridharan Date: Thu, 9 Mar 2023 15:27:13 -0500 Subject: [PATCH 2/4] Namespace is never empty. Fix test and build path without if check --- internal/bootstrap/bootstrap_config.go | 5 +-- internal/bootstrap/bootstrap_config_test.go | 45 ------------------- pkg/consuldp/bootstrap_test.go | 7 ++- .../TestBootstrapConfig/hcp-metrics.golden | 2 +- 4 files changed, 7 insertions(+), 52 deletions(-) diff --git a/internal/bootstrap/bootstrap_config.go b/internal/bootstrap/bootstrap_config.go index f8c129c6..849b7065 100644 --- a/internal/bootstrap/bootstrap_config.go +++ b/internal/bootstrap/bootstrap_config.go @@ -813,10 +813,7 @@ func appendHCPMetricsConfig(args *BootstrapTplArgs, hcpMetricsBindSocketDir stri dir += "/" } - path := fmt.Sprintf("%s%s.sock",dir,args.ProxyID) - if args.Namespace != ""{ - path = fmt.Sprintf("%s%s_%s.sock",dir,args.Namespace,args.ProxyID) - } + path := fmt.Sprintf("%s%s_%s.sock",dir,args.Namespace,args.ProxyID) if args.StatsSinksJSON != "" { args.StatsSinksJSON += ",\n" diff --git a/internal/bootstrap/bootstrap_config_test.go b/internal/bootstrap/bootstrap_config_test.go index 847e3f6d..d31152e6 100644 --- a/internal/bootstrap/bootstrap_config_test.go +++ b/internal/bootstrap/bootstrap_config_test.go @@ -1690,51 +1690,6 @@ func TestAppendHCPMetrics(t *testing.T){ }`, }, }, - "path-without-namespace":{ - inputArgs: &BootstrapTplArgs{ - ProxyID: "web-sidecar-proxy", - }, - bindSocketDir: "/tmp/consul/hcp-metrics", - wantArgs: &BootstrapTplArgs{ - Namespace: "default", - ProxyID: "web-sidecar-proxy", - 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/web-sidecar-proxy.sock" - } - } - } - } - ] - } - ] - } - }`, - }, - }, "append-clusters-and-stats-sink": { inputArgs: &BootstrapTplArgs{ Namespace: "default", diff --git a/pkg/consuldp/bootstrap_test.go b/pkg/consuldp/bootstrap_test.go index 860be316..b74bcba7 100644 --- a/pkg/consuldp/bootstrap_test.go +++ b/pkg/consuldp/bootstrap_test.go @@ -114,6 +114,7 @@ func TestBootstrapConfig(t *testing.T) { Service: &ServiceConfig{ ServiceID: "web-proxy", NodeName: nodeName, + Namespace: "default", }, Envoy: &EnvoyConfig{ AdminBindAddress: "127.0.0.1", @@ -125,8 +126,9 @@ func TestBootstrapConfig(t *testing.T) { XDSServer: &XDSServer{BindAddress: "127.0.0.1", BindPort: xdsBindPort}, }, rsp: &pbdataplane.GetEnvoyBootstrapParamsResponse{ - Service: "web", - NodeName: nodeName, + Service: "web", + Namespace: "default", + NodeName: nodeName, Config: makeStruct(map[string]any{ "envoy_hcp_metrics_bind_socket_dir": "/tmp/consul/hcp-metrics", }), @@ -215,6 +217,7 @@ func TestBootstrapConfig(t *testing.T) { GetEnvoyBootstrapParams(mock.Anything, &pbdataplane.GetEnvoyBootstrapParamsRequest{ NodeSpec: &pbdataplane.GetEnvoyBootstrapParamsRequest_NodeName{NodeName: tc.cfg.Service.NodeName}, ServiceId: tc.cfg.Service.ServiceID, + Namespace: tc.cfg.Service.Namespace, }).Call. Return(tc.rsp, nil) diff --git a/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden b/pkg/consuldp/testdata/TestBootstrapConfig/hcp-metrics.golden index 6a87b8b3..360512fa 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/web-proxy.sock" + "path": "/tmp/consul/hcp-metrics/default_web-proxy.sock" } } } From 445aaf77887a2000f20884e37fd66ce1d3296bb6 Mon Sep 17 00:00:00 2001 From: Ashvitha Sridharan Date: Thu, 9 Mar 2023 16:05:53 -0500 Subject: [PATCH 3/4] reuse constant test --- internal/bootstrap/bootstrap_config_test.go | 200 ++++++-------------- 1 file changed, 59 insertions(+), 141 deletions(-) diff --git a/internal/bootstrap/bootstrap_config_test.go b/internal/bootstrap/bootstrap_config_test.go index d31152e6..c486fad4 100644 --- a/internal/bootstrap/bootstrap_config_test.go +++ b/internal/bootstrap/bootstrap_config_test.go @@ -91,6 +91,19 @@ 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": { @@ -514,6 +527,43 @@ const ( } ] }` + +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" + } + } + } + } + ] + } + ] + } + }` + + 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) { @@ -681,18 +731,7 @@ func TestBootstrapConfig_ConfigureArgs(t *testing.T) { env: []string{"MY_STATSD_URL=udp://127.0.0.1:9125"}, 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, }, @@ -1592,6 +1631,7 @@ func TestConsulTagSpecifiers(t *testing.T) { } } + func TestAppendHCPMetrics(t *testing.T){ tests := map[string]struct{ inputArgs *BootstrapTplArgs @@ -1607,41 +1647,8 @@ func TestAppendHCPMetrics(t *testing.T){ wantArgs: &BootstrapTplArgs{ Namespace: "default", ProxyID: "web-sidecar-proxy", - 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" - } - } - } - } - ] - } - ] - } - }`, + StatsSinksJSON: expectedHCPMetricsStatsSink, + StaticClustersJSON: expectedHCPMetricsCluster, }, }, "dir-with-trailing-slash":{ @@ -1653,112 +1660,23 @@ func TestAppendHCPMetrics(t *testing.T){ wantArgs: &BootstrapTplArgs{ Namespace: "default", ProxyID: "web-sidecar-proxy", - 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" - } - } - } - } - ] - } - ] - } - }`, + StatsSinksJSON: expectedHCPMetricsStatsSink, + StaticClustersJSON: expectedHCPMetricsCluster, }, }, "append-clusters-and-stats-sink": { inputArgs: &BootstrapTplArgs{ Namespace: "default", ProxyID: "web-sidecar-proxy", - 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, StaticClustersJSON: expectedSelfAdminCluster, }, bindSocketDir: "/tmp/consul/hcp-metrics", wantArgs: &BootstrapTplArgs{ Namespace: "default", ProxyID: "web-sidecar-proxy", - 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 - } - } - } - },{ - "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: expectedSelfAdminCluster + `, - { - "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" - } - } - } - } - ] - } - ] - } - }`, + StatsSinksJSON: expectedStatsdSink + ",\n" + expectedHCPMetricsStatsSink , + StaticClustersJSON: expectedSelfAdminCluster + ",\n" + expectedHCPMetricsCluster, }, }, } From f2bd67c9de92b945b1fbb19c9fb4b9311dbc3c55 Mon Sep 17 00:00:00 2001 From: Ashvitha Sridharan Date: Fri, 10 Mar 2023 14:58:26 -0500 Subject: [PATCH 4/4] use path.Join to simplify code --- internal/bootstrap/bootstrap_config.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/bootstrap/bootstrap_config.go b/internal/bootstrap/bootstrap_config.go index 849b7065..f9c8ccda 100644 --- a/internal/bootstrap/bootstrap_config.go +++ b/internal/bootstrap/bootstrap_config.go @@ -8,6 +8,7 @@ import ( "net" "net/url" "os" + "path" "strings" "text/template" ) @@ -808,12 +809,8 @@ func (c *BootstrapConfig) generateListenerConfig(args *BootstrapTplArgs, bindAdd // appendHCPMetricsConfig generates config to enable a socket at path: /_.sock // or /.sock, if namespace is empty. func appendHCPMetricsConfig(args *BootstrapTplArgs, hcpMetricsBindSocketDir string) { - dir := hcpMetricsBindSocketDir - if !strings.HasSuffix(dir, "/") { - dir += "/" - } - - path := fmt.Sprintf("%s%s_%s.sock",dir,args.Namespace,args.ProxyID) + sock := fmt.Sprintf("%s_%s.sock",args.Namespace,args.ProxyID) + path := path.Join(hcpMetricsBindSocketDir, sock) if args.StatsSinksJSON != "" { args.StatsSinksJSON += ",\n"