mirror of https://github.com/grpc/grpc-go.git
stats/opentelemetry/csm: Get mesh_id local label from "CSM_MESH_ID" environment variable, rather than parsing from bootstrap file (#7740)
This commit is contained in:
parent
ad81c20503
commit
54841eff8c
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue