-
Notifications
You must be signed in to change notification settings - Fork 5.5k
config: support determine terminal filter at runtime #15803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
a33db77
e93cfb4
418554b
ed05ce5
bcf50b2
e89113f
3bebde5
18bf6ed
3d81b83
55dba70
af0ecf2
7b2214d
f5c5371
a6dee8f
0e56490
e7075fa
c98dd0e
3b3884e
123ac59
244ebb4
b9dfe5c
d72f95f
f3dde43
dbff93b
953f9b2
ff8a04b
3f9afe6
23aade7
af1a9b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,11 +32,14 @@ class FilterConfigProviderManager { | |
| * @param filter_config_name the filter config resource name. | ||
| * @param factory_context is the context to use for the filter config provider. | ||
| * @param stat_prefix supplies the stat_prefix to use for the provider stats. | ||
| * @param last_filter_in_current_config indicate the filter position at filter chain | ||
| * @param filter_chain_type is the filter chain type | ||
| */ | ||
| virtual FilterConfigProviderPtr createDynamicFilterConfigProvider( | ||
| const envoy::config::core::v3::ExtensionConfigSource& config_source, | ||
| const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, | ||
| const std::string& stat_prefix) PURE; | ||
| const std::string& stat_prefix, bool last_filter_in_current_config, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe just
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const std::string& filter_chain_type) PURE; | ||
|
|
||
| /** | ||
| * Get an FilterConfigProviderPtr for a statically inlined filter config. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,16 +17,21 @@ namespace Http { | |
| DynamicFilterConfigProviderImpl::DynamicFilterConfigProviderImpl( | ||
| FilterConfigSubscriptionSharedPtr& subscription, | ||
| const absl::flat_hash_set<std::string>& require_type_urls, | ||
| Server::Configuration::FactoryContext& factory_context) | ||
| Server::Configuration::FactoryContext& factory_context, bool last_filter_in_current_config, | ||
| const std::string& filter_chain_type) | ||
| : subscription_(subscription), require_type_urls_(require_type_urls), | ||
| tls_(factory_context.threadLocal()), | ||
| init_target_("DynamicFilterConfigProviderImpl", [this]() { | ||
| subscription_->start(); | ||
| // This init target is used to activate the subscription but not wait | ||
| // for a response. It is used whenever a default config is provided to be | ||
| // used while waiting for a response. | ||
| init_target_.ready(); | ||
| }) { | ||
| tls_(factory_context.threadLocal()), init_target_("DynamicFilterConfigProviderImpl", | ||
| [this]() { | ||
| subscription_->start(); | ||
| // This init target is used to activate | ||
| // the subscription but not wait for a | ||
| // response. It is used whenever a default | ||
| // config is provided to be used while | ||
| // waiting for a response. | ||
| init_target_.ready(); | ||
| }), | ||
| last_filter_in_current_config_(last_filter_in_current_config), | ||
| filter_chain_type_(filter_chain_type) { | ||
| subscription_->filter_config_providers_.insert(this); | ||
| tls_.set([](Event::Dispatcher&) { return std::make_shared<ThreadLocalConfig>(); }); | ||
| } | ||
|
|
@@ -64,6 +69,12 @@ void DynamicFilterConfigProviderImpl::onConfigUpdate(Envoy::Http::FilterFactoryC | |
| this->current_config_ = config; | ||
| }); | ||
| } | ||
| void DynamicFilterConfigProviderImpl::validateTermianlFilter(const std::string& name, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo in name
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed. |
||
| const std::string& filter_type, | ||
| bool is_terminal_filter) { | ||
| Config::Utility::validateTerminalFilters(name, filter_type, filter_chain_type_, | ||
| is_terminal_filter, last_filter_in_current_config_); | ||
| } | ||
|
|
||
| FilterConfigSubscription::FilterConfigSubscription( | ||
| const envoy::config::core::v3::ConfigSource& config_source, | ||
|
|
@@ -106,7 +117,7 @@ void FilterConfigSubscription::onConfigUpdate( | |
| throw EnvoyException(fmt::format( | ||
| "Unexpected number of resources in ExtensionConfigDS response: {}", resources.size())); | ||
| } | ||
| const auto& filter_config = dynamic_cast<const envoy::config::core::v3::TypedExtensionConfig&>( | ||
| auto& filter_config = dynamic_cast<const envoy::config::core::v3::TypedExtensionConfig&>( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why remove the const here? we cast to a const ref
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, did not notice. |
||
| resources[0].get().resource()); | ||
| if (filter_config.name() != filter_config_name_) { | ||
| throw EnvoyException(fmt::format("Unexpected resource name in ExtensionConfigDS response: {}", | ||
|
|
@@ -129,6 +140,11 @@ void FilterConfigSubscription::onConfigUpdate( | |
| } | ||
| ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( | ||
| filter_config.typed_config(), validator_, factory); | ||
|
|
||
| for (auto* provider : filter_config_providers_) { | ||
| provider->validateTermianlFilter(filter_config_name_, factory.name(), | ||
| factory.isTerminalFilter(*message, factory_context_)); | ||
| } | ||
| Envoy::Http::FilterFactoryCb factory_callback = | ||
| factory.createFilterFactoryFromProto(*message, stat_prefix_, factory_context_); | ||
| ENVOY_LOG(debug, "Updating filter config {}", filter_config_name_); | ||
|
|
@@ -145,6 +161,7 @@ void FilterConfigSubscription::onConfigUpdate( | |
| last_config_ = factory_callback; | ||
| last_type_url_ = type_url; | ||
| last_version_info_ = version_info; | ||
| last_filter_config_ = filter_config; | ||
| } | ||
|
|
||
| void FilterConfigSubscription::onConfigUpdate( | ||
|
|
@@ -203,7 +220,8 @@ std::shared_ptr<FilterConfigSubscription> FilterConfigProviderManagerImpl::getSu | |
| FilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFilterConfigProvider( | ||
| const envoy::config::core::v3::ExtensionConfigSource& config_source, | ||
| const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, | ||
| const std::string& stat_prefix) { | ||
| const std::string& stat_prefix, bool last_filter_in_current_config, | ||
| const std::string& filter_chain_type) { | ||
| auto subscription = getSubscription(config_source.config_source(), filter_config_name, | ||
| factory_context, stat_prefix); | ||
| // For warming, wait until the subscription receives the first response to indicate readiness. | ||
|
|
@@ -217,8 +235,9 @@ FilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFilterConf | |
| auto factory_type_url = TypeUtil::typeUrlToDescriptorFullName(type_url); | ||
| require_type_urls.emplace(factory_type_url); | ||
| } | ||
| auto provider = std::make_unique<DynamicFilterConfigProviderImpl>(subscription, require_type_urls, | ||
| factory_context); | ||
| auto provider = std::make_unique<DynamicFilterConfigProviderImpl>( | ||
| subscription, require_type_urls, factory_context, last_filter_in_current_config, | ||
| filter_chain_type); | ||
| // Ensure the subscription starts if it has not already. | ||
| if (config_source.apply_default_config_without_warming()) { | ||
| factory_context.initManager().add(provider->init_target_); | ||
|
|
@@ -233,6 +252,14 @@ FilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFilterConf | |
| if (subscription->lastConfig().has_value()) { | ||
| TRY_ASSERT_MAIN_THREAD { | ||
| provider->validateTypeUrl(subscription->lastTypeUrl()); | ||
| auto& factory = | ||
| Config::Utility::getAndCheckFactory<Server::Configuration::NamedHttpFilterConfigFactory>( | ||
| subscription->lastFilterConfig()); | ||
| auto message = Config::Utility::translateAnyToFactoryConfig( | ||
| subscription->lastFilterConfig().typed_config(), | ||
| factory_context.messageValidationVisitor(), factory); | ||
| provider->validateTermianlFilter(filter_config_name, factory.name(), | ||
| factory.isTerminalFilter(*message, factory_context)); | ||
| last_config_valid = true; | ||
| } | ||
| END_TRY catch (const EnvoyException& e) { | ||
|
|
@@ -261,6 +288,8 @@ FilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFilterConf | |
| ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( | ||
| config_source.default_config(), factory_context.messageValidationVisitor(), | ||
| *default_factory); | ||
| provider->validateTermianlFilter(filter_config_name, default_factory->name(), | ||
| default_factory->isTerminalFilter(*message, factory_context)); | ||
| Envoy::Http::FilterFactoryCb default_config = | ||
| default_factory->createFilterFactoryFromProto(*message, stat_prefix, factory_context); | ||
| provider->onConfigUpdate(default_config, "", nullptr); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,11 +33,14 @@ class DynamicFilterConfigProviderImpl : public FilterConfigProvider { | |
| public: | ||
| DynamicFilterConfigProviderImpl(FilterConfigSubscriptionSharedPtr& subscription, | ||
| const absl::flat_hash_set<std::string>& require_type_urls, | ||
| Server::Configuration::FactoryContext& factory_context); | ||
| Server::Configuration::FactoryContext& factory_context, | ||
| bool last_filter_in_current_config, | ||
| const std::string& filter_chain_type); | ||
| ~DynamicFilterConfigProviderImpl() override; | ||
|
|
||
| void validateTypeUrl(const std::string& type_url) const; | ||
|
|
||
| void validateTermianlFilter(const std::string& name, const std::string& filter_type, | ||
| bool is_terminal_filter); | ||
| // Config::ExtensionConfigProvider | ||
| const std::string& name() override; | ||
| absl::optional<Envoy::Http::FilterFactoryCb> config() override; | ||
|
|
@@ -61,6 +64,8 @@ class DynamicFilterConfigProviderImpl : public FilterConfigProvider { | |
| // case no warming is requested by any other filter config provider. | ||
| Init::TargetImpl init_target_; | ||
|
|
||
| const bool last_filter_in_current_config_; | ||
| const std::string filter_chain_type_; | ||
| friend class FilterConfigProviderManagerImpl; | ||
| }; | ||
|
|
||
|
|
@@ -102,6 +107,9 @@ class FilterConfigSubscription | |
| const absl::optional<Envoy::Http::FilterFactoryCb>& lastConfig() { return last_config_; } | ||
| const std::string& lastTypeUrl() { return last_type_url_; } | ||
| const std::string& lastVersionInfo() { return last_version_info_; } | ||
| const envoy::config::core::v3::TypedExtensionConfig& lastFilterConfig() { | ||
| return last_filter_config_; | ||
| } | ||
| void incrementConflictCounter(); | ||
|
|
||
| private: | ||
|
|
@@ -121,6 +129,7 @@ class FilterConfigSubscription | |
| absl::optional<Envoy::Http::FilterFactoryCb> last_config_{absl::nullopt}; | ||
| std::string last_type_url_; | ||
| std::string last_version_info_; | ||
| envoy::config::core::v3::TypedExtensionConfig last_filter_config_; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we intentionally avoid storing the entire filter config, can we just track whether the last filter passed the terminal filter check?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we only need |
||
| Server::Configuration::FactoryContext& factory_context_; | ||
| ProtobufMessage::ValidationVisitor& validator_; | ||
|
|
||
|
|
@@ -174,7 +183,8 @@ class FilterConfigProviderManagerImpl : public FilterConfigProviderManager, | |
| FilterConfigProviderPtr createDynamicFilterConfigProvider( | ||
| const envoy::config::core::v3::ExtensionConfigSource& config_source, | ||
| const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, | ||
| const std::string& stat_prefix) override; | ||
| const std::string& stat_prefix, bool last_filter_in_current_config, | ||
| const std::string& filter_chain_type) override; | ||
|
|
||
| FilterConfigProviderPtr | ||
| createStaticFilterConfigProvider(const Envoy::Http::FilterFactoryCb& config, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe something like
indicates whether this filter is the last filter in the configured chainThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.