Skip to content

Commit

Permalink
[CSM] Add support for GCE resources (#35371)
Browse files Browse the repository at this point in the history
Add support for GCE resources in CSM Observability.

Additionally, fix a bug where we were not adding the remote workload's canonical service label for unknown resource types.

Also, if zone and region are both specified, zone takes precedence.

Closes #35371

COPYBARA_INTEGRATE_REVIEW=#35371 from yashykt:GceSupportToCsm e3064d8
PiperOrigin-RevId: 597989825
  • Loading branch information
yashykt authored and Copybara-Service committed Jan 13, 2024
1 parent 9f6789e commit 8231340
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 55 deletions.
134 changes: 82 additions & 52 deletions src/cpp/ext/csm/metadata_exchange.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ constexpr absl::string_view kPeerCanonicalServiceAttribute =
"csm.remote_workload_canonical_service";
// Type values used by Google Cloud Resource Detector
constexpr absl::string_view kGkeType = "gcp_kubernetes_engine";
constexpr absl::string_view kGceType = "gcp_compute_engine";

enum class GcpResourceType : std::uint8_t { kGke, kUnknown };
enum class GcpResourceType : std::uint8_t { kGke, kGce, kUnknown };

// A minimal class for helping with the information we need from the xDS
// bootstrap file for GSM Observability reasons.
Expand Down Expand Up @@ -151,6 +152,8 @@ std::string GetXdsBootstrapContents() {
GcpResourceType StringToGcpResourceType(absl::string_view type) {
if (type == kGkeType) {
return GcpResourceType::kGke;
} else if (type == kGceType) {
return GcpResourceType::kGce;
}
return GcpResourceType::kUnknown;
}
Expand Down Expand Up @@ -219,39 +222,19 @@ class MeshLabelsIterable : public LabelsIterable {
if (pos_ < local_labels_size) {
return local_labels_[pos_++];
}
if (++pos_ == local_labels_size + 1) {
return std::make_pair(kPeerTypeAttribute,
GetStringValueFromUpbStruct(
struct_pb.struct_pb, kMetadataExchangeTypeKey,
struct_pb.arena.ptr()));
}
// Only handle GKE type for now.
switch (remote_type_) {
case GcpResourceType::kGke:
if ((pos_ - 2 - local_labels_size) >= kGkeAttributeList.size()) {
return absl::nullopt;
}
return std::make_pair(
kGkeAttributeList[pos_ - 2 - local_labels_size].otel_attribute,
GetStringValueFromUpbStruct(
struct_pb.struct_pb,
kGkeAttributeList[pos_ - 2 - local_labels_size]
.metadata_attribute,
struct_pb.arena.ptr()));
case GcpResourceType::kUnknown:
return absl::nullopt;
const size_t fixed_attribute_end =
local_labels_size + kFixedAttributes.size();
if (pos_ < fixed_attribute_end) {
return NextFromAttributeList(struct_pb, kFixedAttributes,
local_labels_size);
}
return NextFromAttributeList(struct_pb, GetAttributesForType(remote_type_),
fixed_attribute_end);
}

size_t Size() const override {
auto& struct_pb = GetDecodedMetadata();
if (struct_pb.struct_pb == nullptr) {
return local_labels_.size();
}
if (remote_type_ != GcpResourceType::kGke) {
return local_labels_.size() + 1;
}
return local_labels_.size() + kGkeAttributeList.size() + 1;
return local_labels_.size() + kFixedAttributes.size() +
GetAttributesForType(remote_type_).size();
}

void ResetIteratorPosition() override { pos_ = 0; }
Expand All @@ -263,7 +246,7 @@ class MeshLabelsIterable : public LabelsIterable {
}

private:
struct GkeAttribute {
struct RemoteAttribute {
absl::string_view otel_attribute;
absl::string_view metadata_attribute;
};
Expand All @@ -273,18 +256,56 @@ class MeshLabelsIterable : public LabelsIterable {
google_protobuf_Struct* struct_pb = nullptr;
};

static constexpr std::array<GkeAttribute, 6> kGkeAttributeList = {
GkeAttribute{kPeerWorkloadNameAttribute,
kMetadataExchangeWorkloadNameKey},
GkeAttribute{kPeerNamespaceNameAttribute,
kMetadataExchangeNamespaceNameKey},
GkeAttribute{kPeerClusterNameAttribute, kMetadataExchangeClusterNameKey},
GkeAttribute{kPeerLocationAttribute, kMetadataExchangeLocationKey},
GkeAttribute{kPeerProjectIdAttribute, kMetadataExchangeProjectIdKey},
GkeAttribute{kPeerCanonicalServiceAttribute,
kMetadataExchangeCanonicalServiceKey},
static constexpr std::array<RemoteAttribute, 2> kFixedAttributes = {
RemoteAttribute{kPeerTypeAttribute, kMetadataExchangeTypeKey},
RemoteAttribute{kPeerCanonicalServiceAttribute,
kMetadataExchangeCanonicalServiceKey},
};

static constexpr std::array<RemoteAttribute, 5> kGkeAttributeList = {
RemoteAttribute{kPeerWorkloadNameAttribute,
kMetadataExchangeWorkloadNameKey},
RemoteAttribute{kPeerNamespaceNameAttribute,
kMetadataExchangeNamespaceNameKey},
RemoteAttribute{kPeerClusterNameAttribute,
kMetadataExchangeClusterNameKey},
RemoteAttribute{kPeerLocationAttribute, kMetadataExchangeLocationKey},
RemoteAttribute{kPeerProjectIdAttribute, kMetadataExchangeProjectIdKey},
};
static constexpr std::array<RemoteAttribute, 3> kGceAttributeList = {
RemoteAttribute{kPeerWorkloadNameAttribute,
kMetadataExchangeWorkloadNameKey},
RemoteAttribute{kPeerLocationAttribute, kMetadataExchangeLocationKey},
RemoteAttribute{kPeerProjectIdAttribute, kMetadataExchangeProjectIdKey},
};

static absl::Span<const RemoteAttribute> GetAttributesForType(
GcpResourceType remote_type) {
switch (remote_type) {
case GcpResourceType::kGke:
return kGkeAttributeList;
case GcpResourceType::kGce:
return kGceAttributeList;
default:
return {};
}
}

absl::optional<std::pair<absl::string_view, absl::string_view>>
NextFromAttributeList(const StructPb& struct_pb,
absl::Span<const RemoteAttribute> attributes,
size_t start_index) {
GPR_DEBUG_ASSERT(pos_ >= start_index);
const size_t index = pos_ - start_index;
if (index >= attributes.size()) return absl::nullopt;
++pos_;
const auto& attribute = attributes[index];
return std::make_pair(attribute.otel_attribute,
GetStringValueFromUpbStruct(
struct_pb.struct_pb, attribute.metadata_attribute,
struct_pb.arena.ptr()));
}

StructPb& GetDecodedMetadata() const {
auto* slice = absl::get_if<grpc_core::Slice>(&metadata_);
if (slice == nullptr) {
Expand Down Expand Up @@ -319,8 +340,12 @@ class MeshLabelsIterable : public LabelsIterable {
uint32_t pos_ = 0;
};

constexpr std::array<MeshLabelsIterable::GkeAttribute, 6>
constexpr std::array<MeshLabelsIterable::RemoteAttribute, 2>
MeshLabelsIterable::kFixedAttributes;
constexpr std::array<MeshLabelsIterable::RemoteAttribute, 5>
MeshLabelsIterable::kGkeAttributeList;
constexpr std::array<MeshLabelsIterable::RemoteAttribute, 3>
MeshLabelsIterable::kGceAttributeList;

} // namespace

Expand Down Expand Up @@ -363,13 +388,13 @@ ServiceMeshLabelsInjector::ServiceMeshLabelsInjector(
opentelemetry::sdk::resource::SemanticConventions::kK8sNamespaceName);
absl::string_view cluster_name_value = GetStringValueFromAttributeMap(
map, opentelemetry::sdk::resource::SemanticConventions::kK8sClusterName);
absl::string_view cluster_location_value = GetStringValueFromAttributeMap(
absl::string_view location_value = GetStringValueFromAttributeMap(
map, opentelemetry::sdk::resource::SemanticConventions::
kCloudRegion); // if regional
if (cluster_location_value == "unknown") {
cluster_location_value = GetStringValueFromAttributeMap(
kCloudAvailabilityZone); // if zonal
if (location_value == "unknown") {
location_value = GetStringValueFromAttributeMap(
map, opentelemetry::sdk::resource::SemanticConventions::
kCloudAvailabilityZone); // if zonal
kCloudRegion); // if regional
}
absl::string_view project_id_value = GetStringValueFromAttributeMap(
map, opentelemetry::sdk::resource::SemanticConventions::kCloudAccountId);
Expand All @@ -378,7 +403,8 @@ ServiceMeshLabelsInjector::ServiceMeshLabelsInjector(
// Create metadata to be sent over wire.
AddStringKeyValueToStructProto(metadata, kMetadataExchangeTypeKey, type_value,
arena.ptr());
// Only handle GKE for now
AddStringKeyValueToStructProto(metadata, kMetadataExchangeCanonicalServiceKey,
canonical_service_value, arena.ptr());
if (type_value == kGkeType) {
AddStringKeyValueToStructProto(metadata, kMetadataExchangeWorkloadNameKey,
workload_name_value, arena.ptr());
Expand All @@ -387,12 +413,16 @@ ServiceMeshLabelsInjector::ServiceMeshLabelsInjector(
AddStringKeyValueToStructProto(metadata, kMetadataExchangeClusterNameKey,
cluster_name_value, arena.ptr());
AddStringKeyValueToStructProto(metadata, kMetadataExchangeLocationKey,
cluster_location_value, arena.ptr());
location_value, arena.ptr());
AddStringKeyValueToStructProto(metadata, kMetadataExchangeProjectIdKey,
project_id_value, arena.ptr());
} else if (type_value == kGceType) {
AddStringKeyValueToStructProto(metadata, kMetadataExchangeWorkloadNameKey,
workload_name_value, arena.ptr());
AddStringKeyValueToStructProto(metadata, kMetadataExchangeLocationKey,
location_value, arena.ptr());
AddStringKeyValueToStructProto(metadata, kMetadataExchangeProjectIdKey,
project_id_value, arena.ptr());
AddStringKeyValueToStructProto(metadata,
kMetadataExchangeCanonicalServiceKey,
canonical_service_value, arena.ptr());
}

size_t output_length;
Expand Down
37 changes: 34 additions & 3 deletions test/cpp/ext/csm/metadata_exchange_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace {

class TestScenario {
public:
enum class ResourceType : std::uint8_t { kGke, kUnknown };
enum class ResourceType : std::uint8_t { kGke, kGce, kUnknown };
enum class XdsBootstrapSource : std::uint8_t { kFromFile, kFromConfig };

explicit TestScenario(ResourceType type, XdsBootstrapSource bootstrap_source)
Expand All @@ -55,6 +55,8 @@ class TestScenario {
switch (type_) {
case ResourceType::kGke:
return TestGkeResource();
case ResourceType::kGce:
return TestGceResource();
case ResourceType::kUnknown:
return TestUnknownResource();
}
Expand All @@ -66,6 +68,9 @@ class TestScenario {
case ResourceType::kGke:
ret_val += "Gke";
break;
case ResourceType::kGce:
ret_val += "Gce";
break;
case ResourceType::kUnknown:
ret_val += "Unknown";
break;
Expand Down Expand Up @@ -98,6 +103,14 @@ class TestScenario {
return opentelemetry::sdk::resource::Resource::Create(attributes);
}

static opentelemetry::sdk::resource::Resource TestGceResource() {
opentelemetry::sdk::common::AttributeMap attributes;
attributes.SetAttribute("cloud.platform", "gcp_compute_engine");
attributes.SetAttribute("cloud.availability_zone", "zone");
attributes.SetAttribute("cloud.account.id", "id");
return opentelemetry::sdk::resource::Resource::Create(attributes);
}

static opentelemetry::sdk::resource::Resource TestUnknownResource() {
opentelemetry::sdk::common::AttributeMap attributes;
attributes.SetAttribute("cloud.platform", "random");
Expand Down Expand Up @@ -163,6 +176,9 @@ class MetadataExchangeTest
absl::get<std::string>(attributes.at("csm.workload_canonical_service")),
"canonical_service");
EXPECT_EQ(absl::get<std::string>(attributes.at("csm.mesh_id")), "mesh-id");
EXPECT_EQ(absl::get<std::string>(
attributes.at("csm.remote_workload_canonical_service")),
"canonical_service");
if (verify_client_only_attributes) {
EXPECT_EQ(absl::get<std::string>(attributes.at("csm.service_name")),
"unknown");
Expand Down Expand Up @@ -190,9 +206,20 @@ class MetadataExchangeTest
EXPECT_EQ(absl::get<std::string>(
attributes.at("csm.remote_workload_project_id")),
"id");
break;
case TestScenario::ResourceType::kGce:
EXPECT_EQ(
absl::get<std::string>(attributes.at("csm.remote_workload_type")),
"gcp_compute_engine");
EXPECT_EQ(
absl::get<std::string>(attributes.at("csm.remote_workload_name")),
"workload");
EXPECT_EQ(absl::get<std::string>(
attributes.at("csm.remote_workload_location")),
"zone");
EXPECT_EQ(absl::get<std::string>(
attributes.at("csm.remote_workload_canonical_service")),
"canonical_service");
attributes.at("csm.remote_workload_project_id")),
"id");
break;
case TestScenario::ResourceType::kUnknown:
EXPECT_EQ(
Expand Down Expand Up @@ -366,6 +393,10 @@ INSTANTIATE_TEST_SUITE_P(
TestScenario::XdsBootstrapSource::kFromConfig),
TestScenario(TestScenario::ResourceType::kGke,
TestScenario::XdsBootstrapSource::kFromFile),
TestScenario(TestScenario::ResourceType::kGce,
TestScenario::XdsBootstrapSource::kFromConfig),
TestScenario(TestScenario::ResourceType::kGce,
TestScenario::XdsBootstrapSource::kFromFile),
TestScenario(TestScenario::ResourceType::kUnknown,
TestScenario::XdsBootstrapSource::kFromConfig),
TestScenario(TestScenario::ResourceType::kUnknown,
Expand Down

0 comments on commit 8231340

Please sign in to comment.