mirror of https://github.com/istio/proxy.git
move flatbuffers
Change-Id: Ic0390cdcf4f6696dbedf644f25bf1d4c3b2bf8c6 Signed-off-by: Kuat Yessenov <kuat@google.com>
This commit is contained in:
parent
0ecfabc99a
commit
789b8a7e95
|
|
@ -20,15 +20,6 @@ load(
|
|||
"envoy_cc_library",
|
||||
"envoy_cc_test",
|
||||
)
|
||||
load(
|
||||
"@com_github_google_flatbuffers//:build_defs.bzl",
|
||||
"DEFAULT_FLATC_ARGS",
|
||||
"flatbuffer_library_public",
|
||||
)
|
||||
load(
|
||||
"@envoy//test/extensions:extensions_build_system.bzl",
|
||||
"envoy_extension_cc_benchmark_binary",
|
||||
)
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
|
@ -44,11 +35,7 @@ envoy_cc_library(
|
|||
],
|
||||
repository = "@envoy",
|
||||
deps = [
|
||||
":metadata_object_lib",
|
||||
":node_info_fb_cc",
|
||||
":util",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
"@proxy_wasm_cpp_host//:null_lib",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
@ -66,18 +53,6 @@ envoy_cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
envoy_cc_test(
|
||||
name = "proto_util_test",
|
||||
size = "small",
|
||||
srcs = ["proto_util_test.cc"],
|
||||
repository = "@envoy",
|
||||
deps = [
|
||||
":node_info_fb_cc",
|
||||
":proto_util",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
envoy_cc_test(
|
||||
name = "util_test",
|
||||
size = "small",
|
||||
|
|
@ -88,62 +63,12 @@ envoy_cc_test(
|
|||
],
|
||||
)
|
||||
|
||||
# TODO: fix this build on mac m1?
|
||||
envoy_extension_cc_benchmark_binary(
|
||||
name = "proto_util_speed_test",
|
||||
srcs = select({
|
||||
"@envoy//bazel:linux": ["proto_util_speed_test.cc"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
extension_names = ["envoy.wasm.runtime.null"],
|
||||
external_deps = [
|
||||
"benchmark",
|
||||
],
|
||||
repository = "@envoy",
|
||||
deps = select({
|
||||
"@envoy//bazel:linux": [
|
||||
":metadata_object_lib",
|
||||
":node_info_fb_cc",
|
||||
":proto_util",
|
||||
"@envoy//source/common/stream_info:filter_state_lib",
|
||||
"@envoy//source/extensions/filters/common/expr:cel_state_lib",
|
||||
"@envoy//test/test_common:status_utility_lib",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
flatbuffer_library_public(
|
||||
name = "node_info_fbs",
|
||||
srcs = ["node_info.fbs"],
|
||||
outs = [
|
||||
"node_info_bfbs_generated.h",
|
||||
"node_info_generated.h",
|
||||
],
|
||||
flatc_args = DEFAULT_FLATC_ARGS + ["--bfbs-gen-embed"],
|
||||
language_flag = "-c",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "node_info_fb_cc",
|
||||
srcs = [":node_info_fbs"],
|
||||
hdrs = [":node_info_fbs"],
|
||||
features = ["-parse_headers"],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
"@com_github_google_flatbuffers//:flatbuffers",
|
||||
"@com_github_google_flatbuffers//:runtime_cc",
|
||||
],
|
||||
)
|
||||
|
||||
envoy_cc_library(
|
||||
name = "metadata_object_lib",
|
||||
srcs = ["metadata_object.cc"],
|
||||
hdrs = ["metadata_object.h"],
|
||||
repository = "@envoy",
|
||||
deps = [
|
||||
":node_info_fb_cc",
|
||||
"@com_github_google_flatbuffers//:flatbuffers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
"@envoy//envoy/common:hashable_interface",
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
#include "extensions/common/metadata_object.h"
|
||||
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "extensions/common/node_info_bfbs_generated.h"
|
||||
#include "source/common/common/hash.h"
|
||||
|
||||
namespace Istio {
|
||||
|
|
@ -170,108 +168,89 @@ absl::optional<uint64_t> WorkloadMetadataObject::hash() const {
|
|||
return Envoy::HashUtil::xxHash64(absl::StrCat(instance_name_, "/", namespace_name_));
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Returns a string view stored in a flatbuffers string.
|
||||
absl::string_view toAbslStringView(const flatbuffers::String* str) {
|
||||
return str ? absl::string_view(str->c_str(), str->size()) : absl::string_view();
|
||||
}
|
||||
|
||||
std::string_view toStdStringView(absl::string_view view) {
|
||||
return std::string_view(view.data(), view.size());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string convertWorkloadMetadataToFlatNode(const WorkloadMetadataObject& obj) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
|
||||
flatbuffers::Offset<flatbuffers::String> name, cluster, namespace_, workload_name, owner,
|
||||
identity;
|
||||
std::vector<flatbuffers::Offset<Wasm::Common::KeyVal>> labels;
|
||||
|
||||
name = fbb.CreateString(toStdStringView(obj.instance_name_));
|
||||
namespace_ = fbb.CreateString(toStdStringView(obj.namespace_name_));
|
||||
cluster = fbb.CreateString(toStdStringView(obj.cluster_name_));
|
||||
workload_name = fbb.CreateString(toStdStringView(obj.workload_name_));
|
||||
identity = fbb.CreateString(toStdStringView(obj.identity_));
|
||||
|
||||
switch (obj.workload_type_) {
|
||||
std::string WorkloadMetadataObject::owner() const {
|
||||
switch (workload_type_) {
|
||||
case WorkloadType::Deployment:
|
||||
owner = fbb.CreateString(absl::StrCat(OwnerPrefix, obj.namespace_name_, "/", DeploymentSuffix,
|
||||
"s/", obj.workload_name_));
|
||||
break;
|
||||
return absl::StrCat(OwnerPrefix, namespace_name_, "/", DeploymentSuffix, "s/", workload_name_);
|
||||
case WorkloadType::Job:
|
||||
owner = fbb.CreateString(
|
||||
absl::StrCat(OwnerPrefix, obj.namespace_name_, "/", JobSuffix, "s/", obj.workload_name_));
|
||||
break;
|
||||
return absl::StrCat(OwnerPrefix, namespace_name_, "/", JobSuffix, "s/", workload_name_);
|
||||
case WorkloadType::CronJob:
|
||||
owner = fbb.CreateString(absl::StrCat(OwnerPrefix, obj.namespace_name_, "/", CronJobSuffix,
|
||||
"s/", obj.workload_name_));
|
||||
break;
|
||||
return absl::StrCat(OwnerPrefix, namespace_name_, "/", CronJobSuffix, "s/", workload_name_);
|
||||
case WorkloadType::Pod:
|
||||
owner = fbb.CreateString(
|
||||
absl::StrCat(OwnerPrefix, obj.namespace_name_, "/", PodSuffix, "s/", obj.workload_name_));
|
||||
break;
|
||||
return absl::StrCat(OwnerPrefix, namespace_name_, "/", PodSuffix, "s/", workload_name_);
|
||||
}
|
||||
|
||||
labels.push_back(
|
||||
Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(CanonicalNameLabel),
|
||||
fbb.CreateString(toStdStringView(obj.canonical_name_))));
|
||||
labels.push_back(
|
||||
Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(CanonicalRevisionLabel),
|
||||
fbb.CreateString(toStdStringView(obj.canonical_revision_))));
|
||||
labels.push_back(Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(AppLabel),
|
||||
fbb.CreateString(toStdStringView(obj.app_name_))));
|
||||
labels.push_back(Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(VersionLabel),
|
||||
fbb.CreateString(toStdStringView(obj.app_version_))));
|
||||
|
||||
auto labels_offset = fbb.CreateVectorOfSortedTables(&labels);
|
||||
Wasm::Common::FlatNodeBuilder node(fbb);
|
||||
node.add_name(name);
|
||||
node.add_cluster_id(cluster);
|
||||
node.add_namespace_(namespace_);
|
||||
node.add_workload_name(workload_name);
|
||||
node.add_owner(owner);
|
||||
node.add_labels(labels_offset);
|
||||
node.add_identity(identity);
|
||||
auto data = node.Finish();
|
||||
fbb.Finish(data);
|
||||
auto fb = fbb.Release();
|
||||
return std::string(reinterpret_cast<const char*>(fb.data()), fb.size());
|
||||
}
|
||||
|
||||
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 absl::string_view identity = toAbslStringView(node.identity());
|
||||
const auto* labels = node.labels();
|
||||
void WorkloadMetadataObject::toStruct(google::protobuf::Struct* out) const {
|
||||
if (!instance_name_.empty()) {
|
||||
(*out->mutable_fields())["NAME"].set_string_value(instance_name_);
|
||||
}
|
||||
if (!cluster_name_.empty()) {
|
||||
(*out->mutable_fields())["CLUSTER_ID"].set_string_value(cluster_name_);
|
||||
}
|
||||
if (!namespace_name_.empty()) {
|
||||
(*out->mutable_fields())["NAMESPACE"].set_string_value(namespace_name_);
|
||||
}
|
||||
if (!workload_name_.empty()) {
|
||||
(*out->mutable_fields())["WORKLOAD_NAME"].set_string_value(workload_name_);
|
||||
}
|
||||
(*out->mutable_fields())["OWNER"].set_string_value(owner());
|
||||
auto* map = (*out->mutable_fields())["LABELS"].mutable_struct_value();
|
||||
if (!canonical_name_.empty()) {
|
||||
(*map->mutable_fields())[CanonicalNameLabel].set_string_value(canonical_name_);
|
||||
}
|
||||
if (!canonical_revision_.empty()) {
|
||||
(*map->mutable_fields())[CanonicalRevisionLabel].set_string_value(canonical_revision_);
|
||||
}
|
||||
if (!app_name_.empty()) {
|
||||
(*map->mutable_fields())[AppLabel].set_string_value(app_name_);
|
||||
}
|
||||
if (!app_version_.empty()) {
|
||||
(*map->mutable_fields())[VersionLabel].set_string_value(app_version_);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<WorkloadMetadataObject>
|
||||
convertStructToWorkloadMetadata(const google::protobuf::Struct& metadata) {
|
||||
absl::string_view instance;
|
||||
absl::string_view cluster;
|
||||
absl::string_view workload;
|
||||
absl::string_view namespace_name;
|
||||
absl::string_view identity;
|
||||
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(CanonicalNameLabel);
|
||||
const auto* name = name_iter ? name_iter->value() : nullptr;
|
||||
canonical_name = toAbslStringView(name);
|
||||
absl::string_view owner;
|
||||
|
||||
const auto* revision_iter = labels->LookupByKey(CanonicalRevisionLabel);
|
||||
const auto* revision = revision_iter ? revision_iter->value() : nullptr;
|
||||
canonical_revision = toAbslStringView(revision);
|
||||
|
||||
const auto* app_iter = labels->LookupByKey(AppLabel);
|
||||
const auto* app = app_iter ? app_iter->value() : nullptr;
|
||||
app_name = toAbslStringView(app);
|
||||
|
||||
const auto* version_iter = labels->LookupByKey(VersionLabel);
|
||||
const auto* version = version_iter ? version_iter->value() : nullptr;
|
||||
app_version = toAbslStringView(version);
|
||||
for (const auto& it : metadata.fields()) {
|
||||
if (it.first == "NAME") {
|
||||
instance = it.second.string_value();
|
||||
} else if (it.first == "NAMESPACE") {
|
||||
namespace_name = it.second.string_value();
|
||||
} else if (it.first == "OWNER") {
|
||||
owner = it.second.string_value();
|
||||
} else if (it.first == "WORKLOAD_NAME") {
|
||||
workload = it.second.string_value();
|
||||
} else if (it.first == "CLUSTER_ID") {
|
||||
cluster = it.second.string_value();
|
||||
} else if (it.first == "LABELS") {
|
||||
for (const auto& labels_it : it.second.struct_value().fields()) {
|
||||
if (labels_it.first == CanonicalNameLabel) {
|
||||
canonical_name = labels_it.second.string_value();
|
||||
} else if (labels_it.first == CanonicalRevisionLabel) {
|
||||
canonical_revision = labels_it.second.string_value();
|
||||
} else if (labels_it.first == AppLabel) {
|
||||
app_name = labels_it.second.string_value();
|
||||
} else if (labels_it.first == VersionLabel) {
|
||||
app_version = labels_it.second.string_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorkloadType workload_type = WorkloadType::Pod;
|
||||
// Strip "s/workload_name" and check for workload type.
|
||||
absl::string_view owner = toAbslStringView(node.owner());
|
||||
if (owner.size() > workload.size() + 2) {
|
||||
owner.remove_suffix(workload.size() + 2);
|
||||
size_t last = owner.rfind('/');
|
||||
|
|
@ -298,8 +277,9 @@ WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(const Wasm::Common::Fla
|
|||
}
|
||||
}
|
||||
|
||||
return WorkloadMetadataObject(instance, cluster, namespace_name, workload, canonical_name,
|
||||
canonical_revision, app_name, app_version, workload_type, identity);
|
||||
return std::make_shared<WorkloadMetadataObject>(instance, cluster, namespace_name, workload,
|
||||
canonical_name, canonical_revision, app_name,
|
||||
app_version, workload_type, identity);
|
||||
}
|
||||
|
||||
absl::optional<WorkloadMetadataObject>
|
||||
|
|
@ -313,10 +293,5 @@ convertEndpointMetadata(const std::string& endpoint_encoding) {
|
|||
parts[3], "", "", WorkloadType::Pod, "");
|
||||
}
|
||||
|
||||
std::string_view nodeInfoSchema() {
|
||||
return std::string_view(reinterpret_cast<const char*>(Wasm::Common::FlatNodeBinarySchema::data()),
|
||||
Wasm::Common::FlatNodeBinarySchema::size());
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
} // namespace Istio
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include "envoy/common/hashable.h"
|
||||
#include "envoy/ssl/connection.h"
|
||||
#include "envoy/stream_info/filter_state.h"
|
||||
#include "extensions/common/node_info_generated.h"
|
||||
|
||||
namespace Istio {
|
||||
namespace Common {
|
||||
|
|
@ -90,6 +89,9 @@ struct WorkloadMetadataObject : public Envoy::StreamInfo::FilterState::Object,
|
|||
|
||||
absl::optional<uint64_t> hash() const override;
|
||||
|
||||
std::string owner() const;
|
||||
void toStruct(google::protobuf::Struct* out) const;
|
||||
|
||||
absl::optional<std::string> serializeAsString() const override { return baggage(); }
|
||||
|
||||
const std::string instance_name_;
|
||||
|
|
@ -104,11 +106,9 @@ struct WorkloadMetadataObject : public Envoy::StreamInfo::FilterState::Object,
|
|||
const std::string identity_;
|
||||
};
|
||||
|
||||
// Convert metadata object to flatbuffer.
|
||||
std::string convertWorkloadMetadataToFlatNode(const WorkloadMetadataObject& obj);
|
||||
|
||||
// Convert flatbuffer to metadata object.
|
||||
WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(const Wasm::Common::FlatNode& node);
|
||||
// Convert metadata struct to metadata object.
|
||||
std::shared_ptr<WorkloadMetadataObject>
|
||||
convertStructToWorkloadMetadata(const google::protobuf::Struct& metadata);
|
||||
|
||||
// Convert endpoint metadata string to a metadata object.
|
||||
// Telemetry metadata is compressed into a semicolon separated string:
|
||||
|
|
@ -118,8 +118,5 @@ WorkloadMetadataObject convertFlatNodeToWorkloadMetadata(const Wasm::Common::Fla
|
|||
absl::optional<WorkloadMetadataObject>
|
||||
convertEndpointMetadata(const std::string& endpoint_encoding);
|
||||
|
||||
// Returns flatbuffer schema for node info.
|
||||
std::string_view nodeInfoSchema();
|
||||
|
||||
} // namespace Common
|
||||
} // namespace Istio
|
||||
|
|
|
|||
|
|
@ -17,114 +17,9 @@
|
|||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
|
||||
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "extensions/common/util.h"
|
||||
#include "extensions/common/metadata_object.h"
|
||||
|
||||
// WASM_PROLOG
|
||||
#ifndef NULL_PLUGIN
|
||||
#include "proxy_wasm_intrinsics.h"
|
||||
|
||||
#else // NULL_PLUGIN
|
||||
|
||||
#include "include/proxy-wasm/null_plugin.h"
|
||||
|
||||
#endif // NULL_PLUGIN
|
||||
|
||||
// END WASM_PROLOG
|
||||
|
||||
namespace Wasm {
|
||||
namespace Common {
|
||||
|
||||
flatbuffers::DetachedBuffer
|
||||
extractNodeFlatBufferFromStruct(const google::protobuf::Struct& metadata) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
flatbuffers::Offset<flatbuffers::String> name, namespace_, owner, workload_name, cluster_id;
|
||||
std::vector<flatbuffers::Offset<KeyVal>> labels, platform_metadata;
|
||||
for (const auto& it : metadata.fields()) {
|
||||
if (it.first == "NAME") {
|
||||
name = fbb.CreateString(it.second.string_value());
|
||||
} else if (it.first == "NAMESPACE") {
|
||||
namespace_ = fbb.CreateString(it.second.string_value());
|
||||
} else if (it.first == "OWNER") {
|
||||
owner = fbb.CreateString(it.second.string_value());
|
||||
} else if (it.first == "WORKLOAD_NAME") {
|
||||
workload_name = fbb.CreateString(it.second.string_value());
|
||||
} else if (it.first == "CLUSTER_ID") {
|
||||
cluster_id = fbb.CreateString(it.second.string_value());
|
||||
} else if (it.first == "LABELS") {
|
||||
for (const auto& labels_it : it.second.struct_value().fields()) {
|
||||
if (labels_it.first == Istio::Common::CanonicalNameLabel ||
|
||||
labels_it.first == Istio::Common::CanonicalRevisionLabel ||
|
||||
labels_it.first == Istio::Common::AppLabel ||
|
||||
labels_it.first == Istio::Common::VersionLabel) {
|
||||
labels.push_back(CreateKeyVal(fbb, fbb.CreateString(labels_it.first),
|
||||
fbb.CreateString(labels_it.second.string_value())));
|
||||
}
|
||||
}
|
||||
} else if (it.first == "PLATFORM_METADATA") {
|
||||
for (const auto& platform_it : it.second.struct_value().fields()) {
|
||||
platform_metadata.push_back(
|
||||
CreateKeyVal(fbb, fbb.CreateString(platform_it.first),
|
||||
fbb.CreateString(platform_it.second.string_value())));
|
||||
}
|
||||
}
|
||||
}
|
||||
// finish pre-order construction
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyVal>>> labels_offset,
|
||||
platform_metadata_offset;
|
||||
if (labels.size() > 0) {
|
||||
labels_offset = fbb.CreateVectorOfSortedTables(&labels);
|
||||
}
|
||||
if (platform_metadata.size() > 0) {
|
||||
platform_metadata_offset = fbb.CreateVectorOfSortedTables(&platform_metadata);
|
||||
}
|
||||
FlatNodeBuilder node(fbb);
|
||||
node.add_name(name);
|
||||
node.add_namespace_(namespace_);
|
||||
node.add_owner(owner);
|
||||
node.add_workload_name(workload_name);
|
||||
node.add_cluster_id(cluster_id);
|
||||
node.add_labels(labels_offset);
|
||||
node.add_platform_metadata(platform_metadata_offset);
|
||||
auto data = node.Finish();
|
||||
fbb.Finish(data);
|
||||
return fbb.Release();
|
||||
}
|
||||
|
||||
void extractStructFromNodeFlatBuffer(const FlatNode& node, google::protobuf::Struct* metadata) {
|
||||
if (node.name()) {
|
||||
(*metadata->mutable_fields())["NAME"].set_string_value(node.name()->str());
|
||||
}
|
||||
if (node.namespace_()) {
|
||||
(*metadata->mutable_fields())["NAMESPACE"].set_string_value(node.namespace_()->str());
|
||||
}
|
||||
if (node.owner()) {
|
||||
(*metadata->mutable_fields())["OWNER"].set_string_value(node.owner()->str());
|
||||
}
|
||||
if (node.workload_name()) {
|
||||
(*metadata->mutable_fields())["WORKLOAD_NAME"].set_string_value(node.workload_name()->str());
|
||||
}
|
||||
if (node.cluster_id()) {
|
||||
(*metadata->mutable_fields())["CLUSTER_ID"].set_string_value(node.cluster_id()->str());
|
||||
}
|
||||
if (node.labels()) {
|
||||
auto* map = (*metadata->mutable_fields())["LABELS"].mutable_struct_value();
|
||||
for (const auto keyval : *node.labels()) {
|
||||
(*map->mutable_fields())[flatbuffers::GetString(keyval->key())].set_string_value(
|
||||
flatbuffers::GetString(keyval->value()));
|
||||
}
|
||||
}
|
||||
if (node.platform_metadata()) {
|
||||
auto* map = (*metadata->mutable_fields())["PLATFORM_METADATA"].mutable_struct_value();
|
||||
for (const auto keyval : *node.platform_metadata()) {
|
||||
(*map->mutable_fields())[flatbuffers::GetString(keyval->key())].set_string_value(
|
||||
flatbuffers::GetString(keyval->value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool serializeToStringDeterministic(const google::protobuf::Message& metadata,
|
||||
std::string* metadata_bytes) {
|
||||
google::protobuf::io::StringOutputStream md(metadata_bytes);
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "extensions/common/node_info_generated.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "google/protobuf/struct.pb.h"
|
||||
|
||||
/**
|
||||
|
|
@ -25,13 +23,6 @@
|
|||
namespace Wasm {
|
||||
namespace Common {
|
||||
|
||||
// Extract node info into a flatbuffer from a struct.
|
||||
flatbuffers::DetachedBuffer
|
||||
extractNodeFlatBufferFromStruct(const google::protobuf::Struct& metadata);
|
||||
|
||||
// Extract struct from a flatbuffer. This is an inverse of the above function.
|
||||
void extractStructFromNodeFlatBuffer(const FlatNode& node, google::protobuf::Struct* metadata);
|
||||
|
||||
// Serialize deterministically a protobuf to a string.
|
||||
bool serializeToStringDeterministic(const google::protobuf::Message& metadata,
|
||||
std::string* metadata_bytes);
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
/* Copyright 2019 Istio Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "extensions/common/metadata_object.h"
|
||||
#include "extensions/common/node_info_generated.h"
|
||||
#include "extensions/common/proto_util.h"
|
||||
#include "extensions/common/util.h"
|
||||
#include "google/protobuf/util/json_util.h"
|
||||
#include "source/common/common/base64.h"
|
||||
#include "source/common/stream_info/filter_state_impl.h"
|
||||
#include "source/extensions/filters/common/expr/cel_state.h"
|
||||
#include "test/test_common/status_utility.h"
|
||||
|
||||
// WASM_PROLOG
|
||||
#ifdef NULL_PLUGIN
|
||||
namespace Wasm {
|
||||
#endif // NULL_PLUGIN
|
||||
|
||||
// END WASM_PROLOG
|
||||
|
||||
namespace Common {
|
||||
|
||||
using namespace google::protobuf::util;
|
||||
|
||||
constexpr std::string_view node_metadata_json = R"###(
|
||||
{
|
||||
"NAME":"test_pod",
|
||||
"NAMESPACE":"test_namespace",
|
||||
"LABELS": {
|
||||
"app": "productpage",
|
||||
"version": "v1",
|
||||
"pod-template-hash": "84975bc778"
|
||||
},
|
||||
"OWNER":"test_owner",
|
||||
"WORKLOAD_NAME":"test_workload",
|
||||
"PLATFORM_METADATA":{
|
||||
"gcp_project":"test_project",
|
||||
"gcp_cluster_location":"test_location",
|
||||
"gcp_cluster_name":"test_cluster"
|
||||
},
|
||||
"ISTIO_VERSION":"istio-1.4",
|
||||
"MESH_ID":"test-mesh"
|
||||
}
|
||||
)###";
|
||||
|
||||
constexpr std::string_view metadata_id_key = "envoy.wasm.metadata_exchange.downstream_id";
|
||||
constexpr std::string_view metadata_key = "envoy.wasm.metadata_exchange.downstream";
|
||||
constexpr std::string_view node_id = "test_pod.test_namespace";
|
||||
|
||||
static void setData(Envoy::StreamInfo::FilterStateImpl& filter_state, std::string_view key,
|
||||
std::string_view value) {
|
||||
Envoy::Extensions::Filters::Common::Expr::CelStatePrototype prototype;
|
||||
auto state_ptr = std::make_unique<Envoy::Extensions::Filters::Common::Expr::CelState>(prototype);
|
||||
state_ptr->setValue(toAbslStringView(value));
|
||||
filter_state.setData(toAbslStringView(key), std::move(state_ptr),
|
||||
Envoy::StreamInfo::FilterState::StateType::Mutable);
|
||||
}
|
||||
|
||||
static const std::string& getData(Envoy::StreamInfo::FilterStateImpl& filter_state,
|
||||
std::string_view key) {
|
||||
return filter_state
|
||||
.getDataReadOnly<Envoy::Extensions::Filters::Common::Expr::CelState>(toAbslStringView(key))
|
||||
->value();
|
||||
}
|
||||
|
||||
static void BM_ReadFlatBuffer(benchmark::State& state) {
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
ASSERT_OK(
|
||||
JsonStringToMessage(std::string(node_metadata_json), &metadata_struct, json_parse_options));
|
||||
auto out = extractNodeFlatBufferFromStruct(metadata_struct);
|
||||
|
||||
Envoy::StreamInfo::FilterStateImpl filter_state{
|
||||
Envoy::StreamInfo::FilterState::LifeSpan::TopSpan};
|
||||
setData(filter_state, metadata_key,
|
||||
std::string_view(reinterpret_cast<const char*>(out.data()), out.size()));
|
||||
|
||||
size_t size = 0;
|
||||
for (auto _ : state) {
|
||||
auto buf = getData(filter_state, metadata_key);
|
||||
auto peer = flatbuffers::GetRoot<FlatNode>(buf.data());
|
||||
size += peer->workload_name()->size() + peer->namespace_()->size() +
|
||||
peer->labels()->LookupByKey("app")->value()->size() +
|
||||
peer->labels()->LookupByKey("version")->value()->size();
|
||||
benchmark::DoNotOptimize(size);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_ReadFlatBuffer);
|
||||
|
||||
static void BM_WriteRawBytes(benchmark::State& state) {
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
ASSERT_OK(
|
||||
JsonStringToMessage(std::string(node_metadata_json), &metadata_struct, json_parse_options));
|
||||
auto bytes = metadata_struct.SerializeAsString();
|
||||
Envoy::StreamInfo::FilterStateImpl filter_state{
|
||||
Envoy::StreamInfo::FilterState::LifeSpan::TopSpan};
|
||||
|
||||
for (auto _ : state) {
|
||||
setData(filter_state, metadata_id_key, node_id);
|
||||
setData(filter_state, metadata_key, bytes);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_WriteRawBytes);
|
||||
|
||||
static void BM_WriteFlatBufferWithCache(benchmark::State& state) {
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
ASSERT_OK(
|
||||
JsonStringToMessage(std::string(node_metadata_json), &metadata_struct, json_parse_options));
|
||||
auto bytes = metadata_struct.SerializeAsString();
|
||||
Envoy::StreamInfo::FilterStateImpl filter_state{
|
||||
Envoy::StreamInfo::FilterState::LifeSpan::TopSpan};
|
||||
|
||||
std::unordered_map<std::string, std::string> cache;
|
||||
|
||||
for (auto _ : state) {
|
||||
// lookup cache by key
|
||||
auto nodeinfo_it = cache.find(std::string(node_id));
|
||||
std::string node_info;
|
||||
if (nodeinfo_it == cache.end()) {
|
||||
google::protobuf::Struct test_struct;
|
||||
test_struct.ParseFromArray(bytes.data(), bytes.size());
|
||||
benchmark::DoNotOptimize(test_struct);
|
||||
|
||||
auto out = extractNodeFlatBufferFromStruct(test_struct);
|
||||
|
||||
node_info =
|
||||
cache.emplace(node_id, std::string(reinterpret_cast<const char*>(out.data()), out.size()))
|
||||
.first->second;
|
||||
} else {
|
||||
node_info = nodeinfo_it->second;
|
||||
}
|
||||
|
||||
setData(filter_state, metadata_id_key, node_id);
|
||||
setData(filter_state, metadata_key, node_info);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_WriteFlatBufferWithCache);
|
||||
|
||||
constexpr std::string_view node_flatbuffer_json = R"###(
|
||||
{
|
||||
"NAME":"test_pod",
|
||||
"NAMESPACE":"default",
|
||||
"CLUSTER_ID": "client-cluster",
|
||||
"LABELS": {
|
||||
"app": "productpage",
|
||||
"version": "v1",
|
||||
"service.istio.io/canonical-name": "productpage-v1",
|
||||
"service.istio.io/canonical-revision": "version-1"
|
||||
},
|
||||
"OWNER": "kubernetes://apis/apps/v1/namespaces/default/deployments/productpage-v1",
|
||||
"WORKLOAD_NAME":"productpage-v1"
|
||||
}
|
||||
)###";
|
||||
|
||||
// Measure decoding performance of x-envoy-peer-metadata.
|
||||
static void BM_DecodeFlatBuffer(benchmark::State& state) {
|
||||
// Construct a header from sample value.
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
ASSERT_OK(
|
||||
JsonStringToMessage(std::string(node_flatbuffer_json), &metadata_struct, json_parse_options));
|
||||
std::string metadata_bytes;
|
||||
::Wasm::Common::serializeToStringDeterministic(metadata_struct, &metadata_bytes);
|
||||
const std::string header_value =
|
||||
Envoy::Base64::encode(metadata_bytes.data(), metadata_bytes.size());
|
||||
|
||||
size_t size = 0;
|
||||
for (auto _ : state) {
|
||||
auto bytes = Envoy::Base64::decodeWithoutPadding(header_value);
|
||||
google::protobuf::Struct metadata;
|
||||
metadata.ParseFromString(bytes);
|
||||
auto fb = ::Wasm::Common::extractNodeFlatBufferFromStruct(metadata);
|
||||
size += fb.size();
|
||||
benchmark::DoNotOptimize(size);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_DecodeFlatBuffer);
|
||||
|
||||
// Measure decoding performance of baggage.
|
||||
static void BM_DecodeBaggage(benchmark::State& state) {
|
||||
// Construct a header from sample value.
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
ASSERT_OK(
|
||||
JsonStringToMessage(std::string(node_flatbuffer_json), &metadata_struct, json_parse_options));
|
||||
auto fb = ::Wasm::Common::extractNodeFlatBufferFromStruct(metadata_struct);
|
||||
const auto& node = *flatbuffers::GetRoot<Wasm::Common::FlatNode>(fb.data());
|
||||
const std::string baggage = Istio::Common::convertFlatNodeToWorkloadMetadata(node).baggage();
|
||||
|
||||
size_t size = 0;
|
||||
for (auto _ : state) {
|
||||
auto obj = Istio::Common::WorkloadMetadataObject::fromBaggage(baggage);
|
||||
size += obj.namespace_name_.size();
|
||||
benchmark::DoNotOptimize(size);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_DecodeBaggage);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
// WASM_EPILOG
|
||||
#ifdef NULL_PLUGIN
|
||||
} // namespace Wasm
|
||||
#endif
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
/* Copyright 2019 Istio Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "extensions/common/proto_util.h"
|
||||
|
||||
#include "extensions/common/node_info_generated.h"
|
||||
#include "google/protobuf/struct.pb.h"
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "google/protobuf/util/json_util.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// WASM_PROLOG
|
||||
#ifdef NULL_PLUGIN
|
||||
namespace Wasm {
|
||||
#endif // NULL_PLUGIN
|
||||
|
||||
// END WASM_PROLOG
|
||||
|
||||
namespace Common {
|
||||
|
||||
using namespace google::protobuf;
|
||||
using namespace google::protobuf::util;
|
||||
|
||||
constexpr std::string_view node_metadata_json = R"###(
|
||||
{
|
||||
"NAME":"test_pod",
|
||||
"NAMESPACE":"test_namespace",
|
||||
"OWNER":"test_owner",
|
||||
"WORKLOAD_NAME":"test_workload",
|
||||
"CLUSTER_ID":"test-cluster",
|
||||
"LABELS":{
|
||||
"app":"test",
|
||||
"version":"v1"
|
||||
},
|
||||
"PLATFORM_METADATA":{
|
||||
"gcp_cluster_location":"test_location",
|
||||
"gcp_cluster_name":"test_cluster",
|
||||
"gcp_project":"test_project"
|
||||
},
|
||||
}
|
||||
)###";
|
||||
|
||||
// Test all possible metadata field.
|
||||
TEST(ProtoUtilTest, extractNodeMetadata) {
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
EXPECT_TRUE(
|
||||
JsonStringToMessage(std::string(node_metadata_json), &metadata_struct, json_parse_options)
|
||||
.ok());
|
||||
auto out = extractNodeFlatBufferFromStruct(metadata_struct);
|
||||
auto peer = flatbuffers::GetRoot<FlatNode>(out.data());
|
||||
EXPECT_EQ(peer->name()->string_view(), "test_pod");
|
||||
EXPECT_EQ(peer->namespace_()->string_view(), "test_namespace");
|
||||
EXPECT_EQ(peer->owner()->string_view(), "test_owner");
|
||||
EXPECT_EQ(peer->workload_name()->string_view(), "test_workload");
|
||||
EXPECT_EQ(peer->cluster_id()->string_view(), "test-cluster");
|
||||
EXPECT_EQ(peer->platform_metadata()->Get(2)->key()->string_view(), "gcp_project");
|
||||
EXPECT_EQ(peer->platform_metadata()->Get(2)->value()->string_view(), "test_project");
|
||||
}
|
||||
|
||||
// Test roundtripping
|
||||
TEST(ProtoUtilTest, Rountrip) {
|
||||
google::protobuf::Struct metadata_struct;
|
||||
JsonParseOptions json_parse_options;
|
||||
EXPECT_TRUE(
|
||||
JsonStringToMessage(std::string(node_metadata_json), &metadata_struct, json_parse_options)
|
||||
.ok());
|
||||
auto out = extractNodeFlatBufferFromStruct(metadata_struct);
|
||||
auto peer = flatbuffers::GetRoot<FlatNode>(out.data());
|
||||
|
||||
google::protobuf::Struct output_struct;
|
||||
extractStructFromNodeFlatBuffer(*peer, &output_struct);
|
||||
|
||||
// Validate serialized bytes
|
||||
std::string input_bytes;
|
||||
EXPECT_TRUE(serializeToStringDeterministic(metadata_struct, &input_bytes));
|
||||
std::string output_bytes;
|
||||
EXPECT_TRUE(serializeToStringDeterministic(output_struct, &output_bytes));
|
||||
EXPECT_EQ(input_bytes, output_bytes)
|
||||
<< metadata_struct.DebugString() << output_struct.DebugString();
|
||||
}
|
||||
|
||||
// Test roundtrip for an empty struct (for corner cases)
|
||||
TEST(ProtoUtilTest, RountripEmpty) {
|
||||
google::protobuf::Struct metadata_struct;
|
||||
auto out = extractNodeFlatBufferFromStruct(metadata_struct);
|
||||
auto peer = flatbuffers::GetRoot<FlatNode>(out.data());
|
||||
google::protobuf::Struct output_struct;
|
||||
extractStructFromNodeFlatBuffer(*peer, &output_struct);
|
||||
EXPECT_EQ(0, output_struct.fields().size());
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
// WASM_EPILOG
|
||||
#ifdef NULL_PLUGIN
|
||||
} // namespace Wasm
|
||||
#endif
|
||||
|
|
@ -19,6 +19,11 @@ load(
|
|||
"@envoy//bazel:envoy_build_system.bzl",
|
||||
"envoy_cc_library",
|
||||
)
|
||||
load(
|
||||
"@com_github_google_flatbuffers//:build_defs.bzl",
|
||||
"DEFAULT_FLATC_ARGS",
|
||||
"flatbuffer_library_public",
|
||||
)
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
|
@ -34,7 +39,7 @@ envoy_cc_library(
|
|||
],
|
||||
repository = "@envoy",
|
||||
deps = [
|
||||
"//extensions/common:node_info_fb_cc",
|
||||
":node_info_fb_cc",
|
||||
"//extensions/common:util",
|
||||
"@proxy_wasm_cpp_host//:null_lib",
|
||||
],
|
||||
|
|
@ -63,3 +68,26 @@ envoy_cc_library(
|
|||
"@proxy_wasm_cpp_sdk//contrib:contrib_lib",
|
||||
],
|
||||
)
|
||||
|
||||
flatbuffer_library_public(
|
||||
name = "node_info_fbs",
|
||||
srcs = ["node_info.fbs"],
|
||||
outs = [
|
||||
"node_info_bfbs_generated.h",
|
||||
"node_info_generated.h",
|
||||
],
|
||||
flatc_args = DEFAULT_FLATC_ARGS + ["--bfbs-gen-embed"],
|
||||
language_flag = "-c",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "node_info_fb_cc",
|
||||
srcs = [":node_info_fbs"],
|
||||
hdrs = [":node_info_fbs"],
|
||||
features = ["-parse_headers"],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
"@com_github_google_flatbuffers//:flatbuffers",
|
||||
"@com_github_google_flatbuffers//:runtime_cc",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -344,6 +344,53 @@ bool extractPeerMetadataFromUpstreamHostMetadata(flatbuffers::FlatBufferBuilder&
|
|||
return extractPeerMetadataFromUpstreamMetadata("upstream_host_metadata", fbb);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Returns a string view stored in a flatbuffers string.
|
||||
std::string_view toStdStringView(absl::string_view view) {
|
||||
return std::string_view(view.data(), view.size());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string convertWorkloadMetadataToFlatNode(const Istio::Common::WorkloadMetadataObject& obj) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
|
||||
flatbuffers::Offset<flatbuffers::String> name, cluster, namespace_, workload_name, owner,
|
||||
identity;
|
||||
std::vector<flatbuffers::Offset<Wasm::Common::KeyVal>> labels;
|
||||
|
||||
name = fbb.CreateString(toStdStringView(obj.instance_name_));
|
||||
namespace_ = fbb.CreateString(toStdStringView(obj.namespace_name_));
|
||||
cluster = fbb.CreateString(toStdStringView(obj.cluster_name_));
|
||||
workload_name = fbb.CreateString(toStdStringView(obj.workload_name_));
|
||||
identity = fbb.CreateString(toStdStringView(obj.identity_));
|
||||
owner = fbb.CreateString(obj.owner());
|
||||
|
||||
labels.push_back(
|
||||
Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(CanonicalNameLabel),
|
||||
fbb.CreateString(toStdStringView(obj.canonical_name_))));
|
||||
labels.push_back(
|
||||
Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(CanonicalRevisionLabel),
|
||||
fbb.CreateString(toStdStringView(obj.canonical_revision_))));
|
||||
labels.push_back(Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(AppLabel),
|
||||
fbb.CreateString(toStdStringView(obj.app_name_))));
|
||||
labels.push_back(Wasm::Common::CreateKeyVal(fbb, fbb.CreateString(VersionLabel),
|
||||
fbb.CreateString(toStdStringView(obj.app_version_))));
|
||||
|
||||
auto labels_offset = fbb.CreateVectorOfSortedTables(&labels);
|
||||
Wasm::Common::FlatNodeBuilder node(fbb);
|
||||
node.add_name(name);
|
||||
node.add_cluster_id(cluster);
|
||||
node.add_namespace_(namespace_);
|
||||
node.add_workload_name(workload_name);
|
||||
node.add_owner(owner);
|
||||
node.add_labels(labels_offset);
|
||||
node.add_identity(identity);
|
||||
auto data = node.Finish();
|
||||
fbb.Finish(data);
|
||||
auto fb = fbb.Release();
|
||||
return std::string(reinterpret_cast<const char*>(fb.data()), fb.size());
|
||||
}
|
||||
|
||||
PeerNodeInfo::PeerNodeInfo(const std::string_view peer_metadata_id_key,
|
||||
const std::string_view peer_metadata_key) {
|
||||
// Attempt to read from filter_state first.
|
||||
|
|
|
|||
|
|
@ -228,6 +228,9 @@ bool extractPeerMetadataFromUpstreamHostMetadata(flatbuffers::FlatBufferBuilder&
|
|||
// Returns true if the metadata is found in the upstream cluster metadata.
|
||||
bool extractPeerMetadataFromUpstreamClusterMetadata(flatbuffers::FlatBufferBuilder& fbb);
|
||||
|
||||
// Convert metadata object to flatbuffer.
|
||||
std::string convertWorkloadMetadataToFlatNode(const Istio::Common::WorkloadMetadataObject& obj);
|
||||
|
||||
class PeerNodeInfo {
|
||||
public:
|
||||
explicit PeerNodeInfo(const std::string_view peer_metadata_id_key,
|
||||
|
|
|
|||
|
|
@ -123,16 +123,13 @@ bool peerInfoRead(Reporter reporter, const StreamInfo::FilterState& filter_state
|
|||
filter_state.hasDataWithName("envoy.wasm.metadata_exchange.peer_unknown");
|
||||
}
|
||||
|
||||
const Wasm::Common::FlatNode* peerInfo(Reporter reporter,
|
||||
const StreamInfo::FilterState& filter_state) {
|
||||
const Istio::Common::WorkloadMetadataObject* peerInfo(Reporter reporter,
|
||||
const StreamInfo::FilterState& filter_state) {
|
||||
const auto& filter_state_key =
|
||||
reporter == Reporter::ServerSidecar || reporter == Reporter::ServerGateway
|
||||
? "wasm.downstream_peer"
|
||||
: "wasm.upstream_peer";
|
||||
const auto* object =
|
||||
filter_state.getDataReadOnly<Envoy::Extensions::Filters::Common::Expr::CelState>(
|
||||
filter_state_key);
|
||||
return object ? flatbuffers::GetRoot<Wasm::Common::FlatNode>(object->value().data()) : nullptr;
|
||||
return filter_state.getDataReadOnly<Istio::Common::WorkloadMetadataObject>(filter_state_key);
|
||||
}
|
||||
|
||||
// Process-wide context shared with all filter instances.
|
||||
|
|
@ -1000,7 +997,7 @@ private:
|
|||
absl::optional<Istio::Common::WorkloadMetadataObject> peer;
|
||||
const auto* object = peerInfo(config_->reporter(), filter_state);
|
||||
if (object) {
|
||||
peer.emplace(Istio::Common::convertFlatNodeToWorkloadMetadata(*object));
|
||||
peer.emplace(*object);
|
||||
} else if (config_->reporter() == Reporter::ClientSidecar) {
|
||||
if (auto label_obj = extractEndpointMetadata(info); label_obj) {
|
||||
peer.emplace(label_obj.value());
|
||||
|
|
@ -1138,7 +1135,7 @@ private:
|
|||
std::optional<Istio::Common::WorkloadMetadataObject> endpoint_peer;
|
||||
const auto* endpoint_object = peerInfo(Reporter::ClientSidecar, filter_state);
|
||||
if (endpoint_object) {
|
||||
endpoint_peer.emplace(Istio::Common::convertFlatNodeToWorkloadMetadata(*endpoint_object));
|
||||
endpoint_peer.emplace(*endpoint_object);
|
||||
}
|
||||
tags_.push_back(
|
||||
{context_.destination_workload_,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ envoy_cc_extension(
|
|||
"@envoy//source/common/http:header_utility_lib",
|
||||
"@envoy//source/common/http:utility_lib",
|
||||
"@envoy//source/common/network:utility_lib",
|
||||
"@envoy//source/common/router:string_accessor_lib",
|
||||
"@envoy//source/extensions/filters/common/expr:cel_state_lib",
|
||||
"@envoy//source/extensions/filters/http/common:factory_base_lib",
|
||||
"@envoy//source/extensions/filters/http/common:pass_through_filter_lib",
|
||||
|
|
|
|||
|
|
@ -23,36 +23,13 @@
|
|||
#include "source/common/http/header_utility.h"
|
||||
#include "source/common/http/utility.h"
|
||||
#include "source/common/network/utility.h"
|
||||
#include "source/extensions/filters/common/expr/cel_state.h"
|
||||
#include "source/common/router/string_accessor_impl.h"
|
||||
|
||||
namespace Envoy {
|
||||
namespace Extensions {
|
||||
namespace HttpFilters {
|
||||
namespace PeerMetadata {
|
||||
|
||||
// Extended peer info that supports "hashing" to enable sharing with the
|
||||
// upstream connection via an internal listener.
|
||||
class CelStateHashable : public Filters::Common::Expr::CelState, public Hashable {
|
||||
public:
|
||||
explicit CelStateHashable(const Filters::Common::Expr::CelStatePrototype& proto)
|
||||
: CelState(proto) {}
|
||||
absl::optional<uint64_t> hash() const override { return HashUtil::xxHash64(value()); }
|
||||
};
|
||||
|
||||
struct CelPrototypeValues {
|
||||
const Filters::Common::Expr::CelStatePrototype NodeInfo{
|
||||
true, Filters::Common::Expr::CelStateType::FlatBuffers,
|
||||
toAbslStringView(Istio::Common::nodeInfoSchema()),
|
||||
// Life span is only needed for Wasm set_property, not in the native filters.
|
||||
StreamInfo::FilterState::LifeSpan::FilterChain};
|
||||
const Filters::Common::Expr::CelStatePrototype NodeId{
|
||||
true, Filters::Common::Expr::CelStateType::String, absl::string_view(),
|
||||
// Life span is only needed for Wasm set_property, not in the native filters.
|
||||
StreamInfo::FilterState::LifeSpan::FilterChain};
|
||||
};
|
||||
|
||||
using CelPrototypes = ConstSingleton<CelPrototypeValues>;
|
||||
|
||||
class XDSMethod : public DiscoveryMethod {
|
||||
public:
|
||||
XDSMethod(bool downstream, Server::Configuration::ServerFactoryContext& factory_context)
|
||||
|
|
@ -104,7 +81,7 @@ absl::optional<PeerInfo> XDSMethod::derivePeerInfo(const StreamInfo::StreamInfo&
|
|||
}
|
||||
const auto metadata_object = metadata_provider_->GetMetadata(peer_address);
|
||||
if (metadata_object) {
|
||||
return Istio::Common::convertWorkloadMetadataToFlatNode(metadata_object.value());
|
||||
return std::make_shared<Istio::Common::WorkloadMetadataObject>(metadata_object.value());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
@ -154,8 +131,7 @@ absl::optional<PeerInfo> MXMethod::lookup(absl::string_view id, absl::string_vie
|
|||
if (!metadata.ParseFromString(bytes)) {
|
||||
return {};
|
||||
}
|
||||
const auto fb = ::Wasm::Common::extractNodeFlatBufferFromStruct(metadata);
|
||||
std::string out(reinterpret_cast<const char*>(fb.data()), fb.size());
|
||||
const auto out = Istio::Common::convertStructToWorkloadMetadata(metadata);
|
||||
if (max_peer_cache_size_ > 0 && !id.empty()) {
|
||||
// do not let the cache grow beyond max cache size.
|
||||
if (static_cast<uint32_t>(cache.size()) > max_peer_cache_size_) {
|
||||
|
|
@ -175,11 +151,10 @@ MXPropagationMethod::MXPropagationMethod(
|
|||
|
||||
std::string MXPropagationMethod::computeValue(
|
||||
Server::Configuration::ServerFactoryContext& factory_context) const {
|
||||
const auto fb = ::Wasm::Common::extractNodeFlatBufferFromStruct(
|
||||
factory_context.localInfo().node().metadata());
|
||||
const auto out =
|
||||
Istio::Common::convertStructToWorkloadMetadata(factory_context.localInfo().node().metadata());
|
||||
google::protobuf::Struct metadata;
|
||||
::Wasm::Common::extractStructFromNodeFlatBuffer(
|
||||
*flatbuffers::GetRoot<::Wasm::Common::FlatNode>(fb.data()), &metadata);
|
||||
out->toStruct(&metadata);
|
||||
std::string metadata_bytes;
|
||||
::Wasm::Common::serializeToStringDeterministic(metadata, &metadata_bytes);
|
||||
return Base64::encode(metadata_bytes.data(), metadata_bytes.size());
|
||||
|
|
@ -296,15 +271,13 @@ void FilterConfig::injectUpstream(const StreamInfo::StreamInfo& info,
|
|||
}
|
||||
|
||||
void FilterConfig::setFilterState(StreamInfo::StreamInfo& info, bool downstream,
|
||||
const std::string& value) const {
|
||||
const PeerInfo& value) const {
|
||||
const absl::string_view key =
|
||||
downstream ? Istio::Common::WasmDownstreamPeer : Istio::Common::WasmUpstreamPeer;
|
||||
if (!info.filterState()->hasDataWithName(key)) {
|
||||
auto node_info = std::make_unique<CelStateHashable>(CelPrototypes::get().NodeInfo);
|
||||
node_info->setValue(value);
|
||||
info.filterState()->setData(
|
||||
key, std::move(node_info), StreamInfo::FilterState::StateType::Mutable,
|
||||
StreamInfo::FilterState::LifeSpan::FilterChain, sharedWithUpstream());
|
||||
info.filterState()->setData(key, value, StreamInfo::FilterState::StateType::Mutable,
|
||||
StreamInfo::FilterState::LifeSpan::FilterChain,
|
||||
sharedWithUpstream());
|
||||
} else {
|
||||
ENVOY_LOG(debug, "Duplicate peer metadata, skipping");
|
||||
}
|
||||
|
|
@ -313,11 +286,10 @@ void FilterConfig::setFilterState(StreamInfo::StreamInfo& info, bool downstream,
|
|||
const absl::string_view id_key =
|
||||
downstream ? Istio::Common::WasmDownstreamPeerID : Istio::Common::WasmUpstreamPeerID;
|
||||
if (!info.filterState()->hasDataWithName(id_key)) {
|
||||
auto node_id = std::make_unique<Filters::Common::Expr::CelState>(CelPrototypes::get().NodeId);
|
||||
node_id->setValue("unknown");
|
||||
info.filterState()->setData(
|
||||
id_key, std::move(node_id), StreamInfo::FilterState::StateType::Mutable,
|
||||
StreamInfo::FilterState::LifeSpan::FilterChain, sharedWithUpstream());
|
||||
info.filterState()->setData(id_key, std::make_shared<Router::StringAccessorImpl>("unknown"),
|
||||
StreamInfo::FilterState::StateType::Mutable,
|
||||
StreamInfo::FilterState::LifeSpan::FilterChain,
|
||||
sharedWithUpstream());
|
||||
} else {
|
||||
ENVOY_LOG(debug, "Duplicate peer id, skipping");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct HeaderValues {
|
|||
using Headers = ConstSingleton<HeaderValues>;
|
||||
|
||||
// Peer info in the flatbuffers format.
|
||||
using PeerInfo = std::string;
|
||||
using PeerInfo = std::shared_ptr<Istio::Common::WorkloadMetadataObject>;
|
||||
|
||||
struct Context {
|
||||
bool request_peer_id_received_{false};
|
||||
|
|
@ -62,7 +62,7 @@ private:
|
|||
absl::optional<PeerInfo> lookup(absl::string_view id, absl::string_view value) const;
|
||||
const bool downstream_;
|
||||
struct MXCache : public ThreadLocal::ThreadLocalObject {
|
||||
absl::flat_hash_map<std::string, std::string> cache_;
|
||||
absl::flat_hash_map<std::string, PeerInfo> cache_;
|
||||
};
|
||||
mutable ThreadLocal::TypedSlot<MXCache> tls_;
|
||||
const int64_t max_peer_cache_size_{500};
|
||||
|
|
@ -114,7 +114,7 @@ private:
|
|||
: StreamInfo::StreamSharingMayImpactPooling::None;
|
||||
}
|
||||
void discover(StreamInfo::StreamInfo&, bool downstream, Http::HeaderMap&, Context&) const;
|
||||
void setFilterState(StreamInfo::StreamInfo&, bool downstream, const std::string& value) const;
|
||||
void setFilterState(StreamInfo::StreamInfo&, bool downstream, const PeerInfo& value) const;
|
||||
const bool shared_with_upstream_;
|
||||
const std::vector<DiscoveryMethodPtr> downstream_discovery_;
|
||||
const std::vector<DiscoveryMethodPtr> upstream_discovery_;
|
||||
|
|
|
|||
|
|
@ -84,16 +84,11 @@ protected:
|
|||
void checkPeerNamespace(bool downstream, const std::string& expected) {
|
||||
EXPECT_TRUE(stream_info_.filterState()->hasDataWithName(
|
||||
downstream ? Istio::Common::WasmDownstreamPeerID : Istio::Common::WasmUpstreamPeerID));
|
||||
const auto* obj = stream_info_.filterState()->getDataReadOnly<Filters::Common::Expr::CelState>(
|
||||
downstream ? Istio::Common::WasmDownstreamPeer : Istio::Common::WasmUpstreamPeer);
|
||||
const auto* obj =
|
||||
stream_info_.filterState()->getDataReadOnly<Istio::Common::WorkloadMetadataObject>(
|
||||
downstream ? Istio::Common::WasmDownstreamPeer : Istio::Common::WasmUpstreamPeer);
|
||||
ASSERT_NE(nullptr, obj);
|
||||
Protobuf::Arena arena;
|
||||
auto map = obj->exprValue(&arena, false);
|
||||
ASSERT_TRUE(map.IsMap());
|
||||
auto value =
|
||||
(*map.MapOrDie())[google::api::expr::runtime::CelValue::CreateStringView("namespace")];
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(expected, value.value().StringOrDie().value());
|
||||
EXPECT_EQ(expected, obj->namespace_name_);
|
||||
}
|
||||
void checkShared(bool expected) {
|
||||
EXPECT_EQ(expected,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ envoy_cc_library(
|
|||
"@envoy//source/common/network:utility_lib",
|
||||
"@envoy//source/common/protobuf",
|
||||
"@envoy//source/common/protobuf:utility_lib",
|
||||
"@envoy//source/extensions/filters/common/expr:cel_state_lib",
|
||||
"@envoy//source/common/router:string_accessor_lib",
|
||||
"@envoy//source/extensions/filters/network:well_known_names",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "envoy/stats/scope.h"
|
||||
#include "source/common/buffer/buffer_impl.h"
|
||||
#include "source/common/protobuf/utility.h"
|
||||
#include "source/common/router/string_accessor_impl.h"
|
||||
#include "source/extensions/filters/network/metadata_exchange/metadata_exchange_initial_header.h"
|
||||
|
||||
namespace Envoy {
|
||||
|
|
@ -58,18 +59,6 @@ constructProxyHeaderData(const Envoy::ProtobufWkt::Any& proxy_data) {
|
|||
return proxy_data_buffer;
|
||||
}
|
||||
|
||||
bool serializeToStringDeterministic(const google::protobuf::Struct& metadata,
|
||||
std::string* metadata_bytes) {
|
||||
google::protobuf::io::StringOutputStream md(metadata_bytes);
|
||||
google::protobuf::io::CodedOutputStream mcs(&md);
|
||||
|
||||
mcs.SetSerializationDeterministic(true);
|
||||
if (!metadata.SerializeToCodedStream(&mcs)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MetadataExchangeConfig::MetadataExchangeConfig(
|
||||
|
|
@ -209,7 +198,7 @@ void MetadataExchangeFilter::writeNodeMetadata() {
|
|||
Envoy::ProtobufWkt::Any metadata_any_value;
|
||||
metadata_any_value.set_type_url(StructTypeUrl);
|
||||
std::string serialized_data;
|
||||
serializeToStringDeterministic(data, &serialized_data);
|
||||
::Wasm::Common::serializeToStringDeterministic(data, &serialized_data);
|
||||
*metadata_any_value.mutable_value() = serialized_data;
|
||||
std::unique_ptr<::Envoy::Buffer::OwnedImpl> buf = constructProxyHeaderData(metadata_any_value);
|
||||
write_callbacks_->injectWriteDataToFilterChain(*buf, false);
|
||||
|
|
@ -274,9 +263,8 @@ void MetadataExchangeFilter::tryReadProxyData(Buffer::Instance& data) {
|
|||
Envoy::MessageUtil::anyConvert<Envoy::ProtobufWkt::Struct>(proxy_data);
|
||||
auto key_metadata_it = value_struct.fields().find(ExchangeMetadataHeader);
|
||||
if (key_metadata_it != value_struct.fields().end()) {
|
||||
const auto fb =
|
||||
::Wasm::Common::extractNodeFlatBufferFromStruct(key_metadata_it->second.struct_value());
|
||||
std::string out(reinterpret_cast<const char*>(fb.data()), fb.size());
|
||||
const auto out =
|
||||
Istio::Common::convertStructToWorkloadMetadata(key_metadata_it->second.struct_value());
|
||||
updatePeer(out);
|
||||
}
|
||||
const auto key_metadata_id_it = value_struct.fields().find(ExchangeMetadataHeaderId);
|
||||
|
|
@ -289,36 +277,25 @@ void MetadataExchangeFilter::tryReadProxyData(Buffer::Instance& data) {
|
|||
}
|
||||
}
|
||||
|
||||
void MetadataExchangeFilter::updatePeer(const std::string& fb) {
|
||||
// Filter object captures schema by view, hence the global singleton for the
|
||||
// prototype.
|
||||
auto state = std::make_unique<::Envoy::Extensions::Filters::Common::Expr::CelState>(
|
||||
MetadataExchangeConfig::nodeInfoPrototype());
|
||||
state->setValue(fb);
|
||||
|
||||
void MetadataExchangeFilter::updatePeer(
|
||||
const std::shared_ptr<Istio::Common::WorkloadMetadataObject>& obj) {
|
||||
auto key = config_->filter_direction_ == FilterDirection::Downstream ? kDownstreamMetadataKey
|
||||
: kUpstreamMetadataKey;
|
||||
read_callbacks_->connection().streamInfo().filterState()->setData(
|
||||
absl::StrCat("wasm.", key), std::move(state), StreamInfo::FilterState::StateType::Mutable,
|
||||
absl::StrCat("wasm.", key), obj, StreamInfo::FilterState::StateType::Mutable,
|
||||
StreamInfo::FilterState::LifeSpan::Connection);
|
||||
}
|
||||
|
||||
void MetadataExchangeFilter::updatePeerId(absl::string_view key, absl::string_view value) {
|
||||
CelStatePrototype prototype(
|
||||
/* read_only = */ false, ::Envoy::Extensions::Filters::Common::Expr::CelStateType::String,
|
||||
absl::string_view(), StreamInfo::FilterState::LifeSpan::Connection);
|
||||
auto state = std::make_unique<::Envoy::Extensions::Filters::Common::Expr::CelState>(prototype);
|
||||
state->setValue(value);
|
||||
read_callbacks_->connection().streamInfo().filterState()->setData(
|
||||
absl::StrCat("wasm.", key), std::move(state), StreamInfo::FilterState::StateType::Mutable,
|
||||
prototype.life_span_);
|
||||
absl::StrCat("wasm.", key), std::make_shared<Router::StringAccessorImpl>(value),
|
||||
StreamInfo::FilterState::StateType::Mutable, StreamInfo::FilterState::LifeSpan::Connection);
|
||||
}
|
||||
|
||||
void MetadataExchangeFilter::getMetadata(google::protobuf::Struct* metadata) {
|
||||
if (local_info_.node().has_metadata()) {
|
||||
const auto fb = ::Wasm::Common::extractNodeFlatBufferFromStruct(local_info_.node().metadata());
|
||||
::Wasm::Common::extractStructFromNodeFlatBuffer(
|
||||
*flatbuffers::GetRoot<::Wasm::Common::FlatNode>(fb.data()), metadata);
|
||||
const auto out = Istio::Common::convertStructToWorkloadMetadata(local_info_.node().metadata());
|
||||
out->toStruct(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +308,7 @@ void MetadataExchangeFilter::setMetadataNotFoundFilterState() {
|
|||
ENVOY_LOG(debug, "Look up metadata based on peer address {}", peer_address->asString());
|
||||
const auto metadata_object = config_->metadata_provider_->GetMetadata(peer_address);
|
||||
if (metadata_object) {
|
||||
updatePeer(Istio::Common::convertWorkloadMetadataToFlatNode(metadata_object.value()));
|
||||
updatePeer(std::make_shared<Istio::Common::WorkloadMetadataObject>(metadata_object.value()));
|
||||
updatePeerId(config_->filter_direction_ == FilterDirection::Downstream
|
||||
? kDownstreamMetadataIdKey
|
||||
: kUpstreamMetadataIdKey,
|
||||
|
|
|
|||
|
|
@ -23,12 +23,10 @@
|
|||
#include "envoy/stats/scope.h"
|
||||
#include "envoy/stats/stats_macros.h"
|
||||
#include "envoy/stream_info/filter_state.h"
|
||||
#include "extensions/common/node_info_bfbs_generated.h"
|
||||
#include "extensions/common/proto_util.h"
|
||||
#include "extensions/common/metadata_object.h"
|
||||
#include "source/common/common/stl_helpers.h"
|
||||
#include "source/common/protobuf/protobuf.h"
|
||||
#include "source/extensions/filters/common/expr/cel_state.h"
|
||||
#include "source/extensions/filters/network/metadata_exchange/config/metadata_exchange.pb.h"
|
||||
#include "source/extensions/common/workload_discovery/api.h"
|
||||
|
||||
|
|
@ -36,8 +34,6 @@ namespace Envoy {
|
|||
namespace Tcp {
|
||||
namespace MetadataExchange {
|
||||
|
||||
using ::Envoy::Extensions::Filters::Common::Expr::CelStatePrototype;
|
||||
|
||||
/**
|
||||
* All MetadataExchange filter stats. @see stats_macros.h
|
||||
*/
|
||||
|
|
@ -86,13 +82,6 @@ public:
|
|||
// Stats for MetadataExchange Filter.
|
||||
MetadataExchangeStats stats_;
|
||||
|
||||
static const CelStatePrototype& nodeInfoPrototype() {
|
||||
static const CelStatePrototype* const prototype = new CelStatePrototype(
|
||||
true, ::Envoy::Extensions::Filters::Common::Expr::CelStateType::FlatBuffers,
|
||||
::Istio::Common::nodeInfoSchema(), StreamInfo::FilterState::LifeSpan::Connection);
|
||||
return *prototype;
|
||||
}
|
||||
|
||||
private:
|
||||
MetadataExchangeStats generateStats(const std::string& prefix, Stats::Scope& scope) {
|
||||
return MetadataExchangeStats{ALL_METADATA_EXCHANGE_STATS(POOL_COUNTER_PREFIX(scope, prefix))};
|
||||
|
|
@ -137,7 +126,7 @@ private:
|
|||
void tryReadProxyData(Buffer::Instance& data);
|
||||
|
||||
// Helper function to share the metadata with other filters.
|
||||
void updatePeer(const std::string& fb);
|
||||
void updatePeer(const std::shared_ptr<Istio::Common::WorkloadMetadataObject>& obj);
|
||||
void updatePeerId(absl::string_view key, absl::string_view value);
|
||||
|
||||
// Helper function to get Dynamic metadata.
|
||||
|
|
|
|||
Loading…
Reference in New Issue