From 54841eff8c107067337510cda5b304df1f1bf1bc Mon Sep 17 00:00:00 2001 From: Zach Reyes <39203661+zasweq@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:51:45 -0400 Subject: [PATCH] stats/opentelemetry/csm: Get mesh_id local label from "CSM_MESH_ID" environment variable, rather than parsing from bootstrap file (#7740) --- stats/opentelemetry/csm/observability_test.go | 22 +++---- stats/opentelemetry/csm/pluginoption.go | 37 +----------- stats/opentelemetry/csm/pluginoption_test.go | 57 ++----------------- 3 files changed, 18 insertions(+), 98 deletions(-) diff --git a/stats/opentelemetry/csm/observability_test.go b/stats/opentelemetry/csm/observability_test.go index 7b498cb50879..520d353a6707 100644 --- a/stats/opentelemetry/csm/observability_test.go +++ b/stats/opentelemetry/csm/observability_test.go @@ -32,8 +32,6 @@ import ( "google.golang.org/grpc/encoding/gzip" istats "google.golang.org/grpc/internal/stats" "google.golang.org/grpc/internal/stubserver" - "google.golang.org/grpc/internal/testutils" - "google.golang.org/grpc/internal/testutils/xds/e2e" testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/metadata" @@ -46,12 +44,11 @@ import ( // Env Vars as well, and mocks the resource detector's returned attribute set to // simulate the environment. It registers a cleanup function on the provided t // to restore the environment to its original state. -func setupEnv(t *testing.T, resourceDetectorEmissions map[string]string, nodeID, csmCanonicalServiceName, csmWorkloadName string) { - bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, "xds_server_uri") - testutils.CreateBootstrapFileForTesting(t, bootstrapContents) - +func setupEnv(t *testing.T, resourceDetectorEmissions map[string]string, meshID, csmCanonicalServiceName, csmWorkloadName string) { + oldCSMMeshID, csmMeshIDPresent := os.LookupEnv("CSM_MESH_ID") oldCSMCanonicalServiceName, csmCanonicalServiceNamePresent := os.LookupEnv("CSM_CANONICAL_SERVICE_NAME") oldCSMWorkloadName, csmWorkloadNamePresent := os.LookupEnv("CSM_WORKLOAD_NAME") + os.Setenv("CSM_MESH_ID", meshID) os.Setenv("CSM_CANONICAL_SERVICE_NAME", csmCanonicalServiceName) os.Setenv("CSM_WORKLOAD_NAME", csmWorkloadName) @@ -67,6 +64,11 @@ func setupEnv(t *testing.T, resourceDetectorEmissions map[string]string, nodeID, return &attrSet } t.Cleanup(func() { + if csmMeshIDPresent { + os.Setenv("CSM_MESH_ID", oldCSMMeshID) + } else { + os.Unsetenv("CSM_MESH_ID") + } if csmCanonicalServiceNamePresent { os.Setenv("CSM_CANONICAL_SERVICE_NAME", oldCSMCanonicalServiceName) } else { @@ -99,10 +101,10 @@ func (s) TestCSMPluginOptionUnary(t *testing.T) { "k8s.namespace.name": "k8s_namespace_name_val", "k8s.cluster.name": "k8s_cluster_name_val", } - const nodeID = "projects/12345/networks/mesh:mesh_id/nodes/aaaa-aaaa-aaaa-aaaa" + const meshID = "mesh_id" const csmCanonicalServiceName = "csm_canonical_service_name" const csmWorkloadName = "csm_workload_name" - setupEnv(t, resourceDetectorEmissions, nodeID, csmCanonicalServiceName, csmWorkloadName) + setupEnv(t, resourceDetectorEmissions, meshID, csmCanonicalServiceName, csmWorkloadName) attributesWant := map[string]string{ "csm.workload_canonical_service": csmCanonicalServiceName, // from env @@ -266,10 +268,10 @@ func (s) TestCSMPluginOptionStreaming(t *testing.T) { "k8s.namespace.name": "k8s_namespace_name_val", "k8s.cluster.name": "k8s_cluster_name_val", } - const nodeID = "projects/12345/networks/mesh:mesh_id/nodes/aaaa-aaaa-aaaa-aaaa" + const meshID = "mesh_id" const csmCanonicalServiceName = "csm_canonical_service_name" const csmWorkloadName = "csm_workload_name" - setupEnv(t, resourceDetectorEmissions, nodeID, csmCanonicalServiceName, csmWorkloadName) + setupEnv(t, resourceDetectorEmissions, meshID, csmCanonicalServiceName, csmWorkloadName) attributesWant := map[string]string{ "csm.workload_canonical_service": csmCanonicalServiceName, // from env diff --git a/stats/opentelemetry/csm/pluginoption.go b/stats/opentelemetry/csm/pluginoption.go index e415f2f53588..62a8d3813028 100644 --- a/stats/opentelemetry/csm/pluginoption.go +++ b/stats/opentelemetry/csm/pluginoption.go @@ -24,13 +24,10 @@ import ( "encoding/base64" "net/url" "os" - "strings" "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/internal/xds/bootstrap" "google.golang.org/grpc/metadata" "google.golang.org/grpc/stats/opentelemetry/internal" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" @@ -233,24 +230,6 @@ func constructMetadataFromEnv(ctx context.Context) (map[string]string, string) { return initializeLocalAndMetadataLabels(labels) } -// parseMeshIDString parses the mesh id from the node id according to the format -// "projects/[GCP Project number]/networks/mesh:[Mesh ID]/nodes/[UUID]". Returns -// "unknown" if there is a syntax error in the node ID. -func parseMeshIDFromNodeID(nodeID string) string { - meshSplit := strings.Split(nodeID, "/") - if len(meshSplit) != 6 { - return "unknown" - } - if meshSplit[0] != "projects" || meshSplit[2] != "networks" || meshSplit[4] != "nodes" { - return "unknown" - } - meshID, ok := strings.CutPrefix(meshSplit[3], "mesh:") - if !ok { // errors become "unknown" - return "unknown" - } - return meshID -} - // initializeLocalAndMetadataLabels csm local labels for a CSM Plugin Option to // record. It also builds out a base 64 encoded protobuf.Struct containing the // metadata exchange labels to be sent as part of metadata exchange from a CSM @@ -261,9 +240,7 @@ func initializeLocalAndMetadataLabels(labels map[string]string) (map[string]stri val := labels["canonical_service"] localLabels := make(map[string]string) localLabels["csm.workload_canonical_service"] = val - // Get the CSM Mesh ID from the bootstrap file. - nodeID := getNodeID() - localLabels["csm.mesh_id"] = parseMeshIDFromNodeID(nodeID) + localLabels["csm.mesh_id"] = getEnv("CSM_MESH_ID") // Metadata exchange labels - can go ahead and encode into proto, and then // base64. @@ -288,18 +265,6 @@ func initializeLocalAndMetadataLabels(labels map[string]string) (map[string]stri return localLabels, metadataExchangeLabelsEncoded } -// getNodeID gets the Node ID from the bootstrap data. -func getNodeID() string { - cfg, err := bootstrap.GetConfiguration() - if err != nil { - return "" // will become "unknown" - } - if cfg.Node() == nil { - return "" - } - return cfg.Node().GetId() -} - // metadataExchangeKey is the key for HTTP metadata exchange. const metadataExchangeKey = "x-envoy-peer-metadata" diff --git a/stats/opentelemetry/csm/pluginoption_test.go b/stats/opentelemetry/csm/pluginoption_test.go index 8588c545360c..55e959760918 100644 --- a/stats/opentelemetry/csm/pluginoption_test.go +++ b/stats/opentelemetry/csm/pluginoption_test.go @@ -29,8 +29,6 @@ import ( "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/grpctest" - "google.golang.org/grpc/internal/testutils" - "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/metadata" "github.com/google/go-cmp/cmp" @@ -304,51 +302,6 @@ func (s) TestDetermineTargetCSM(t *testing.T) { } } -func (s) TestBootstrap(t *testing.T) { - tests := []struct { - name string - nodeID string - meshIDWant string - }{ - { - name: "malformed-node-id-unknown", - nodeID: "malformed", - meshIDWant: "unknown", - }, - { - name: "node-id-parsed", - nodeID: "projects/12345/networks/mesh:mesh_id/nodes/aaaa-aaaa-aaaa-aaaa", - meshIDWant: "mesh_id", - }, - { - name: "wrong-syntax-unknown", - nodeID: "wrong-syntax/12345/networks/mesh:mesh_id/nodes/aaaa-aaaa-aaaa-aaaa", - meshIDWant: "unknown", - }, - { - name: "node-id-parsed", - nodeID: "projects/12345/networks/mesh:/nodes/aaaa-aaaa-aaaa-aaaa", - meshIDWant: "", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - bootstrapContents := e2e.DefaultBootstrapContents(t, test.nodeID, "xds_server_uri") - testutils.CreateBootstrapFileForTesting(t, bootstrapContents) - nodeIDGot := getNodeID() // this should return the node ID plumbed into bootstrap above - if nodeIDGot != test.nodeID { - t.Fatalf("getNodeID: got %v, want %v", nodeIDGot, test.nodeID) - } - - meshIDGot := parseMeshIDFromNodeID(nodeIDGot) - if meshIDGot != test.meshIDWant { - t.Fatalf("parseMeshIDFromNodeID(%v): got %v, want %v", nodeIDGot, meshIDGot, test.meshIDWant) - } - }) - } -} - // TestSetLabels tests the setting of labels, which snapshots the resource and // environment. It mocks the resource and environment, and then calls into // labels creation. It verifies to local labels created and metadata exchange @@ -360,14 +313,14 @@ func (s) TestSetLabels(t *testing.T) { resourceKeyValues map[string]string csmCanonicalServiceNamePopulated bool csmWorkloadNamePopulated bool - bootstrapGeneratorPopulated bool + meshIDPopulated bool localLabelsWant map[string]string metadataExchangeLabelsWant map[string]string }{ { name: "no-type", csmCanonicalServiceNamePopulated: true, - bootstrapGeneratorPopulated: true, + meshIDPopulated: true, resourceKeyValues: map[string]string{}, localLabelsWant: map[string]string{ "csm.workload_canonical_service": "canonical_service_name_val", // env var populated so should be set. @@ -480,9 +433,9 @@ func (s) TestSetLabels(t *testing.T) { os.Setenv("CSM_WORKLOAD_NAME", "workload_name_val") defer os.Unsetenv("CSM_WORKLOAD_NAME") } - if test.bootstrapGeneratorPopulated { - bootstrapContents := e2e.DefaultBootstrapContents(t, "projects/12345/networks/mesh:mesh_id/nodes/aaaa-aaaa-aaaa-aaaa", "xds_server_uri") - testutils.CreateBootstrapFileForTesting(t, bootstrapContents) + if test.meshIDPopulated { + os.Setenv("CSM_MESH_ID", "mesh_id") + defer os.Unsetenv("CSM_MESH_ID") } var attributes []attribute.KeyValue for k, v := range test.resourceKeyValues {