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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ message DynamicModuleFilter {
// value: aGVsbG8= # echo -n "hello" | base64
//
google.protobuf.Any filter_config = 3;

// Allows configuring the stat prefix for all metrics emitted by the filter. By default, the stat prefix
// is equal to `dynamicmodulescustom`.
string stat_prefix = 4;
}

// Configuration of the HTTP per-route filter for dynamic modules. This filter allows loading shared object files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ absl::StatusOr<Http::FilterFactoryCb> DynamicModuleConfigFactory::createFilterFa
filter_config =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
proto_config.filter_name(), config, std::move(dynamic_module.value()),
dual_info.scope, context);
dual_info.scope, proto_config.stat_prefix(), context);

if (!filter_config.ok()) {
return absl::InvalidArgumentError("Failed to create filter config: " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ namespace HttpFilters {
DynamicModuleHttpFilterConfig::DynamicModuleHttpFilterConfig(
const absl::string_view filter_name, const absl::string_view filter_config,
Extensions::DynamicModules::DynamicModulePtr dynamic_module, Stats::Scope& stats_scope,
Server::Configuration::ServerFactoryContext& context)
const std::string stat_prefix, Server::Configuration::ServerFactoryContext& context)
: cluster_manager_(context.clusterManager()),
stats_scope_(stats_scope.createScope(std::string(CustomStatNamespace) + ".")),
stats_scope_(stats_scope.createScope(
(stat_prefix.length() > 0 ? stat_prefix : std::string(CustomStatNamespace)) + ".")),
stat_name_pool_(stats_scope_->symbolTable()), filter_name_(filter_name),
filter_config_(filter_config), dynamic_module_(std::move(dynamic_module)) {};

Expand Down Expand Up @@ -54,7 +55,7 @@ newDynamicModuleHttpPerRouteConfig(const absl::string_view per_route_config_name
absl::StatusOr<DynamicModuleHttpFilterConfigSharedPtr> newDynamicModuleHttpFilterConfig(
const absl::string_view filter_name, const absl::string_view filter_config,
Extensions::DynamicModules::DynamicModulePtr dynamic_module, Stats::Scope& stats_scope,
Server::Configuration::ServerFactoryContext& context) {
const std::string stat_prefix, Server::Configuration::ServerFactoryContext& context) {
auto constructor =
dynamic_module->getFunctionPointer<decltype(&envoy_dynamic_module_on_http_filter_config_new)>(
"envoy_dynamic_module_on_http_filter_config_new");
Expand Down Expand Up @@ -110,7 +111,7 @@ absl::StatusOr<DynamicModuleHttpFilterConfigSharedPtr> newDynamicModuleHttpFilte
RETURN_IF_NOT_OK_REF(on_scheduled.status());

auto config = std::make_shared<DynamicModuleHttpFilterConfig>(
filter_name, filter_config, std::move(dynamic_module), stats_scope, context);
filter_name, filter_config, std::move(dynamic_module), stats_scope, stat_prefix, context);

const void* filter_config_envoy_ptr =
(*constructor.value())(static_cast<void*>(config.get()), filter_name.data(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class DynamicModuleHttpFilterConfig {
DynamicModuleHttpFilterConfig(const absl::string_view filter_name,
const absl::string_view filter_config,
DynamicModulePtr dynamic_module, Stats::Scope& stats_scope,
const std::string stat_prefix,
Server::Configuration::ServerFactoryContext& context);

~DynamicModuleHttpFilterConfig();
Expand Down Expand Up @@ -309,13 +310,14 @@ newDynamicModuleHttpPerRouteConfig(const absl::string_view per_route_config_name
* @param filter_name the name of the filter.
* @param filter_config the configuration for the module.
* @param dynamic_module the dynamic module to use.
* @param stat_prefix the stat prefix for the filter.
* @param context the server factory context.
* @return a shared pointer to the new config object or an error if the module could not be loaded.
*/
absl::StatusOr<DynamicModuleHttpFilterConfigSharedPtr> newDynamicModuleHttpFilterConfig(
const absl::string_view filter_name, const absl::string_view filter_config,
Extensions::DynamicModules::DynamicModulePtr dynamic_module, Stats::Scope& stats_scope,
Server::Configuration::ServerFactoryContext& context);
const std::string stat_prefix, Server::Configuration::ServerFactoryContext& context);

} // namespace HttpFilters
} // namespace DynamicModules
Expand Down
2 changes: 1 addition & 1 deletion test/extensions/dynamic_modules/http/abi_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ TEST(ABIImpl, Stats) {
Stats::TestUtil::TestScope stats_scope{"", stats_store};
NiceMock<Server::Configuration::MockServerFactoryContext> context;
auto filter_config = std::make_shared<DynamicModuleHttpFilterConfig>(
"some_name", "some_config", nullptr, stats_scope, context);
"some_name", "some_config", nullptr, stats_scope, "", context);
DynamicModuleHttpFilter filter{filter_config, stats_scope.symbolTable()};

const std::string counter_name{"some_counter"};
Expand Down
52 changes: 40 additions & 12 deletions test/extensions/dynamic_modules/http/filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ TEST_P(DynamicModuleTestLanguages, Nop) {
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()),
*stats_store.createScope(""), context);
*stats_store.createScope(""), "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
Expand Down Expand Up @@ -71,7 +71,7 @@ TEST(DynamicModulesTest, ConfigInitializationFailure) {
Stats::IsolatedStoreImpl stats_store;
auto filter_config_or_status =
newDynamicModuleHttpFilterConfig("config_init_failure", "", std::move(dynamic_module.value()),
*stats_store.createScope(""), context);
*stats_store.createScope(""), "", context);
EXPECT_FALSE(filter_config_or_status.ok());
EXPECT_THAT(filter_config_or_status.status().message(),
testing::HasSubstr("Failed to initialize dynamic module"));
Expand All @@ -92,7 +92,7 @@ TEST(DynamicModulesTest, StatsCallbacks) {
Stats::TestUtil::TestScope stats_scope{"", stats_store};
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
Expand Down Expand Up @@ -197,6 +197,34 @@ TEST(DynamicModulesTest, StatsCallbacks) {
filter->onDestroy();
}

TEST(DynamicModulesTest, StatsCallbacksWithPrefix) {
const std::string filter_name = "stats_callbacks";
const std::string filter_config = "";
// TODO: Add non-Rust test program once we have non-Rust SDK.
auto dynamic_module = newDynamicModule(testSharedObjectPath("http", "rust"), false);
if (!dynamic_module.ok()) {
ENVOY_LOG_MISC(debug, "Failed to load dynamic module: {}", dynamic_module.status().message());
}
EXPECT_TRUE(dynamic_module.ok());

NiceMock<Server::Configuration::MockServerFactoryContext> context;
Stats::TestUtil::TestStore stats_store;
Stats::TestUtil::TestScope stats_scope{"", stats_store};
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), stats_scope, "fooprefix",
context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
stats_scope.symbolTable());
filter->initializeInModuleFilter();

Stats::CounterOptConstRef counter = stats_store.findCounterByString("fooprefix.streams_total");
EXPECT_TRUE(counter.has_value());
EXPECT_EQ(counter->get().value(), 1);
}

TEST(DynamicModulesTest, HeaderCallbacks) {
const std::string filter_name = "header_callbacks";
const std::string filter_config = "";
Expand All @@ -212,7 +240,7 @@ TEST(DynamicModulesTest, HeaderCallbacks) {
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()),
*stats_store.createScope(""), context);
*stats_store.createScope(""), "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
Expand Down Expand Up @@ -274,7 +302,7 @@ TEST(DynamicModulesTest, DynamicMetadataCallbacks) {
auto stats_scope = stats_store.createScope("");
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
Expand Down Expand Up @@ -357,7 +385,7 @@ TEST(DynamicModulesTest, FilterStateCallbacks) {
auto stats_scope = stats_store.createScope("");
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
Expand Down Expand Up @@ -434,7 +462,7 @@ TEST(DynamicModulesTest, BodyCallbacks) {
auto stats_scope = stats_store.createScope("");
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto filter = std::make_shared<DynamicModuleHttpFilter>(filter_config_or_status.value(),
Expand Down Expand Up @@ -511,7 +539,7 @@ TEST(DynamicModulesTest, HttpFilterHttpCallout_non_existing_cluster) {
.WillOnce(testing::Return(nullptr));
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

Http::MockStreamDecoderFilterCallbacks callbacks;
Expand Down Expand Up @@ -548,7 +576,7 @@ TEST(DynamicModulesTest, HttpFilterHttpCallout_immediate_failing_cluster) {
const std::string filter_config = "immediate_failing_cluster";
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

std::shared_ptr<Upstream::MockThreadLocalCluster> cluster =
Expand Down Expand Up @@ -601,7 +629,7 @@ TEST(DynamicModulesTest, HttpFilterHttpCallout_success) {
const std::string filter_config = "success_cluster";
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

std::shared_ptr<Upstream::MockThreadLocalCluster> cluster =
Expand Down Expand Up @@ -670,7 +698,7 @@ TEST(DynamicModulesTest, HttpFilterHttpCallout_resetting) {
const std::string filter_config = "resetting_cluster";
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

std::shared_ptr<Upstream::MockThreadLocalCluster> cluster =
Expand Down Expand Up @@ -723,7 +751,7 @@ TEST(DynamicModulesTest, HttpFilterPerFilterConfigLifetimes) {
const std::string filter_config = "listener config";
auto filter_config_or_status =
Envoy::Extensions::DynamicModules::HttpFilters::newDynamicModuleHttpFilterConfig(
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, context);
filter_name, filter_config, std::move(dynamic_module.value()), *stats_scope, "", context);
EXPECT_TRUE(filter_config_or_status.ok());

auto dynamic_module_for_route =
Expand Down
30 changes: 25 additions & 5 deletions test/extensions/dynamic_modules/http/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DynamicModulesIntegrationTest : public testing::TestWithParam<Network::Add
initializeFilter(const std::string& filter_name, const std::string& config = "",
const std::string& per_route_config = "",
const std::string& type_url = "type.googleapis.com/google.protobuf.StringValue",
bool upstream_filter = false) {
bool upstream_filter = false, const std::string& stat_prefix = "") {
TestEnvironment::setEnvVar(
"ENVOY_DYNAMIC_MODULES_SEARCH_PATH",
TestEnvironment::substitute(
Expand All @@ -31,6 +31,8 @@ name: envoy.extensions.filters.http.dynamic_modules
filter_config:
"@type": {}
value: {}
stat_prefix: {}

)EOF";

if (!per_route_config.empty()) {
Expand Down Expand Up @@ -63,8 +65,8 @@ per_route_config_name: {}

config_helper_.addConfigModifier(setEnableDownstreamTrailersHttp1());
config_helper_.addConfigModifier(setEnableUpstreamTrailersHttp1());
config_helper_.prependFilter(fmt::format(filter_config, filter_name, type_url, config),
!upstream_filter);
config_helper_.prependFilter(
fmt::format(filter_config, filter_name, type_url, config, stat_prefix), !upstream_filter);
initialize();
}
void runHeaderCallbacksTest(bool upstream_filter) {
Expand Down Expand Up @@ -598,14 +600,32 @@ TEST_P(DynamicModulesIntegrationTest, StatsCallbacks) {
3 + 13);

Http::TestResponseHeaderMapImpl response_headers = default_response_headers_;
response_headers.addCopy(Http::LowerCaseString("header_to_count"), "5");
response_headers.addCopy(Http::LowerCaseString("header_to_set"), "1000");
upstream_request_->encodeHeaders(response_headers, true);
ASSERT_TRUE(response->waitForEndStream());
EXPECT_TRUE(response->complete());
}
}

TEST_P(DynamicModulesIntegrationTest, StatsCallbacksWithPrefix) {
initializeFilter("stats_callbacks", "header_to_count,header_to_set", "",
"type.googleapis.com/google.protobuf.StringValue", false, "fooprefix");
codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http"))));

Http::TestRequestHeaderMapImpl request_headers = default_request_headers_;
request_headers.addCopy(Http::LowerCaseString("header_to_count"), "13");
auto encoder_decoder = codec_client_->startRequest(request_headers, true);
auto response = std::move(encoder_decoder.second);
waitForNextUpstreamRequest();
test_server_->waitUntilHistogramHasSamples("fooprefix.requests_header_values");

EXPECT_EQ(test_server_->counter("fooprefix.requests_total")->value(), 1);

Http::TestResponseHeaderMapImpl response_headers = default_response_headers_;
upstream_request_->encodeHeaders(response_headers, true);
ASSERT_TRUE(response->waitForEndStream());
EXPECT_TRUE(response->complete());
}

TEST_P(DynamicModulesIntegrationTest, InjectBody) {
initializeFilter("inject_body");
codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http"))));
Expand Down