diff --git a/envoy/config/extension_config_provider.h b/envoy/config/extension_config_provider.h index e55ca63543f6..ba8761f045fa 100644 --- a/envoy/config/extension_config_provider.h +++ b/envoy/config/extension_config_provider.h @@ -16,7 +16,7 @@ using ConfigAppliedCb = std::function; * the extension configuration discovery service. Dynamically updated extension * configurations may share subscriptions across extension config providers. */ -template class ExtensionConfigProvider { +template class ExtensionConfigProvider { public: virtual ~ExtensionConfigProvider() = default; @@ -63,9 +63,9 @@ class DynamicExtensionConfigProviderBase { virtual void applyDefaultConfiguration() PURE; }; -template +template class DynamicExtensionConfigProvider : public DynamicExtensionConfigProviderBase, - public ExtensionConfigProvider {}; + public ExtensionConfigProvider {}; } // namespace Config } // namespace Envoy diff --git a/envoy/filter/BUILD b/envoy/filter/BUILD index 02e267213684..9a6697e0ee63 100644 --- a/envoy/filter/BUILD +++ b/envoy/filter/BUILD @@ -13,7 +13,6 @@ envoy_cc_library( hdrs = ["config_provider_manager.h"], deps = [ "//envoy/config:extension_config_provider_interface", - "//envoy/http:filter_interface", "//envoy/init:manager_interface", "//envoy/server:filter_config_interface", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", diff --git a/envoy/filter/config_provider_manager.h b/envoy/filter/config_provider_manager.h index 824c36e73dea..cd1affc57997 100644 --- a/envoy/filter/config_provider_manager.h +++ b/envoy/filter/config_provider_manager.h @@ -2,7 +2,6 @@ #include "envoy/config/core/v3/config_source.pb.h" #include "envoy/config/extension_config_provider.h" -#include "envoy/http/filter.h" #include "envoy/init/manager.h" #include "envoy/server/filter_config.h" @@ -11,19 +10,20 @@ namespace Envoy { namespace Filter { -using FilterConfigProvider = - Envoy::Config::ExtensionConfigProvider; -using FilterConfigProviderPtr = std::unique_ptr; -using DynamicFilterConfigProvider = Envoy::Config::DynamicExtensionConfigProvider< - Server::Configuration::NamedHttpFilterConfigFactory, Envoy::Http::FilterFactoryCb>; -using DynamicFilterConfigProviderPtr = std::unique_ptr; +template +using FilterConfigProvider = Envoy::Config::ExtensionConfigProvider; +template +using FilterConfigProviderPtr = std::unique_ptr>; +template +using DynamicFilterConfigProvider = Envoy::Config::DynamicExtensionConfigProvider; +template +using DynamicFilterConfigProviderPtr = std::unique_ptr>; /** * The FilterConfigProviderManager exposes the ability to get an FilterConfigProvider * for both static and dynamic filter config providers. */ -class FilterConfigProviderManager { +template class FilterConfigProviderManager { public: virtual ~FilterConfigProviderManager() = default; @@ -38,7 +38,7 @@ class FilterConfigProviderManager { * configured chain * @param filter_chain_type is the filter chain type */ - virtual DynamicFilterConfigProviderPtr createDynamicFilterConfigProvider( + virtual DynamicFilterConfigProviderPtr 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, bool last_filter_in_filter_chain, @@ -49,8 +49,8 @@ class FilterConfigProviderManager { * @param config is a fully resolved filter instantiation factory. * @param filter_config_name is the name of the filter configuration resource. */ - virtual FilterConfigProviderPtr - createStaticFilterConfigProvider(const Envoy::Http::FilterFactoryCb& config, + virtual FilterConfigProviderPtr + createStaticFilterConfigProvider(const FactoryCb& config, const std::string& filter_config_name) PURE; }; diff --git a/source/common/filter/config_discovery_impl.cc b/source/common/filter/config_discovery_impl.cc index 5b694d63b427..7ff56f26471f 100644 --- a/source/common/filter/config_discovery_impl.cc +++ b/source/common/filter/config_discovery_impl.cc @@ -73,7 +73,6 @@ FilterConfigSubscription::FilterConfigSubscription( : Config::SubscriptionBase( factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), filter_config_name_(filter_config_name), factory_context_(factory_context), - validator_(factory_context.messageValidationContext().dynamicValidationVisitor()), init_target_(fmt::format("FilterConfigSubscription init {}", filter_config_name_), [this]() { start(); }), scope_(factory_context.scope().createScope(stat_prefix + "extension_config_discovery." + @@ -116,9 +115,6 @@ void FilterConfigSubscription::onConfigUpdate( if (new_hash == last_config_hash_) { return; } - auto& factory = - Config::Utility::getAndCheckFactory( - filter_config); // Ensure that the filter config is valid in the filter chain context once the proto is processed. // Validation happens before updating to prevent a partial update application. It might be // possible that the providers have distinct type URL constraints. @@ -126,18 +122,17 @@ void FilterConfigSubscription::onConfigUpdate( for (auto* provider : filter_config_providers_) { provider->validateTypeUrl(type_url); } - ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - filter_config.typed_config(), validator_, factory); - bool is_terminal_filter = factory.isTerminalFilterByProto(*message, factory_context_); + auto [message, factory_name, is_terminal_filter] = + filter_config_provider_manager_.getMessage(filter_config, factory_context_); for (auto* provider : filter_config_providers_) { - provider->validateTerminalFilter(filter_config_name_, factory.name(), is_terminal_filter); + provider->validateTerminalFilter(filter_config_name_, factory_name, is_terminal_filter); } ENVOY_LOG(debug, "Updating filter config {}", filter_config_name_); Common::applyToAllWithCleanup( filter_config_providers_, - [&message, &version_info](DynamicFilterConfigProviderImplBase* provider, - std::shared_ptr cleanup) { + [&message = message, &version_info](DynamicFilterConfigProviderImplBase* provider, + std::shared_ptr cleanup) { provider->onConfigUpdate(*message, version_info, [cleanup] {}); }, [this]() { stats_.config_reload_.inc(); }); @@ -145,7 +140,7 @@ void FilterConfigSubscription::onConfigUpdate( last_config_ = std::move(message); last_type_url_ = type_url; last_version_info_ = version_info; - last_filter_name_ = factory.name(); + last_filter_name_ = factory_name; last_filter_is_terminal_ = is_terminal_filter; } @@ -244,46 +239,18 @@ void FilterConfigProviderManagerImplBase::applyLastOrDefaultConfig( } } -DynamicFilterConfigProviderPtr 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, bool last_filter_in_filter_chain, - 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. - // Otherwise, mark ready immediately and start the subscription on initialization. A default - // config is expected in the latter case. - if (!config_source.apply_default_config_without_warming()) { - factory_context.initManager().add(subscription->initTarget()); - } - absl::flat_hash_set require_type_urls; - for (const auto& type_url : config_source.type_urls()) { - auto factory_type_url = TypeUtil::typeUrlToDescriptorFullName(type_url); - require_type_urls.emplace(factory_type_url); - } - - ProtobufTypes::MessagePtr default_config; - if (config_source.has_default_config()) { - default_config = - getDefaultConfig(config_source.default_config(), filter_config_name, factory_context, - last_filter_in_filter_chain, filter_chain_type, require_type_urls); - } - - auto provider = std::make_unique( - subscription, require_type_urls, factory_context, std::move(default_config), - last_filter_in_filter_chain, filter_chain_type, - [this, stat_prefix, - &factory_context](const Protobuf::Message& message) -> Envoy::Http::FilterFactoryCb { - return instantiateFilterFactory(message, stat_prefix, factory_context); - }); - - // Ensure the subscription starts if it has not already. - if (config_source.apply_default_config_without_warming()) { - factory_context.initManager().add(provider->initTarget()); - } - applyLastOrDefaultConfig(subscription, *provider, filter_config_name); - return provider; +std::tuple +HttpFilterConfigProviderManagerImpl::getMessage( + const envoy::config::core::v3::TypedExtensionConfig& filter_config, + Server::Configuration::FactoryContext& factory_context) const { + auto& factory = + Config::Utility::getAndCheckFactory( + filter_config); + ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( + filter_config.typed_config(), + factory_context.messageValidationContext().dynamicValidationVisitor(), factory); + bool is_terminal_filter = factory.isTerminalFilterByProto(*message, factory_context); + return {std::move(message), factory.name(), is_terminal_filter}; } ProtobufTypes::MessagePtr HttpFilterConfigProviderManagerImpl::getDefaultConfig( diff --git a/source/common/filter/config_discovery_impl.h b/source/common/filter/config_discovery_impl.h index 4183ffe41fbb..3d708adaa75a 100644 --- a/source/common/filter/config_discovery_impl.h +++ b/source/common/filter/config_discovery_impl.h @@ -62,16 +62,17 @@ class DynamicFilterConfigProviderImplBase : public Config::DynamicExtensionConfi /** * Implementation of a filter config provider using discovery subscriptions. **/ +template class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBase, - public DynamicFilterConfigProvider { + public DynamicFilterConfigProvider { public: - DynamicFilterConfigProviderImpl( - FilterConfigSubscriptionSharedPtr& subscription, - const absl::flat_hash_set& require_type_urls, - Server::Configuration::FactoryContext& factory_context, - ProtobufTypes::MessagePtr&& default_config, bool last_filter_in_filter_chain, - const std::string& filter_chain_type, - std::function factory_cb_fn) + DynamicFilterConfigProviderImpl(FilterConfigSubscriptionSharedPtr& subscription, + const absl::flat_hash_set& require_type_urls, + Server::Configuration::FactoryContext& factory_context, + ProtobufTypes::MessagePtr&& default_config, + bool last_filter_in_filter_chain, + const std::string& filter_chain_type, + std::function factory_cb_fn) : DynamicFilterConfigProviderImplBase(subscription, require_type_urls, last_filter_in_filter_chain, filter_chain_type), default_configuration_(std::move(default_config)), tls_(factory_context.threadLocal()), @@ -81,12 +82,12 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBa // Config::ExtensionConfigProvider const std::string& name() override { return DynamicFilterConfigProviderImplBase::name(); } - absl::optional config() override { return tls_->config_; } + absl::optional config() override { return tls_->config_; } // Config::DynamicExtensionConfigProviderBase void onConfigUpdate(const Protobuf::Message& message, const std::string&, Config::ConfigAppliedCb cb) override { - const Envoy::Http::FilterFactoryCb config = factory_cb_fn_(message); + const FactoryCb config = factory_cb_fn_(message); tls_.runOnAllThreads( [config, cb](OptRef tls) { tls->config_ = config; @@ -102,7 +103,7 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBa } void onConfigRemoved(Config::ConfigAppliedCb applied_on_all_threads) override { - const absl::optional default_config = + const absl::optional default_config = default_configuration_ ? absl::make_optional(factory_cb_fn_(*default_configuration_)) : absl::nullopt; tls_.runOnAllThreads( @@ -126,15 +127,15 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBa private: struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { ThreadLocalConfig() : config_{absl::nullopt} {} - absl::optional config_{}; + absl::optional config_{}; }; // Currently applied configuration to ensure that the main thread deletes the last reference to // it. - absl::optional current_config_{absl::nullopt}; + absl::optional current_config_{absl::nullopt}; const ProtobufTypes::MessagePtr default_configuration_; ThreadLocal::TypedSlot tls_; - const std::function factory_cb_fn_; + const std::function factory_cb_fn_; }; /** @@ -199,7 +200,6 @@ class FilterConfigSubscription std::string last_filter_name_; bool last_filter_is_terminal_; Server::Configuration::FactoryContext& factory_context_; - ProtobufMessage::ValidationVisitor& validator_; Init::SharedTargetImpl init_target_; bool started_{false}; @@ -222,18 +222,18 @@ class FilterConfigSubscription /** * Provider implementation of a static filter config. **/ -class StaticFilterConfigProviderImpl : public FilterConfigProvider { +template +class StaticFilterConfigProviderImpl : public FilterConfigProvider { public: - StaticFilterConfigProviderImpl(const Envoy::Http::FilterFactoryCb& config, - const std::string filter_config_name) + StaticFilterConfigProviderImpl(const FactoryCb& config, const std::string filter_config_name) : config_(config), filter_config_name_(filter_config_name) {} // Config::ExtensionConfigProvider const std::string& name() override { return filter_config_name_; } - absl::optional config() override { return config_; } + absl::optional config() override { return config_; } private: - Envoy::Http::FilterFactoryCb config_; + FactoryCb config_; const std::string filter_config_name_; }; @@ -241,6 +241,13 @@ class StaticFilterConfigProviderImpl : public FilterConfigProvider { * Base class for a FilterConfigProviderManager. */ class FilterConfigProviderManagerImplBase : Logger::Loggable { +public: + virtual ~FilterConfigProviderManagerImplBase() = default; + + virtual std::tuple + getMessage(const envoy::config::core::v3::TypedExtensionConfig& filter_config, + Server::Configuration::FactoryContext& factory_context) const PURE; + protected: std::shared_ptr getSubscription(const envoy::config::core::v3::ConfigSource& config_source, @@ -258,20 +265,56 @@ class FilterConfigProviderManagerImplBase : Logger::Loggable /** * An implementation of FilterConfigProviderManager. */ +template class FilterConfigProviderManagerImpl : public FilterConfigProviderManagerImplBase, - public FilterConfigProviderManager, + public FilterConfigProviderManager, public Singleton::Instance { public: - DynamicFilterConfigProviderPtr createDynamicFilterConfigProvider( + DynamicFilterConfigProviderPtr 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, bool last_filter_in_filter_chain, - const std::string& filter_chain_type) override; + const std::string& filter_chain_type) override { + 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. + // Otherwise, mark ready immediately and start the subscription on initialization. A default + // config is expected in the latter case. + if (!config_source.apply_default_config_without_warming()) { + factory_context.initManager().add(subscription->initTarget()); + } + absl::flat_hash_set require_type_urls; + for (const auto& type_url : config_source.type_urls()) { + auto factory_type_url = TypeUtil::typeUrlToDescriptorFullName(type_url); + require_type_urls.emplace(factory_type_url); + } + + ProtobufTypes::MessagePtr default_config; + if (config_source.has_default_config()) { + default_config = + getDefaultConfig(config_source.default_config(), filter_config_name, factory_context, + last_filter_in_filter_chain, filter_chain_type, require_type_urls); + } - FilterConfigProviderPtr - createStaticFilterConfigProvider(const Envoy::Http::FilterFactoryCb& config, + auto provider = std::make_unique>( + subscription, require_type_urls, factory_context, std::move(default_config), + last_filter_in_filter_chain, filter_chain_type, + [this, stat_prefix, &factory_context](const Protobuf::Message& message) -> FactoryCb { + return instantiateFilterFactory(message, stat_prefix, factory_context); + }); + + // Ensure the subscription starts if it has not already. + if (config_source.apply_default_config_without_warming()) { + factory_context.initManager().add(provider->initTarget()); + } + applyLastOrDefaultConfig(subscription, *provider, filter_config_name); + return provider; + } + + FilterConfigProviderPtr + createStaticFilterConfigProvider(const FactoryCb& config, const std::string& filter_config_name) override { - return std::make_unique(config, filter_config_name); + return std::make_unique>(config, filter_config_name); } protected: @@ -281,12 +324,18 @@ class FilterConfigProviderManagerImpl : public FilterConfigProviderManagerImplBa bool last_filter_in_filter_chain, const std::string& filter_chain_type, const absl::flat_hash_set& require_type_urls) const PURE; - virtual Http::FilterFactoryCb + virtual FactoryCb instantiateFilterFactory(const Protobuf::Message& message, const std::string& stat_prefix, Server::Configuration::FactoryContext& factory_context) const PURE; }; -class HttpFilterConfigProviderManagerImpl : public FilterConfigProviderManagerImpl { +class HttpFilterConfigProviderManagerImpl + : public FilterConfigProviderManagerImpl { +public: + std::tuple + getMessage(const envoy::config::core::v3::TypedExtensionConfig& filter_config, + Server::Configuration::FactoryContext& factory_context) const override; + protected: ProtobufTypes::MessagePtr getDefaultConfig(const ProtobufWkt::Any& proto_config, const std::string& filter_config_name, diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index e480599fefd9..3464659a14c0 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -39,7 +39,7 @@ namespace Extensions { namespace NetworkFilters { namespace HttpConnectionManager { -using FilterConfigProviderManager = Filter::FilterConfigProviderManager; +using FilterConfigProviderManager = Filter::FilterConfigProviderManager; /** * Config registration for the HTTP connection manager filter. @see NamedNetworkFilterConfigFactory. @@ -125,7 +125,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, // Http::FilterChainFactory void createFilterChain(Http::FilterChainFactoryCallbacks& callbacks) override; - using FilterFactoriesList = std::list; + using FilterFactoriesList = std::list>; struct FilterConfig { std::unique_ptr filter_factories; bool allow_upgrade; diff --git a/test/common/filter/config_discovery_impl_test.cc b/test/common/filter/config_discovery_impl_test.cc index 7eebb2b237a0..4db6a0010866 100644 --- a/test/common/filter/config_discovery_impl_test.cc +++ b/test/common/filter/config_discovery_impl_test.cc @@ -76,9 +76,9 @@ class FilterConfigDiscoveryImplTest : public FilterConfigDiscoveryTestBase { } ~FilterConfigDiscoveryImplTest() override { factory_context_.thread_local_.shutdownThread(); } - DynamicFilterConfigProviderPtr createProvider(std::string name, bool warm, - bool default_configuration, - bool last_filter_config = true) { + DynamicFilterConfigProviderPtr + createProvider(std::string name, bool warm, bool default_configuration, + bool last_filter_config = true) { EXPECT_CALL(init_manager_, add(_)); envoy::config::core::v3::ExtensionConfigSource config_source; @@ -121,8 +121,9 @@ config_source: { ads: {} } init_manager_.initialize(init_watcher_); } - std::unique_ptr filter_config_provider_manager_; - DynamicFilterConfigProviderPtr provider_; + std::unique_ptr> + filter_config_provider_manager_; + DynamicFilterConfigProviderPtr provider_; Config::SubscriptionCallbacks* callbacks_{}; };