Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/common/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ bool extractPeerMetadataFromUpstreamMetadata(
std::vector<absl::string_view> parts = absl::StrSplit(endpoint_labels, ';');
// workload label should semicolon separated four parts string:
// workload_name;namespace;canonical_service;canonical_revision;cluster_id.
if (parts.size() < 4) {
if (parts.size() < 5) {
return false;
}

Expand Down
157 changes: 107 additions & 50 deletions extensions/common/metadata_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "extensions/common/metadata_object.h"

#include "absl/strings/str_join.h"
#include "flatbuffers/flatbuffers.h"
#include "source/common/common/hash.h"

Expand Down Expand Up @@ -126,12 +127,48 @@ std::string WorkloadMetadataObject::baggage() const {
default:
break;
}
return absl::StrCat("k8s.cluster.name=", cluster_name_,
",k8s.namespace.name=", namespace_name_, ",k8s.",
workload_type, ".name=", workload_name_,
",service.name=", canonical_name_,
",service.version=", canonical_revision_,
",app.name=", app_name_, ",app.version=", app_version_);
std::vector<absl::string_view> parts;
parts.push_back("k8s.");
parts.push_back(workload_type);
parts.push_back(".name=");
parts.push_back(workload_name_);
if (!cluster_name_.empty()) {
parts.push_back(",");
parts.push_back(ClusterNameToken);
parts.push_back("=");
parts.push_back(cluster_name_);
}
if (!namespace_name_.empty()) {
parts.push_back(",");
parts.push_back(NamespaceNameToken);
parts.push_back("=");
parts.push_back(namespace_name_);
}
if (!canonical_name_.empty()) {
parts.push_back(",");
parts.push_back(ServiceNameToken);
parts.push_back("=");
parts.push_back(canonical_name_);
}
if (!canonical_revision_.empty()) {
parts.push_back(",");
parts.push_back(ServiceVersionToken);
parts.push_back("=");
parts.push_back(canonical_revision_);
}
if (!app_name_.empty()) {
parts.push_back(",");
parts.push_back(AppNameToken);
parts.push_back("=");
parts.push_back(app_name_);
}
if (!app_version_.empty()) {
parts.push_back(",");
parts.push_back(AppVersionToken);
parts.push_back("=");
parts.push_back(app_version_);
}
return absl::StrJoin(parts, "");
}

absl::optional<uint64_t> WorkloadMetadataObject::hash() const {
Expand All @@ -152,7 +189,7 @@ std::string_view toStdStringView(absl::string_view view) {
} // namespace

flatbuffers::DetachedBuffer convertWorkloadMetadataToFlatNode(
const Istio::Common::WorkloadMetadataObject& obj) {
const WorkloadMetadataObject& obj) {
flatbuffers::FlatBufferBuilder fbb;

flatbuffers::Offset<flatbuffers::String> name, cluster, namespace_,
Expand All @@ -165,22 +202,22 @@ flatbuffers::DetachedBuffer convertWorkloadMetadataToFlatNode(
workload_name = fbb.CreateString(toStdStringView(obj.workload_name_));

switch (obj.workload_type_) {
case Istio::Common::WorkloadType::Deployment:
case WorkloadType::Deployment:
owner = fbb.CreateString(absl::StrCat(OwnerPrefix, obj.namespace_name_,
"/", DeploymentSuffix, "s/",
obj.workload_name_));
break;
case Istio::Common::WorkloadType::Job:
case WorkloadType::Job:
owner =
fbb.CreateString(absl::StrCat(OwnerPrefix, obj.namespace_name_, "/",
JobSuffix, "s/", obj.workload_name_));
break;
case Istio::Common::WorkloadType::CronJob:
case WorkloadType::CronJob:
owner = fbb.CreateString(absl::StrCat(OwnerPrefix, obj.namespace_name_,
"/", CronJobSuffix, "s/",
obj.workload_name_));
break;
case Istio::Common::WorkloadType::Pod:
case WorkloadType::Pod:
owner =
fbb.CreateString(absl::StrCat(OwnerPrefix, obj.namespace_name_, "/",
PodSuffix, "s/", obj.workload_name_));
Expand Down Expand Up @@ -213,62 +250,82 @@ flatbuffers::DetachedBuffer convertWorkloadMetadataToFlatNode(
return fbb.Release();
}

Istio::Common::WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(
WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(
const Wasm::Common::FlatNode& node) {
const absl::string_view instance = toAbslStringView(node.name());
const absl::string_view cluster = toAbslStringView(node.cluster_id());
const absl::string_view workload = toAbslStringView(node.workload_name());
const absl::string_view namespace_name = toAbslStringView(node.namespace_());
const auto* labels = node.labels();

const auto* name_iter =
labels->LookupByKey("service.istio.io/canonical-name");
const auto* name = name_iter ? name_iter->value() : nullptr;
const absl::string_view canonical_name = toAbslStringView(name);
absl::string_view canonical_name;
absl::string_view canonical_revision;
absl::string_view app_name;
absl::string_view app_version;
if (labels) {
const auto* name_iter =
labels->LookupByKey("service.istio.io/canonical-name");
const auto* name = name_iter ? name_iter->value() : nullptr;
canonical_name = toAbslStringView(name);

const auto* revision_iter =
labels->LookupByKey("service.istio.io/canonical-revision");
const auto* revision = revision_iter ? revision_iter->value() : nullptr;
const absl::string_view canonical_revision = toAbslStringView(revision);
const auto* revision_iter =
labels->LookupByKey("service.istio.io/canonical-revision");
const auto* revision = revision_iter ? revision_iter->value() : nullptr;
canonical_revision = toAbslStringView(revision);

const auto* app_iter = labels->LookupByKey("app");
const auto* app = app_iter ? app_iter->value() : nullptr;
const absl::string_view app_name = toAbslStringView(app);
const auto* app_iter = labels->LookupByKey("app");
const auto* app = app_iter ? app_iter->value() : nullptr;
app_name = toAbslStringView(app);

const auto* version_iter = labels->LookupByKey("version");
const auto* version = version_iter ? version_iter->value() : nullptr;
const absl::string_view app_version = toAbslStringView(version);
const auto* version_iter = labels->LookupByKey("version");
const auto* version = version_iter ? version_iter->value() : nullptr;
app_version = toAbslStringView(version);
}

Istio::Common::WorkloadType workload_type = Istio::Common::WorkloadType::Pod;
WorkloadType workload_type = WorkloadType::Pod;
// Strip "s/workload_name" and check for workload type.
absl::string_view owner = toAbslStringView(node.owner());
owner.remove_suffix(workload.size() + 2);
size_t last = owner.rfind('/');
if (last != absl::string_view::npos) {
const auto it = ALL_WORKLOAD_TOKENS.find(owner.substr(last + 1));
if (it != ALL_WORKLOAD_TOKENS.end()) {
switch (it->second) {
case WorkloadType::Deployment:
workload_type = Istio::Common::WorkloadType::Deployment;
break;
case WorkloadType::CronJob:
workload_type = Istio::Common::WorkloadType::CronJob;
break;
case WorkloadType::Job:
workload_type = Istio::Common::WorkloadType::Job;
break;
case WorkloadType::Pod:
workload_type = Istio::Common::WorkloadType::Pod;
break;
default:
break;
if (owner.size() > workload.size() + 2) {
owner.remove_suffix(workload.size() + 2);
size_t last = owner.rfind('/');
if (last != absl::string_view::npos) {
const auto it = ALL_WORKLOAD_TOKENS.find(owner.substr(last + 1));
if (it != ALL_WORKLOAD_TOKENS.end()) {
switch (it->second) {
case WorkloadType::Deployment:
workload_type = WorkloadType::Deployment;
break;
case WorkloadType::CronJob:
workload_type = WorkloadType::CronJob;
break;
case WorkloadType::Job:
workload_type = WorkloadType::Job;
break;
case WorkloadType::Pod:
workload_type = WorkloadType::Pod;
break;
default:
break;
}
}
}
}

return Istio::Common::WorkloadMetadataObject(
instance, cluster, namespace_name, workload, canonical_name,
canonical_revision, app_name, app_version, workload_type);
return WorkloadMetadataObject(instance, cluster, namespace_name, workload,
canonical_name, canonical_revision, app_name,
app_version, workload_type);
}

absl::optional<WorkloadMetadataObject> convertEndpointMetadata(
const std::string& endpoint_encoding) {
std::vector<absl::string_view> parts = absl::StrSplit(endpoint_encoding, ';');
if (parts.size() < 5) {
return {};
}
// TODO: we cannot determine workload type from the encoding.
return absl::make_optional<WorkloadMetadataObject>(
"", parts[4], parts[1], parts[0], parts[2], parts[3], "", "",
WorkloadType::Pod);
}

} // namespace Common
Expand Down
12 changes: 10 additions & 2 deletions extensions/common/metadata_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,19 @@ struct WorkloadMetadataObject : public Envoy::StreamInfo::FilterState::Object,

// Convert metadata object to flatbuffer.
flatbuffers::DetachedBuffer convertWorkloadMetadataToFlatNode(
const Istio::Common::WorkloadMetadataObject& obj);
const WorkloadMetadataObject& obj);

// Convert flatbuffer to metadata object.
Istio::Common::WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(
WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(
const Wasm::Common::FlatNode& node);

// Convert endpoint metadata string to a metadata object.
// Telemetry metadata is compressed into a semicolon separated string:
// workload-name;namespace;canonical-service-name;canonical-service-revision;cluster-id.
// Telemetry metadata is stored as a string under "istio", "workload" field
// path.
absl::optional<WorkloadMetadataObject> convertEndpointMetadata(
const std::string& endpoint_encoding);

} // namespace Common
} // namespace Istio
69 changes: 47 additions & 22 deletions extensions/common/metadata_object_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,26 @@ TEST(WorkloadMetadataObjectTest, Baggage) {
WorkloadType::Job);

EXPECT_EQ(deploy.baggage(),
absl::StrCat("k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,k8s.deployment.name=foo,",
absl::StrCat("k8s.deployment.name=foo,k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,",
"service.name=foo-service,service.version=v1alpha3,",
"app.name=foo-app,app.version=v1"));

EXPECT_EQ(pod.baggage(),
absl::StrCat("k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,k8s.pod.name=foo,",
absl::StrCat("k8s.pod.name=foo,k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,",
"service.name=foo-service,service.version=v1alpha3,",
"app.name=foo-app,app.version=v1"));

EXPECT_EQ(cronjob.baggage(),
absl::StrCat("k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,k8s.cronjob.name=foo,"
absl::StrCat("k8s.cronjob.name=foo,k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,"
"service.name=foo-service,service.version=v1alpha3,",
"app.name=foo-app,app.version=v1"));

EXPECT_EQ(job.baggage(),
absl::StrCat("k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,k8s.job.name=foo,",
absl::StrCat("k8s.job.name=foo,k8s.cluster.name=my-cluster,",
"k8s.namespace.name=default,",
"service.name=foo-service,service.version=v1alpha3,",
"app.name=foo-app,app.version=v1"));
}
Expand All @@ -86,9 +86,9 @@ void checkFlatNodeConversion(const WorkloadMetadataObject& obj) {
TEST(WorkloadMetadataObjectTest, FromBaggage) {
{
auto obj = WorkloadMetadataObject::fromBaggage(
absl::StrCat("k8s.cluster.name=my-cluster,k8s.namespace.name=default,",
"k8s.deployment.name=foo,service.name=foo-service,",
"service.version=v1alpha3"));
absl::StrCat("k8s.deployment.name=foo,k8s.cluster.name=my-cluster,k8s."
"namespace.name=default,",
"service.name=foo-service,", "service.version=v1alpha3"));
EXPECT_EQ(obj.canonical_name_, "foo-service");
EXPECT_EQ(obj.canonical_revision_, "v1alpha3");
EXPECT_EQ(obj.workload_type_, WorkloadType::Deployment);
Expand All @@ -100,9 +100,9 @@ TEST(WorkloadMetadataObjectTest, FromBaggage) {

{
auto obj = WorkloadMetadataObject::fromBaggage(
absl::StrCat("k8s.cluster.name=my-cluster,k8s.namespace.name=test,k8s."
"pod.name=foo-pod-435,service.name=",
"foo-service,service.version=v1beta2"));
absl::StrCat("k8s.pod.name=foo-pod-435,k8s.cluster.name=my-cluster,k8s."
"namespace.name=test,"
"service.name=foo-service,service.version=v1beta2"));

EXPECT_EQ(obj.canonical_name_, "foo-service");
EXPECT_EQ(obj.canonical_revision_, "v1beta2");
Expand All @@ -116,9 +116,9 @@ TEST(WorkloadMetadataObjectTest, FromBaggage) {

{
auto obj = WorkloadMetadataObject::fromBaggage(
absl::StrCat("k8s.cluster.name=my-cluster,k8s.namespace.name=test,",
"k8s.job.name=foo-job-435,service.name=foo-service,",
"service.version=v1beta4"));
absl::StrCat("k8s.job.name=foo-job-435,k8s.cluster.name=my-cluster,k8s."
"namespace.name=test,",
"service.name=foo-service,", "service.version=v1beta4"));

EXPECT_EQ(obj.canonical_name_, "foo-service");
EXPECT_EQ(obj.canonical_revision_, "v1beta4");
Expand All @@ -132,9 +132,9 @@ TEST(WorkloadMetadataObjectTest, FromBaggage) {

{
auto obj = WorkloadMetadataObject::fromBaggage(
absl::StrCat("k8s.cluster.name=my-cluster,k8s.namespace.name=test,",
"k8s.cronjob.name=foo-cronjob,service.name=foo-service,",
"service.version=v1beta4"));
absl::StrCat("k8s.cronjob.name=foo-cronjob,k8s.cluster.name=my-cluster,"
"k8s.namespace.name=test,",
"service.name=foo-service,", "service.version=v1beta4"));

EXPECT_EQ(obj.canonical_name_, "foo-service");
EXPECT_EQ(obj.canonical_revision_, "v1beta4");
Expand All @@ -149,8 +149,8 @@ TEST(WorkloadMetadataObjectTest, FromBaggage) {

{
auto obj = WorkloadMetadataObject::fromBaggage(absl::StrCat(
"k8s.namespace.name=default,",
"k8s.deployment.name=foo,service.name=foo-service,",
"k8s.deployment.name=foo,k8s.namespace.name=default,",
"service.name=foo-service,",
"service.version=v1alpha3,app.name=foo-app,app.version=v1"));

EXPECT_EQ(obj.canonical_name_, "foo-service");
Expand All @@ -165,5 +165,30 @@ TEST(WorkloadMetadataObjectTest, FromBaggage) {
}
}

TEST(WorkloadMetadataObjectTest, ConvertFromFlatNode) {
flatbuffers::FlatBufferBuilder fbb;
Wasm::Common::FlatNodeBuilder builder(fbb);
auto data = builder.Finish();
fbb.Finish(data);
auto buffer = fbb.Release();
const auto& node =
*flatbuffers::GetRoot<Wasm::Common::FlatNode>(buffer.data());
auto obj = convertFlatNodeToWorkloadMetadata(node);
EXPECT_EQ(obj.baggage(), "k8s.pod.name=");
}

TEST(WorkloadMetadataObjectTest, ConvertFromEndpointMetadata) {
EXPECT_EQ(absl::nullopt, convertEndpointMetadata(""));
EXPECT_EQ(absl::nullopt, convertEndpointMetadata("a;b"));
EXPECT_EQ(absl::nullopt, convertEndpointMetadata("a;;;b"));
EXPECT_EQ(absl::nullopt, convertEndpointMetadata("a;b;c;d"));
auto obj =
convertEndpointMetadata("foo-pod;default;foo-service;v1;my-cluster");
ASSERT_TRUE(obj.has_value());
EXPECT_EQ(obj->baggage(),
"k8s.pod.name=foo-pod,k8s.cluster.name=my-cluster,k8s.namespace."
"name=default,service.name=foo-service,service.version=v1");
}

} // namespace Common
} // namespace Istio
1 change: 0 additions & 1 deletion source/extensions/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ envoy_cc_library(
":utils_lib",
"//src/istio/authn:context_proto_cc_proto",
"//src/istio/utils:attribute_names_lib",
"//src/istio/utils:utils_lib",
"@envoy//source/exe:envoy_common_lib",
],
)
Expand Down
Loading