Skip to content

Commit 82251af

Browse files
authored
istio stats: remove the dependency to the direction of factory context (#46906)
Commit Message: istio stats: remove the dependency to the direction of factory context Additional Description: Now, the the istio stats won't depends on the factory context's trafficDirection(), like what we did at the #46893 After all these filters be updated, we could remove the direction() from the FactoryContext and the these filters also could works correctly at cross-listeners shared filter chain (FCDS). Risk Level: low. Testing: n/a. Docs Changes: n/a. Release Notes: n/a. Platform Specific Features: n/a. --------- Signed-off-by: wbpcode <wbphub@gmail.com>
1 parent 810f5e4 commit 82251af

2 files changed

Lines changed: 90 additions & 44 deletions

File tree

contrib/istio/filters/http/istio_stats/source/istio_stats.cc

Lines changed: 85 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ enum class Reporter {
114114
ServerSidecar,
115115
// Gateway listener for a set of destination workloads.
116116
ServerGateway,
117+
// The configuration does not specify the
118+
// reporter type and the traffic direction
119+
// will be used to infer the reporter type.
120+
Unspecified,
117121
};
118122

119123
// Detect if peer info read is completed by TCP metadata exchange.
@@ -474,30 +478,22 @@ struct MetricOverrides : public Logger::Loggable<Logger::Id::filter> {
474478

475479
struct Config : public Logger::Loggable<Logger::Id::filter> {
476480
Config(const stats::PluginConfig& proto_config,
477-
Server::Configuration::FactoryContext& factory_context)
478-
: context_(factory_context.serverFactoryContext().singletonManager().getTyped<Context>(
481+
Server::Configuration::ServerFactoryContext& context, Stats::Scope& stats_scope)
482+
: context_(context.singletonManager().getTyped<Context>(
479483
SINGLETON_MANAGER_REGISTERED_NAME(Context),
480-
[&factory_context] {
481-
return std::make_shared<Context>(factory_context.serverFactoryContext().scope(),
482-
factory_context.serverFactoryContext().localInfo());
484+
[&context] {
485+
return std::make_shared<Context>(context.scope(), context.localInfo());
483486
})),
484487
disable_host_header_fallback_(proto_config.disable_host_header_fallback()),
485488
report_duration_(
486489
PROTOBUF_GET_MS_OR_DEFAULT(proto_config, tcp_reporting_duration, /* 5s */ 5000)) {
487-
recordVersion(factory_context);
490+
recordVersion(stats_scope);
488491
reporter_ = Reporter::ClientSidecar;
489492
switch (proto_config.reporter()) {
490493
case stats::Reporter::UNSPECIFIED:
491-
switch (factory_context.direction()) {
492-
case envoy::config::core::v3::TrafficDirection::INBOUND:
493-
reporter_ = Reporter::ServerSidecar;
494-
break;
495-
case envoy::config::core::v3::TrafficDirection::OUTBOUND:
496-
reporter_ = Reporter::ClientSidecar;
497-
break;
498-
default:
499-
break;
500-
}
494+
// Mark as unspecified to allow the filter to infer the reporter type based on traffic
495+
// direction.
496+
reporter_ = Reporter::Unspecified;
501497
break;
502498
case stats::Reporter::SERVER_GATEWAY:
503499
reporter_ = Reporter::ServerGateway;
@@ -743,14 +739,13 @@ struct Config : public Logger::Loggable<Logger::Id::filter> {
743739
bool evaluated_{false};
744740
};
745741

746-
void recordVersion(Server::Configuration::FactoryContext& factory_context) {
742+
void recordVersion(Stats::Scope& scope) {
747743
Stats::StatNameTagVector tags;
748744
tags.push_back({context_->component_, context_->proxy_});
749745
tags.push_back({context_->tag_, context_->istio_version_.empty() ? context_->unknown_
750746
: context_->istio_version_});
751747

752-
Stats::Utility::gaugeFromStatNames(factory_context.scope(),
753-
{context_->stat_namespace_, context_->istio_build_},
748+
Stats::Utility::gaugeFromStatNames(scope, {context_->stat_namespace_, context_->istio_build_},
754749
Stats::Gauge::ImportMode::Accumulate, tags)
755750
.set(1);
756751
}
@@ -776,9 +771,46 @@ class IstioStatsFilter : public Http::PassThroughFilter,
776771
public:
777772
IstioStatsFilter(ConfigSharedPtr config)
778773
: config_(config), context_(*config->context_), pool_(config->scope().symbolTable()),
779-
stream_(*config_, pool_) {
774+
stream_(*config_, pool_) {}
775+
~IstioStatsFilter() override { ASSERT(report_timer_ == nullptr); }
776+
777+
// The reporter type is only set explicitly by gateways/waypoints. Sidecars leave it
778+
// unspecified in the config and it is inferred here from the direction of the listener
779+
// that owns this stream or connection.
780+
Reporter resolveReporter() const {
781+
ASSERT(decoder_callbacks_ != nullptr || network_read_callbacks_ != nullptr);
782+
if (config_->reporter() != Reporter::Unspecified) {
783+
return config_->reporter();
784+
}
785+
786+
OptRef<const Network::ListenerInfo> listener_info;
787+
if (decoder_callbacks_ != nullptr) {
788+
listener_info = decoder_callbacks_->streamInfo().downstreamAddressProvider().listenerInfo();
789+
} else if (network_read_callbacks_ != nullptr) {
790+
listener_info = network_read_callbacks_->connection().connectionInfoProvider().listenerInfo();
791+
}
792+
if (listener_info.has_value()) {
793+
switch (listener_info->direction()) {
794+
case envoy::config::core::v3::TrafficDirection::INBOUND:
795+
return Reporter::ServerSidecar;
796+
case envoy::config::core::v3::TrafficDirection::OUTBOUND:
797+
return Reporter::ClientSidecar;
798+
default:
799+
break;
800+
}
801+
}
802+
// Retain the historical default for listeners without a traffic direction.
803+
return Reporter::ClientSidecar;
804+
}
805+
806+
// Resolved reporter type. Only valid once initializeTags() has run, which is the first
807+
// thing both the HTTP and the network entry point do.
808+
Reporter reporter() const { return reporter_; }
809+
810+
void initializeTags() {
811+
reporter_ = resolveReporter();
780812
tags_.reserve(25);
781-
switch (config_->reporter()) {
813+
switch (reporter_) {
782814
case Reporter::ServerSidecar:
783815
tags_.push_back({context_.reporter_, context_.destination_});
784816
break;
@@ -788,11 +820,19 @@ class IstioStatsFilter : public Http::PassThroughFilter,
788820
case Reporter::ClientSidecar:
789821
tags_.push_back({context_.reporter_, context_.source_});
790822
break;
823+
case Reporter::Unspecified:
824+
// Unreachable: resolveReporter() never returns Unspecified.
825+
IS_ENVOY_BUG("unresolved istio stats reporter");
826+
tags_.push_back({context_.reporter_, context_.unknown_});
827+
break;
791828
}
792829
}
793-
~IstioStatsFilter() override { ASSERT(report_timer_ == nullptr); }
794830

795831
// Http::StreamDecoderFilter
832+
void setDecoderFilterCallbacks(Http::StreamDecoderFilterCallbacks& callbacks) override {
833+
decoder_callbacks_ = &callbacks;
834+
initializeTags();
835+
}
796836
Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& request_headers, bool) override {
797837
is_grpc_ = Grpc::Common::isGrpcRequestHeaders(request_headers);
798838
if (is_grpc_) {
@@ -866,6 +906,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
866906
}
867907
void initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) override {
868908
network_read_callbacks_ = &callbacks;
909+
initializeTags();
869910
network_read_callbacks_->connection().addConnectionCallbacks(*this);
870911
}
871912
// Network::ConnectionCallbacks
@@ -893,7 +934,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
893934
if (decoder_callbacks_) {
894935
if (!peer_read_) {
895936
const auto& info = decoder_callbacks_->streamInfo();
896-
peer_read_ = peerInfoRead(config_->reporter(), info.filterState());
937+
peer_read_ = peerInfoRead(reporter(), info.filterState());
897938
if (peer_read_ || end_stream) {
898939
ENVOY_LOG(trace, "Populating peer metadata from HTTP MX.");
899940
populatePeerInfo(info, info.filterState());
@@ -922,7 +963,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
922963
const auto& info = network_read_callbacks_->connection().streamInfo();
923964
// TCP MX writes to upstream stream info instead.
924965
OptRef<const StreamInfo::UpstreamInfo> upstream_info;
925-
if (config_->reporter() == Reporter::ClientSidecar) {
966+
if (reporter() == Reporter::ClientSidecar) {
926967
upstream_info = info.upstreamInfo();
927968
}
928969
const StreamInfo::FilterState& filter_state =
@@ -931,7 +972,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
931972
: info.filterState();
932973

933974
if (!peer_read_) {
934-
peer_read_ = peerInfoRead(config_->reporter(), filter_state);
975+
peer_read_ = peerInfoRead(reporter(), filter_state);
935976
// Report connection open once peer info is read or connection is closed.
936977
if (peer_read_ || end_stream) {
937978
ENVOY_LOG(trace, "Populating peer metadata from TCP MX.");
@@ -979,10 +1020,10 @@ class IstioStatsFilter : public Http::PassThroughFilter,
9791020
const StreamInfo::FilterState& filter_state) {
9801021
// Compute peer info with client-side fallbacks.
9811022
std::optional<Istio::Common::WorkloadMetadataObject> peer;
982-
auto object = peerInfo(config_->reporter(), filter_state);
1023+
auto object = peerInfo(reporter(), filter_state);
9831024
if (object) {
9841025
peer.emplace(object.value());
985-
} else if (config_->reporter() == Reporter::ClientSidecar) {
1026+
} else if (reporter() == Reporter::ClientSidecar) {
9861027
if (auto label_obj = extractEndpointMetadata(info); label_obj) {
9871028
peer.emplace(label_obj.value());
9881029
}
@@ -1044,7 +1085,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
10441085

10451086
std::string peer_san;
10461087
absl::string_view local_san;
1047-
switch (config_->reporter()) {
1088+
switch (reporter()) {
10481089
case Reporter::ServerSidecar:
10491090
case Reporter::ServerGateway: {
10501091
auto peer_principal =
@@ -1078,7 +1119,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
10781119
peer_san = ssl_info->uriSanPeerCertificate()[0];
10791120
}
10801121
if (peer_san.empty()) {
1081-
auto endpoint_object = peerInfo(config_->reporter(), filter_state);
1122+
auto endpoint_object = peerInfo(reporter(), filter_state);
10821123
if (endpoint_object) {
10831124
endpoint_peer.emplace(endpoint_object.value());
10841125
peer_san = endpoint_peer->identity_;
@@ -1091,6 +1132,8 @@ class IstioStatsFilter : public Http::PassThroughFilter,
10911132
}
10921133
break;
10931134
}
1135+
case Reporter::Unspecified:
1136+
break;
10941137
}
10951138
// Implements fallback from using the namespace from SAN if available to
10961139
// using peer metadata, otherwise.
@@ -1104,7 +1147,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
11041147
if (peer_namespace.empty() && peer) {
11051148
peer_namespace = peer->namespace_name_;
11061149
}
1107-
switch (config_->reporter()) {
1150+
switch (reporter()) {
11081151
case Reporter::ServerSidecar:
11091152
case Reporter::ServerGateway: {
11101153
tags_.push_back({context_.source_workload_, peer && !peer->workload_name_.empty()
@@ -1130,7 +1173,7 @@ class IstioStatsFilter : public Http::PassThroughFilter,
11301173
tags_.push_back({context_.source_cluster_, peer && !peer->cluster_name_.empty()
11311174
? pool_.add(peer->cluster_name_)
11321175
: context_.unknown_});
1133-
switch (config_->reporter()) {
1176+
switch (reporter()) {
11341177
case Reporter::ServerGateway: {
11351178
std::optional<Istio::Common::WorkloadMetadataObject> endpoint_peer;
11361179
auto endpoint_object = peerInfo(Reporter::ClientSidecar, filter_state);
@@ -1256,8 +1299,9 @@ class IstioStatsFilter : public Http::PassThroughFilter,
12561299
Context& context_;
12571300
Stats::StatNameDynamicPool pool_;
12581301
Stats::StatNameTagVector tags_;
1302+
Reporter reporter_{Reporter::ClientSidecar};
12591303
Event::TimerPtr report_timer_{nullptr};
1260-
Network::ReadFilterCallbacks* network_read_callbacks_;
1304+
Network::ReadFilterCallbacks* network_read_callbacks_{nullptr};
12611305
bool peer_read_{false};
12621306
uint64_t bytes_sent_{0};
12631307
uint64_t bytes_received_{0};
@@ -1272,12 +1316,12 @@ class IstioStatsFilter : public Http::PassThroughFilter,
12721316
} // namespace
12731317

12741318
absl::StatusOr<Http::FilterFactoryCb>
1275-
IstioStatsFilterConfigFactory::createFilterFactoryFromProtoTyped(
1276-
const stats::PluginConfig& proto_config, const std::string&,
1277-
Server::Configuration::FactoryContext& factory_context) {
1278-
factory_context.serverFactoryContext().api().customStatNamespaces().registerStatNamespace(
1279-
CustomStatNamespace);
1280-
ConfigSharedPtr config = std::make_shared<Config>(proto_config, factory_context);
1319+
IstioStatsFilterConfigFactory::createHttpFilterFactoryFromProtoTyped(
1320+
const stats::PluginConfig& proto_config, Server::Configuration::ServerFactoryContext& context,
1321+
Server::Configuration::ExtraFactoryContext& extra_context) {
1322+
context.api().customStatNamespaces().registerStatNamespace(CustomStatNamespace);
1323+
ConfigSharedPtr config =
1324+
std::make_shared<Config>(proto_config, context, extra_context.scopeOr(context));
12811325
return [config](Http::FilterChainFactoryCallbacks& callbacks) {
12821326
auto filter = std::make_shared<IstioStatsFilter>(config);
12831327
callbacks.addStreamFilter(filter);
@@ -1295,8 +1339,9 @@ IstioStatsNetworkFilterConfigFactory::createFilterFactoryFromProto(
12951339
const Protobuf::Message& proto_config, Server::Configuration::FactoryContext& factory_context) {
12961340
factory_context.serverFactoryContext().api().customStatNamespaces().registerStatNamespace(
12971341
CustomStatNamespace);
1298-
ConfigSharedPtr config = std::make_shared<Config>(
1299-
dynamic_cast<const stats::PluginConfig&>(proto_config), factory_context);
1342+
ConfigSharedPtr config =
1343+
std::make_shared<Config>(dynamic_cast<const stats::PluginConfig&>(proto_config),
1344+
factory_context.serverFactoryContext(), factory_context.scope());
13001345
return [config](Network::FilterManager& filter_manager) {
13011346
filter_manager.addReadFilter(std::make_shared<IstioStatsFilter>(config));
13021347
};

contrib/istio/filters/http/istio_stats/source/istio_stats.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ namespace Extensions {
1313
namespace HttpFilters {
1414
namespace IstioStats {
1515

16-
class IstioStatsFilterConfigFactory : public Common::ExceptionFreeFactoryBase<stats::PluginConfig> {
16+
class IstioStatsFilterConfigFactory : public Common::UnifiedFactoryBase<stats::PluginConfig> {
1717
public:
18-
IstioStatsFilterConfigFactory() : ExceptionFreeFactoryBase("envoy.filters.http.istio_stats") {}
18+
IstioStatsFilterConfigFactory() : UnifiedFactoryBase("envoy.filters.http.istio_stats") {}
1919

2020
private:
2121
absl::StatusOr<Http::FilterFactoryCb>
22-
createFilterFactoryFromProtoTyped(const stats::PluginConfig& proto_config, const std::string&,
23-
Server::Configuration::FactoryContext&) override;
22+
createHttpFilterFactoryFromProtoTyped(const stats::PluginConfig& proto_config,
23+
Server::Configuration::ServerFactoryContext&,
24+
Server::Configuration::ExtraFactoryContext&) override;
2425
};
2526

2627
class IstioStatsNetworkFilterConfigFactory

0 commit comments

Comments
 (0)