move flatbuffers

Change-Id: Ic0390cdcf4f6696dbedf644f25bf1d4c3b2bf8c6
Signed-off-by: Kuat Yessenov <kuat@google.com>
This commit is contained in:
Kuat Yessenov 2024-05-14 20:48:35 +00:00
parent 0ecfabc99a
commit 789b8a7e95
19 changed files with 195 additions and 733 deletions

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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",
],
)

View File

@ -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.

View File

@ -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,

View File

@ -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_,

View File

@ -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",

View File

@ -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");
}

View File

@ -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_;

View File

@ -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,

View File

@ -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",
],
)

View File

@ -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,

View File

@ -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.