diff --git a/source/common/config/config_provider_impl.cc b/source/common/config/config_provider_impl.cc index ed209e8427ad..11cbf993e51c 100644 --- a/source/common/config/config_provider_impl.cc +++ b/source/common/config/config_provider_impl.cc @@ -23,24 +23,6 @@ ConfigSubscriptionCommonBase::~ConfigSubscriptionCommonBase() { init_target_.ready(); config_provider_manager_.unbindSubscription(manager_identifier_); } - -void ConfigSubscriptionCommonBase::bindConfigProvider(MutableConfigProviderCommonBase* provider) { - // All config providers bound to a ConfigSubscriptionCommonBase must be of the same concrete - // type; this is assumed by ConfigSubscriptionInstance::checkAndApplyConfigUpdate() and is - // verified by the assertion below. NOTE: an inlined statement ASSERT() triggers a potentially - // evaluated expression warning from clang due to `typeid(**mutable_config_providers_.begin())`. - // To avoid this, we use a lambda to separate the first mutable provider dereference from the - // typeid() statement. - ASSERT([&]() { - if (!mutable_config_providers_.empty()) { - const auto& first_provider = **mutable_config_providers_.begin(); - return typeid(*provider) == typeid(first_provider); - } - return true; - }()); - mutable_config_providers_.insert(provider); -} - bool ConfigSubscriptionInstance::checkAndApplyConfigUpdate(const Protobuf::Message& config_proto, const std::string& config_name, const std::string& version_info) { @@ -55,49 +37,12 @@ bool ConfigSubscriptionInstance::checkAndApplyConfigUpdate(const Protobuf::Messa config_info_ = {new_hash, version_info}; ENVOY_LOG(debug, "{}: loading new configuration: config_name={} hash={}", name_, config_name, new_hash); - - ASSERT(!mutable_config_providers_.empty()); - ConfigProvider::ConfigConstSharedPtr new_config; - for (auto* provider : mutable_config_providers_) { - // All bound mutable config providers must be of the same type (see the ASSERT... in - // bindConfigProvider()). - // This makes it safe to call any of the provider's onConfigProtoUpdate() to get a new config - // impl, which can then be passed to all providers. - auto* typed_provider = static_cast(provider); - if (new_config == nullptr) { - if ((new_config = typed_provider->onConfigProtoUpdate(config_proto)) == nullptr) { - return false; - } - } - typed_provider->onConfigUpdate(new_config); - } - + ConfigProvider::ConfigConstSharedPtr new_config_impl = onConfigProtoUpdate(config_proto); + applyConfigUpdate([new_config_impl](ConfigProvider::ConfigConstSharedPtr) + -> ConfigProvider::ConfigConstSharedPtr { return new_config_impl; }); return true; } -void DeltaConfigSubscriptionInstance::applyDeltaConfigUpdate( - const std::function& update_fn) { - // The Config implementation is assumed to be shared across the config providers bound to this - // subscription, therefore, simply propagating the update to all worker threads for a single bound - // provider will be sufficient. - if (mutable_config_providers_.size() > 1) { - ASSERT(static_cast(*mutable_config_providers_.begin()) - ->getConfig() == static_cast( - *std::next(mutable_config_providers_.begin())) - ->getConfig()); - } - - // TODO(AndresGuedez): currently, the caller has to compute the differences in resources between - // DS API config updates and passes a granular update_fn() that adds/modifies/removes resources as - // needed. Such logic could be generalized as part of this framework such that this function owns - // the diffing and issues the corresponding call to add/modify/remove a resource according to a - // vector of functions passed by the caller. - auto* typed_provider = - static_cast(getAnyBoundMutableConfigProvider()); - ConfigSharedPtr config = typed_provider->getConfig(); - typed_provider->onConfigUpdate([config, update_fn]() { update_fn(config); }); -} - ConfigProviderManagerImplBase::ConfigProviderManagerImplBase(Server::Admin& admin, const std::string& config_name) { config_tracker_entry_ = diff --git a/source/common/config/config_provider_impl.h b/source/common/config/config_provider_impl.h index 2553b3976e59..a1a7b02d71b7 100644 --- a/source/common/config/config_provider_impl.h +++ b/source/common/config/config_provider_impl.h @@ -20,11 +20,11 @@ namespace Envoy { namespace Config { // This file provides a set of base classes, (ImmutableConfigProviderBase, -// MutableConfigProviderCommonBase, MutableConfigProviderBase, DeltaMutableConfigProviderBase, -// ConfigProviderManagerImplBase, ConfigSubscriptionCommonBase, ConfigSubscriptionInstance, -// DeltaConfigSubscriptionInstance), conforming to the ConfigProvider/ConfigProviderManager -// interfaces, which in tandem provide a framework for implementing statically defined (i.e., -// immutable) and dynamic (mutable via subscriptions) configuration for Envoy. +// MutableConfigProviderCommonBase, ConfigProviderManagerImplBase, ConfigSubscriptionCommonBase, +// ConfigSubscriptionInstance, DeltaConfigSubscriptionInstance), conforming to the +// ConfigProvider/ConfigProviderManager interfaces, which in tandem provide a framework for +// implementing statically defined (i.e., immutable) and dynamic (mutable via subscriptions) +// configuration for Envoy. // // The mutability property applies to the ConfigProvider itself and _not_ the underlying config // proto, which is always immutable. MutableConfigProviderCommonBase objects receive config proto @@ -58,11 +58,12 @@ namespace Config { // interface. // // For mutable (xDS) providers: -// 1) According to the API type, create a class derived from MutableConfigProviderBase or -// DeltaMutableConfigProviderBase and implement the required interface. -// 2) According to the API type, create a class derived from ConfigSubscriptionInstance or -// DeltaConfigSubscriptionInstance; this is the entity responsible for owning and managing the -// Envoy::Config::Subscription that provides the underlying config subscription. +// 1) According to the API type, create a class derived from MutableConfigProviderCommonBase and +// implement the required interface. +// 2) According to the API type, create a class derived from +// ConfigSubscriptionInstance or DeltaConfigSubscriptionInstance; this is the entity responsible +// for owning and managing the Envoy::Config::Subscription that provides the +// underlying config subscription, and the Config implemention shared by associated providers. // a) For a ConfigProvider::ApiType::Full subscription instance (i.e., a // ConfigSubscriptionInstance child): // - When subscription callbacks (onConfigUpdate, onConfigUpdateFailed) are issued by the @@ -78,8 +79,8 @@ namespace Config { // - When subscription callbacks (onConfigUpdate, onConfigUpdateFailed) are issued by the // underlying subscription, the corresponding ConfigSubscriptionInstance functions must be called // as well. -// - On a successful config update, applyConfigUpdate() should be called to propagate the config -// updates to all bound config providers and worker threads. +// - On a successful config update, applyConfigUpdate() should be called to propagate the +// config updates to all bound config providers and worker threads. class ConfigProviderManagerImplBase; @@ -130,12 +131,13 @@ class ImmutableConfigProviderBase : public ConfigProvider { class MutableConfigProviderCommonBase; /** - * Provides common DS API subscription functionality required by the ConfigProvider::ApiType - * specific base classes (see ConfigSubscriptionInstance and DeltaConfigSubscriptionInstance). + * Provides common DS API subscription functionality required by the ConfigProvider::ApiType. * - * To do so, this class keeps track of a set of MutableConfigProviderCommonBase instances associated - * with an underlying subscription; providers are bound/unbound as needed as they are created and - * destroyed. + * This class can not be instantiated directly; instead, it provides the foundation for + * config subscription implementations which derive from it. + * + * A subscription is intended to be co-owned by config providers with the same config source, it's + * designed to be created/destructed on admin thread only. * * xDS config providers and subscriptions are split to avoid lifetime issues with arguments * required by the config providers. An example is the Server::Configuration::FactoryContext, which @@ -143,11 +145,17 @@ class MutableConfigProviderCommonBase; * in use (see #3960). This split enables single ownership of the config providers, while enabling * shared ownership of the underlying subscription. * - * This class can not be instantiated directly; instead, it provides the foundation for - * config subscription implementations which derive from it. */ -class ConfigSubscriptionCommonBase : protected Logger::Loggable { +class ConfigSubscriptionCommonBase + : protected Logger::Loggable, + public std::enable_shared_from_this { public: + // Callback for updating a Config implementation held in each worker thread, the callback is + // called in applyConfigUpdate() with the current version Config, and is expected to return the + // new version Config. + using ConfigUpdateCb = + std::function; + struct LastConfigInfo { absl::optional last_config_hash_; std::string last_config_version_; @@ -166,6 +174,10 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggable& configInfo() const { return config_info_; } + ConfigProvider::ConfigConstSharedPtr getConfig() const { + return tls_->getTyped().config_; + } + /** * Must be called by derived classes when the onConfigUpdate() callback associated with the * underlying subscription is issued. @@ -184,25 +196,49 @@ class ConfigSubscriptionCommonBase : protected Logger::LoggablerunOnAllThreads( + [this, update_fn]() { + tls_->getTyped().config_ = update_fn(this->getConfig()); + }, + // During the update propagation, a subscription may get teared down in main thread due to + // all owners/providers destructed in a xDS update (e.g. LDS demolishes a + // RouteConfigProvider and its subscription). + // If such a race condition happens, holding a reference to the "*this" subscription + // instance in this cb will ensure the shared "*this" gets posted back to main thread, after + // all the workers finish calling the update_fn, at which point it's safe to destruct + // "*this" instance. + [shared_this, complete_cb]() { complete_cb(); }); } void setLastUpdated() { last_updated_ = time_source_.systemTime(); } @@ -212,16 +248,12 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggable mutable_config_providers_; absl::optional config_info_; + // This slot holds a Config implementation in each thread, which is intended to be shared between + // config providers from the same config source. + ThreadLocal::SlotPtr tls_; private: - void bindConfigProvider(MutableConfigProviderCommonBase* provider); - - void unbindConfigProvider(MutableConfigProviderCommonBase* provider) { - mutable_config_providers_.erase(provider); - } - Init::TargetImpl init_target_; const uint64_t manager_identifier_; ConfigProviderManagerImplBase& config_provider_manager_; @@ -235,28 +267,34 @@ class ConfigSubscriptionCommonBase : protected Logger::Loggables and // instead centralizing lifetime management in the ConfigProviderManagerImplBase with explicit // reference counting would be more maintainable. - friend class MutableConfigProviderCommonBase; - friend class MutableConfigProviderBase; - friend class DeltaMutableConfigProviderBase; friend class ConfigProviderManagerImplBase; - friend class MockMutableConfigProviderBase; }; using ConfigSubscriptionCommonBaseSharedPtr = std::shared_ptr; /** * Provides common subscription functionality required by ConfigProvider::ApiType::Full DS APIs. + * A single Config instance is shared across all providers and all workers associated with this + * subscription. */ class ConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { -protected: +public: ConfigSubscriptionInstance(const std::string& name, const uint64_t manager_identifier, ConfigProviderManagerImplBase& config_provider_manager, - TimeSource& time_source, const SystemTime& last_updated, - const LocalInfo::LocalInfo& local_info) - : ConfigSubscriptionCommonBase(name, manager_identifier, config_provider_manager, time_source, - last_updated, local_info) {} + Server::Configuration::FactoryContext& factory_context) + : ConfigSubscriptionCommonBase(name, manager_identifier, config_provider_manager, + factory_context) {} - ~ConfigSubscriptionInstance() override = default; + /** + * Must be called by the derived class' constructor. + * @param initial_config supplies an initial Envoy::Config::ConfigProvider::Config associated with + * the underlying subscription, shared across all providers and workers. + */ + void initialize(const ConfigProvider::ConfigConstSharedPtr& initial_config) { + tls_->set([initial_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { + return std::make_shared(initial_config); + }); + } /** * Determines whether a configuration proto is a new update, and if so, propagates it to all @@ -268,170 +306,66 @@ class ConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { */ bool checkAndApplyConfigUpdate(const Protobuf::Message& config_proto, const std::string& config_name, const std::string& version_info); -}; -using ConfigSharedPtr = std::shared_ptr; +protected: + /** + * Called when a new config proto is received via an xDS subscription. + * On successful validation of the config, must return a shared_ptr to a ConfigProvider::Config + * implementation that will be propagated to all mutable config providers sharing the + * subscription. + * Note that this function is called _once_ across all shared config providers per xDS + * subscription config update. + * @param config_proto supplies the configuration proto. + * @return ConfigConstSharedPtr the ConfigProvider::Config to share with other providers. + */ + virtual ConfigProvider::ConfigConstSharedPtr + onConfigProtoUpdate(const Protobuf::Message& config_proto) PURE; +}; /** * Provides common subscription functionality required by ConfigProvider::ApiType::Delta DS APIs. */ class DeltaConfigSubscriptionInstance : public ConfigSubscriptionCommonBase { protected: - DeltaConfigSubscriptionInstance(const std::string& name, const uint64_t manager_identifier, - ConfigProviderManagerImplBase& config_provider_manager, - TimeSource& time_source, const SystemTime& last_updated, - const LocalInfo::LocalInfo& local_info) - : ConfigSubscriptionCommonBase(name, manager_identifier, config_provider_manager, time_source, - last_updated, local_info) {} - - ~DeltaConfigSubscriptionInstance() override = default; + using ConfigSubscriptionCommonBase::ConfigSubscriptionCommonBase; /** - * Propagates a config update to the config providers and worker threads associated with the - * subscription. - * - * @param update_fn the callback to run on each worker thread. + * Must be called by the derived class' constructor. + * @param init_cb supplies an initial Envoy::Config::ConfigProvider::Config associated with the + * underlying subscription for each worker thread. */ - void applyDeltaConfigUpdate(const std::function& update_fn); + void initialize(const std::function& init_cb) { + tls_->set([init_cb](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { + return std::make_shared(init_cb()); + }); + } }; /** * Provides generic functionality required by the ConfigProvider::ApiType specific dynamic config - * providers (see MutableConfigProviderBase and DeltaMutableConfigProviderBase). + * providers. * * This class can not be instantiated directly; instead, it provides the foundation for * dynamic config provider implementations which derive from it. */ class MutableConfigProviderCommonBase : public ConfigProvider { public: - ~MutableConfigProviderCommonBase() override { subscription_->unbindConfigProvider(this); } - // Envoy::Config::ConfigProvider SystemTime lastUpdated() const override { return subscription_->lastUpdated(); } ApiType apiType() const override { return api_type_; } protected: MutableConfigProviderCommonBase(ConfigSubscriptionCommonBaseSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, ApiType api_type) - : tls_(factory_context.threadLocal().allocateSlot()), subscription_(subscription), - api_type_(api_type) {} - - ThreadLocal::SlotPtr tls_; - ConfigSubscriptionCommonBaseSharedPtr subscription_; - -private: - ApiType api_type_; -}; + : subscription_(subscription), api_type_(api_type) {} -/** - * Provides common mutable (dynamic) config provider functionality required by - * ConfigProvider::ApiType::Full DS APIs. - */ -class MutableConfigProviderBase : public MutableConfigProviderCommonBase { -public: // Envoy::Config::ConfigProvider - // NOTE: This is being promoted to public for internal uses to avoid an unnecessary dynamic_cast - // in the public API (ConfigProvider::config()). - ConfigConstSharedPtr getConfig() const override { - return tls_->getTyped().config_; - } - - /** - * Called when a new config proto is received via an xDS subscription. - * On successful validation of the config, must return a shared_ptr to a ConfigProvider::Config - * implementation that will be propagated to all mutable config providers sharing the - * subscription. - * Note that this function is called _once_ across all shared config providers per xDS - * subscription config update. - * @param config_proto supplies the configuration proto. - * @return ConfigConstSharedPtr the ConfigProvider::Config to share with other providers. - */ - virtual ConfigConstSharedPtr onConfigProtoUpdate(const Protobuf::Message& config_proto) PURE; - - /** - * Must be called by the derived class' constructor. - * @param initial_config supplies an initial Envoy::Config::ConfigProvider::Config associated with - * the underlying subscription. - */ - void initialize(const ConfigConstSharedPtr& initial_config) { - subscription_->bindConfigProvider(this); - tls_->set([initial_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared(initial_config); - }); - } - - /** - * Propagates a newly instantiated Envoy::Config::ConfigProvider::Config to all workers. - * @param config supplies the newly instantiated config. - */ - void onConfigUpdate(const ConfigConstSharedPtr& config) { - if (getConfig() == config) { - return; - } - tls_->runOnAllThreads( - [this, config]() -> void { tls_->getTyped().config_ = config; }); - } - -protected: - MutableConfigProviderBase(ConfigSubscriptionCommonBaseSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - ApiType api_type) - : MutableConfigProviderCommonBase(std::move(subscription), factory_context, api_type) {} + ConfigConstSharedPtr getConfig() const override { return subscription_->getConfig(); } - ~MutableConfigProviderBase() override = default; + ConfigSubscriptionCommonBaseSharedPtr subscription_; private: - struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { - ThreadLocalConfig(ConfigProvider::ConfigConstSharedPtr initial_config) - : config_(std::move(initial_config)) {} - - ConfigProvider::ConfigConstSharedPtr config_; - }; -}; - -/** - * Provides common mutable (dynamic) config provider functionality required by - * ConfigProvider::ApiType::Delta DS APIs. - */ -class DeltaMutableConfigProviderBase : public MutableConfigProviderCommonBase { -public: - // Envoy::Config::ConfigProvider - // This promotes getConfig() to public so that internal uses can avoid an unnecessary dynamic_cast - // in the public API (ConfigProvider::config()). - ConfigConstSharedPtr getConfig() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } - - /** - * Non-const overload for use within the framework. - * @return ConfigSharedPtr the config implementation associated with the provider. - */ - virtual ConfigSharedPtr getConfig() PURE; - - /** - * Propagates a delta config update to all workers. - * @param updateCb the callback to run on each worker. - */ - void onConfigUpdate(Envoy::Event::PostCb update_cb) { - tls_->runOnAllThreads(std::move(update_cb)); - } - -protected: - DeltaMutableConfigProviderBase(ConfigSubscriptionCommonBaseSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - ApiType api_type) - : MutableConfigProviderCommonBase(std::move(subscription), factory_context, api_type) {} - - ~DeltaMutableConfigProviderBase() override = default; - - /** - * Must be called by the derived class' constructor. - * @param initializeCb supplies the initialization callback to be issued for each worker - * thread. - */ - void initialize(ThreadLocal::Slot::InitializeCb initializeCb) { - subscription_->bindConfigProvider(this); - tls_->set(std::move(initializeCb)); - } + ApiType api_type_; }; /** @@ -454,8 +388,6 @@ class DeltaMutableConfigProviderBase : public MutableConfigProviderCommonBase { */ class ConfigProviderManagerImplBase : public ConfigProviderManager, public Singleton::Instance { public: - ~ConfigProviderManagerImplBase() override = default; - /** * This is invoked by the /config_dump admin handler. * @return ProtobufTypes::MessagePtr the config dump proto corresponding to the associated diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 6e07d093018a..31d354477d5e 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -175,6 +175,7 @@ envoy_cc_library( hdrs = ["scoped_rds.h"], deps = [ ":scoped_config_lib", + "//include/envoy/config:config_provider_interface", "//include/envoy/config:subscription_interface", "//include/envoy/stats:stats_interface", "//source/common/common:assert_lib", diff --git a/source/common/router/scoped_config_impl.cc b/source/common/router/scoped_config_impl.cc index ee3ce1318568..f5c8007f9e74 100644 --- a/source/common/router/scoped_config_impl.cc +++ b/source/common/router/scoped_config_impl.cc @@ -104,12 +104,11 @@ ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const { return std::make_unique(std::move(key)); } -void ThreadLocalScopedConfigImpl::addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr&) {} +void ScopedConfigImpl::addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr&) {} -void ThreadLocalScopedConfigImpl::removeRoutingScope(const std::string&) {} +void ScopedConfigImpl::removeRoutingScope(const std::string&) {} -Router::ConfigConstSharedPtr -ThreadLocalScopedConfigImpl::getRouteConfig(const Http::HeaderMap&) const { +Router::ConfigConstSharedPtr ScopedConfigImpl::getRouteConfig(const Http::HeaderMap&) const { return std::make_shared(); } diff --git a/source/common/router/scoped_config_impl.h b/source/common/router/scoped_config_impl.h index 808b442838c4..184929f94664 100644 --- a/source/common/router/scoped_config_impl.h +++ b/source/common/router/scoped_config_impl.h @@ -141,9 +141,9 @@ class ScopeKeyBuilderImpl : public ScopeKeyBuilderBase { * ConnectionManagerImpl::refreshCachedRoute() will call getRouterConfig() to obtain the * Router::ConfigConstSharedPtr to use for route selection. */ -class ThreadLocalScopedConfigImpl : public ScopedConfig, public ThreadLocal::ThreadLocalObject { +class ScopedConfigImpl : public ScopedConfig { public: - ThreadLocalScopedConfigImpl(ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) + ScopedConfigImpl(ScopedRoutes::ScopeKeyBuilder&& scope_key_builder) : scope_key_builder_(std::move(scope_key_builder)) {} void addOrUpdateRoutingScope(const ScopedRouteInfoConstSharedPtr& scoped_route_info); diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc index 86e1d1dc88b8..e30ea4296b7c 100644 --- a/source/common/router/scoped_rds.cc +++ b/source/common/router/scoped_rds.cc @@ -68,7 +68,7 @@ InlineScopedRoutesConfigProvider::InlineScopedRoutesConfigProvider( ConfigProviderInstanceType::Inline, ConfigProvider::ApiType::Delta), name_(std::move(name)), - config_(std::make_shared(std::move(scope_key_builder))), + config_(std::make_shared(std::move(scope_key_builder))), config_protos_(std::make_move_iterator(config_protos.begin()), std::make_move_iterator(config_protos.end())), rds_config_source_(std::move(rds_config_source)) {} @@ -76,12 +76,13 @@ InlineScopedRoutesConfigProvider::InlineScopedRoutesConfigProvider( ScopedRdsConfigSubscription::ScopedRdsConfigSubscription( const envoy::config::filter::network::http_connection_manager::v2::ScopedRds& scoped_rds, const uint64_t manager_identifier, const std::string& name, + const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes:: + ScopeKeyBuilder& scope_key_builder, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, ScopedRoutesConfigProviderManager& config_provider_manager) - : DeltaConfigSubscriptionInstance( - "SRDS", manager_identifier, config_provider_manager, factory_context.timeSource(), - factory_context.timeSource().systemTime(), factory_context.localInfo()), - name_(name), + : DeltaConfigSubscriptionInstance("SRDS", manager_identifier, config_provider_manager, + factory_context), + name_(name), scope_key_builder_(scope_key_builder), scope_(factory_context.scope().createScope(stat_prefix + "scoped_rds." + name + ".")), stats_({ALL_SCOPED_RDS_STATS(POOL_COUNTER(*scope_))}), validation_visitor_(factory_context.messageValidationVisitor()) { @@ -91,6 +92,12 @@ ScopedRdsConfigSubscription::ScopedRdsConfigSubscription( Grpc::Common::typeUrl( envoy::api::v2::ScopedRouteConfiguration().GetDescriptor()->full_name()), *scope_, *this); + + initialize([scope_key_builder]() -> Envoy::Config::ConfigProvider::ConfigConstSharedPtr { + return std::make_shared( + envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder( + scope_key_builder)); + }); } void ScopedRdsConfigSubscription::onConfigUpdate( @@ -124,10 +131,12 @@ void ScopedRdsConfigSubscription::onConfigUpdate( ScopedRouteInfoConstSharedPtr scoped_route_info = scoped_config_manager_.addOrUpdateRoutingScope(scoped_route, version_info); ENVOY_LOG(debug, "srds: add/update scoped_route '{}'", scoped_route_name); - applyDeltaConfigUpdate([scoped_route_info](const ConfigProvider::ConfigConstSharedPtr& config) { - auto* thread_local_scoped_config = const_cast( - static_cast(config.get())); + applyConfigUpdate([scoped_route_info](const ConfigProvider::ConfigConstSharedPtr& config) + -> ConfigProvider::ConfigConstSharedPtr { + auto* thread_local_scoped_config = + const_cast(static_cast(config.get())); thread_local_scoped_config->addOrUpdateRoutingScope(scoped_route_info); + return config; }); } @@ -135,35 +144,28 @@ void ScopedRdsConfigSubscription::onConfigUpdate( const std::string scoped_route_name = scoped_route.first; ENVOY_LOG(debug, "srds: remove scoped route '{}'", scoped_route_name); scoped_config_manager_.removeRoutingScope(scoped_route_name); - applyDeltaConfigUpdate([scoped_route_name](const ConfigProvider::ConfigConstSharedPtr& config) { - auto* thread_local_scoped_config = const_cast( - static_cast(config.get())); + applyConfigUpdate([scoped_route_name](const ConfigProvider::ConfigConstSharedPtr& config) + -> ConfigProvider::ConfigConstSharedPtr { + // In place update. + auto* thread_local_scoped_config = + const_cast(static_cast(config.get())); thread_local_scoped_config->removeRoutingScope(scoped_route_name); + return config; }); } - ConfigSubscriptionCommonBase::onConfigUpdate(); + DeltaConfigSubscriptionInstance::onConfigUpdate(); setLastConfigInfo(absl::optional({absl::nullopt, version_info})); stats_.config_reload_.inc(); } ScopedRdsConfigProvider::ScopedRdsConfigProvider( ScopedRdsConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - envoy::api::v2::core::ConfigSource rds_config_source, - const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes:: - ScopeKeyBuilder& scope_key_builder) - : DeltaMutableConfigProviderBase(std::move(subscription), factory_context, - ConfigProvider::ApiType::Delta), + envoy::api::v2::core::ConfigSource rds_config_source) + : MutableConfigProviderCommonBase(std::move(subscription), ConfigProvider::ApiType::Delta), subscription_(static_cast( MutableConfigProviderCommonBase::subscription_.get())), - rds_config_source_(std::move(rds_config_source)) { - initialize([scope_key_builder](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return std::make_shared( - envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder( - scope_key_builder)); - }); -} + rds_config_source_(std::move(rds_config_source)) {} ProtobufTypes::MessagePtr ScopedRoutesConfigProviderManager::dumpConfigs() const { auto config_dump = std::make_unique(); @@ -207,28 +209,25 @@ ConfigProviderPtr ScopedRoutesConfigProviderManager::createXdsConfigProvider( const Protobuf::Message& config_source_proto, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, const ConfigProviderManager::OptionalArg& optarg) { + const auto& typed_optarg = static_cast(optarg); ScopedRdsConfigSubscriptionSharedPtr subscription = ConfigProviderManagerImplBase::getSubscription( config_source_proto, factory_context.initManager(), [&config_source_proto, &factory_context, &stat_prefix, - &optarg](const uint64_t manager_identifier, - ConfigProviderManagerImplBase& config_provider_manager) + &typed_optarg](const uint64_t manager_identifier, + ConfigProviderManagerImplBase& config_provider_manager) -> Envoy::Config::ConfigSubscriptionCommonBaseSharedPtr { const auto& scoped_rds_config_source = dynamic_cast< const envoy::config::filter::network::http_connection_manager::v2::ScopedRds&>( config_source_proto); return std::make_shared( - scoped_rds_config_source, manager_identifier, - static_cast(optarg) - .scoped_routes_name_, - factory_context, stat_prefix, + scoped_rds_config_source, manager_identifier, typed_optarg.scoped_routes_name_, + typed_optarg.scope_key_builder_, factory_context, stat_prefix, static_cast(config_provider_manager)); }); - const auto& typed_optarg = static_cast(optarg); - return std::make_unique(std::move(subscription), factory_context, - typed_optarg.rds_config_source_, - typed_optarg.scope_key_builder_); + return std::make_unique(std::move(subscription), + typed_optarg.rds_config_source_); } ConfigProviderPtr ScopedRoutesConfigProviderManager::createStaticConfigProvider( diff --git a/source/common/router/scoped_rds.h b/source/common/router/scoped_rds.h index f0cc72f71c15..725c3ec755ea 100644 --- a/source/common/router/scoped_rds.h +++ b/source/common/router/scoped_rds.h @@ -86,6 +86,8 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio ScopedRdsConfigSubscription( const envoy::config::filter::network::http_connection_manager::v2::ScopedRds& scoped_rds, const uint64_t manager_identifier, const std::string& name, + const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes:: + ScopeKeyBuilder& scope_key_builder, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, ScopedRoutesConfigProviderManager& config_provider_manager); @@ -98,7 +100,7 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio } private: - // Envoy::Config::ConfigSubscriptionCommonBase + // Envoy::Config::DeltaConfigSubscriptionInstance void start() override { subscription_->start({}); } // Envoy::Config::SubscriptionCallbacks @@ -109,7 +111,7 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } void onConfigUpdateFailed(const EnvoyException*) override { - ConfigSubscriptionCommonBase::onConfigUpdateFailed(); + DeltaConfigSubscriptionInstance::onConfigUpdateFailed(); } std::string resourceName(const ProtobufWkt::Any& resource) override { return MessageUtil::anyConvert(resource, @@ -119,6 +121,8 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio const std::string name_; std::unique_ptr subscription_; + const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder + scope_key_builder_; Stats::ScopePtr scope_; ScopedRdsStats stats_; ScopedConfigManager scoped_config_manager_; @@ -129,25 +133,13 @@ using ScopedRdsConfigSubscriptionSharedPtr = std::shared_ptr(tls_->get()); - } - private: ScopedRdsConfigSubscription* subscription_; const envoy::api::v2::core::ConfigSource rds_config_source_; diff --git a/test/common/config/config_provider_impl_test.cc b/test/common/config/config_provider_impl_test.cc index 2b3e320a7a62..020d6f5260d8 100644 --- a/test/common/config/config_provider_impl_test.cc +++ b/test/common/config/config_provider_impl_test.cc @@ -4,7 +4,6 @@ #include "common/protobuf/utility.h" #include "test/common/config/dummy_config.pb.h" -#include "test/mocks/config/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" @@ -20,6 +19,22 @@ using testing::InSequence; class DummyConfigProviderManager; +class DummyConfig : public Envoy::Config::ConfigProvider::Config { +public: + DummyConfig() = default; + explicit DummyConfig(const test::common::config::DummyConfig& config_proto) { + protos_.push_back(config_proto); + } + void addProto(const test::common::config::DummyConfig& config_proto) { + protos_.push_back(config_proto); + } + + uint32_t numProtos() const { return protos_.size(); } + +private: + std::vector protos_; +}; + class StaticDummyConfigProvider : public ImmutableConfigProviderBase { public: StaticDummyConfigProvider(const test::common::config::DummyConfig& config_proto, @@ -48,12 +63,18 @@ class DummyConfigSubscription : public ConfigSubscriptionInstance, DummyConfigSubscription(const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, DummyConfigProviderManager& config_provider_manager); - ~DummyConfigSubscription() override = default; // Envoy::Config::ConfigSubscriptionCommonBase void start() override {} + // Envoy::Config::ConfigSubscriptionInstance + ConfigProvider::ConfigConstSharedPtr + onConfigProtoUpdate(const Protobuf::Message& config_proto) override { + return std::make_shared( + static_cast(config_proto)); + } + // Envoy::Config::SubscriptionCallbacks void onConfigUpdate(const Protobuf::RepeatedPtrField& resources, const std::string& version_info) override { @@ -84,33 +105,17 @@ class DummyConfigSubscription : public ConfigSubscriptionInstance, }; using DummyConfigSubscriptionSharedPtr = std::shared_ptr; -class DummyConfig : public ConfigProvider::Config { +class DummyDynamicConfigProvider : public MutableConfigProviderCommonBase { public: - DummyConfig(const test::common::config::DummyConfig&) {} -}; - -class DummyDynamicConfigProvider : public MutableConfigProviderBase { -public: - DummyDynamicConfigProvider(DummyConfigSubscriptionSharedPtr&& subscription, - const ConfigConstSharedPtr& initial_config, - Server::Configuration::FactoryContext& factory_context) - : MutableConfigProviderBase(std::move(subscription), factory_context, ApiType::Full), + explicit DummyDynamicConfigProvider(DummyConfigSubscriptionSharedPtr&& subscription) + : MutableConfigProviderCommonBase(std::move(subscription), ApiType::Full), subscription_(static_cast( - MutableConfigProviderCommonBase::subscription_.get())) { - initialize(initial_config); - } + MutableConfigProviderCommonBase::subscription_.get())) {} ~DummyDynamicConfigProvider() override = default; DummyConfigSubscription& subscription() { return *subscription_; } - // Envoy::Config::MutableConfigProviderBase - ConfigProvider::ConfigConstSharedPtr - onConfigProtoUpdate(const Protobuf::Message& config) override { - return std::make_shared( - static_cast(config)); - } - // Envoy::Config::ConfigProvider const Protobuf::Message* getConfigProto() const override { if (!subscription_->config_proto().has_value()) { @@ -127,7 +132,7 @@ class DummyDynamicConfigProvider : public MutableConfigProviderBase { class DummyConfigProviderManager : public ConfigProviderManagerImplBase { public: - DummyConfigProviderManager(Server::Admin& admin) + explicit DummyConfigProviderManager(Server::Admin& admin) : ConfigProviderManagerImplBase(admin, "dummy") {} ~DummyConfigProviderManager() override = default; @@ -177,14 +182,7 @@ class DummyConfigProviderManager : public ConfigProviderManagerImplBase { static_cast(config_provider_manager)); }); - ConfigProvider::ConfigConstSharedPtr initial_config; - const auto* provider = static_cast( - subscription->getAnyBoundMutableConfigProvider()); - if (provider) { - initial_config = provider->getConfig(); - } - return std::make_unique(std::move(subscription), initial_config, - factory_context); + return std::make_unique(std::move(subscription)); } // Envoy::Config::ConfigProviderManager @@ -204,6 +202,15 @@ class DummyConfigProviderManager : public ConfigProviderManagerImplBase { } }; +DummyConfigSubscription::DummyConfigSubscription( + const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, + DummyConfigProviderManager& config_provider_manager) + : ConfigSubscriptionInstance("DummyDS", manager_identifier, config_provider_manager, + factory_context) { + // A nullptr is shared as the initial value. + initialize(nullptr); +} + StaticDummyConfigProvider::StaticDummyConfigProvider( const test::common::config::DummyConfig& config_proto, Server::Configuration::FactoryContext& factory_context, @@ -212,13 +219,6 @@ StaticDummyConfigProvider::StaticDummyConfigProvider( ConfigProviderInstanceType::Static, ApiType::Full), config_(std::make_shared(config_proto)), config_proto_(config_proto) {} -DummyConfigSubscription::DummyConfigSubscription( - const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, - DummyConfigProviderManager& config_provider_manager) - : ConfigSubscriptionInstance( - "DummyDS", manager_identifier, config_provider_manager, factory_context.timeSource(), - factory_context.timeSource().systemTime(), factory_context.localInfo()) {} - class ConfigProviderImplTest : public testing::Test { public: void initialize() { @@ -318,7 +318,7 @@ TEST_F(ConfigProviderImplTest, SharedOwnership) { .size()); } -// A ConfigProviderManager that returns a mock ConfigProvider. +// A ConfigProviderManager that returns a dummy ConfigProvider. class DummyConfigProviderManagerMockConfigProvider : public DummyConfigProviderManager { public: DummyConfigProviderManagerMockConfigProvider(Server::Admin& admin) @@ -338,15 +338,14 @@ class DummyConfigProviderManagerMockConfigProvider : public DummyConfigProviderM manager_identifier, factory_context, static_cast(config_provider_manager)); }); - return std::make_unique(std::move(subscription), nullptr, - factory_context); + return std::make_unique(std::move(subscription)); } }; // Test that duplicate config updates will not trigger creation of a new ConfigProvider::Config. TEST_F(ConfigProviderImplTest, DuplicateConfigProto) { InSequence sequence; - // This provider manager returns a MockMutableConfigProviderBase. + // This provider manager returns a DummyDynamicConfigProvider. auto provider_manager = std::make_unique(factory_context_.admin_); envoy::api::v2::core::ApiConfigSource config_source_proto; @@ -354,18 +353,21 @@ TEST_F(ConfigProviderImplTest, DuplicateConfigProto) { ConfigProviderPtr provider = provider_manager->createXdsConfigProvider( config_source_proto, factory_context_, "dummy_prefix", ConfigProviderManager::NullOptionalArg()); - auto* typed_provider = static_cast(provider.get()); - DummyConfigSubscription& subscription = - static_cast(typed_provider->subscription()); + auto* typed_provider = static_cast(provider.get()); + auto& subscription = static_cast(typed_provider->subscription()); + EXPECT_EQ(subscription.getConfig(), nullptr); // First time issuing a configUpdate(). A new ConfigProvider::Config should be created. - EXPECT_CALL(*typed_provider, onConfigProtoUpdate(_)).Times(1); Protobuf::RepeatedPtrField untyped_dummy_configs; untyped_dummy_configs.Add()->PackFrom(parseDummyConfigFromYaml("a: a dynamic dummy config")); subscription.onConfigUpdate(untyped_dummy_configs, "1"); + EXPECT_NE(subscription.getConfig(), nullptr); + auto config_ptr = subscription.getConfig(); + EXPECT_EQ(typed_provider->config().get(), config_ptr.get()); // Second time issuing the configUpdate(), this time with a duplicate proto. A new // ConfigProvider::Config _should not_ be created. - EXPECT_CALL(*typed_provider, onConfigProtoUpdate(_)).Times(0); - subscription.onConfigUpdate(untyped_dummy_configs, "1"); + subscription.onConfigUpdate(untyped_dummy_configs, "2"); + EXPECT_EQ(config_ptr, subscription.getConfig()); + EXPECT_EQ(typed_provider->config().get(), config_ptr.get()); } // An empty config provider tests on base class' constructor. @@ -518,7 +520,31 @@ class DeltaDummyConfigSubscription : public DeltaConfigSubscriptionInstance, // Envoy::Config::SubscriptionCallbacks void onConfigUpdate(const Protobuf::RepeatedPtrField& resources, - const std::string& version_info) override; + const std::string& version_info) override { + if (resources.empty()) { + return; + } + + // For simplicity, there is no logic here to track updates and/or removals to the existing + // config proto set (i.e., this is append only). Real xDS APIs will need to track additions, + // updates and removals to the config set and apply the diffs to the underlying config + // implementations. + for (const auto& resource_any : resources) { + auto dummy_config = TestUtility::anyConvert(resource_any); + proto_map_[version_info] = dummy_config; + // Propagate the new config proto to all worker threads. + applyConfigUpdate([&dummy_config](ConfigProvider::ConfigConstSharedPtr prev_config) + -> ConfigProvider::ConfigConstSharedPtr { + auto* config = const_cast(static_cast(prev_config.get())); + // Per above, append only for now. + config->addProto(dummy_config); + return prev_config; + }); + } + + ConfigSubscriptionCommonBase::onConfigUpdate(); + setLastConfigInfo(absl::optional({absl::nullopt, version_info})); + } void onConfigUpdate(const Protobuf::RepeatedPtrField&, const Protobuf::RepeatedPtrField&, const std::string&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; @@ -537,32 +563,12 @@ class DeltaDummyConfigSubscription : public DeltaConfigSubscriptionInstance, }; using DeltaDummyConfigSubscriptionSharedPtr = std::shared_ptr; -class ThreadLocalDummyConfig : public ThreadLocal::ThreadLocalObject, - public Envoy::Config::ConfigProvider::Config { +class DeltaDummyDynamicConfigProvider : public Envoy::Config::MutableConfigProviderCommonBase { public: - void addProto(const test::common::config::DummyConfig& config_proto) { - protos_.push_back(config_proto); - } - - uint32_t numProtos() const { return protos_.size(); } - -private: - std::vector protos_; -}; - -class DeltaDummyDynamicConfigProvider : public Envoy::Config::DeltaMutableConfigProviderBase { -public: - DeltaDummyDynamicConfigProvider(DeltaDummyConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::FactoryContext& factory_context, - std::shared_ptr dummy_config) - : DeltaMutableConfigProviderBase(std::move(subscription), factory_context, - ConfigProvider::ApiType::Delta), + DeltaDummyDynamicConfigProvider(DeltaDummyConfigSubscriptionSharedPtr&& subscription) + : MutableConfigProviderCommonBase(std::move(subscription), ConfigProvider::ApiType::Delta), subscription_(static_cast( - MutableConfigProviderCommonBase::subscription_.get())) { - initialize([&dummy_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { - return (dummy_config != nullptr) ? dummy_config : std::make_shared(); - }); - } + MutableConfigProviderCommonBase::subscription_.get())) {} DeltaDummyConfigSubscription& subscription() { return *subscription_; } @@ -574,23 +580,12 @@ class DeltaDummyDynamicConfigProvider : public Envoy::Config::DeltaMutableConfig } return proto_vector; } + std::string getConfigVersion() const override { return (subscription_->configInfo().has_value()) ? subscription_->configInfo().value().last_config_version_ : ""; } - ConfigConstSharedPtr getConfig() const override { - return std::dynamic_pointer_cast(tls_->get()); - } - - // Envoy::Config::DeltaMutableConfigProviderBase - ConfigSharedPtr getConfig() override { - return std::dynamic_pointer_cast(tls_->get()); - } - - std::shared_ptr getThreadLocalDummyConfig() { - return std::dynamic_pointer_cast(tls_->get()); - } private: DeltaDummyConfigSubscription* subscription_; @@ -642,44 +637,17 @@ class DeltaDummyConfigProviderManager : public ConfigProviderManagerImplBase { static_cast(config_provider_manager)); }); - auto* existing_provider = static_cast( - subscription->getAnyBoundMutableConfigProvider()); - return std::make_unique( - std::move(subscription), factory_context, - (existing_provider != nullptr) ? existing_provider->getThreadLocalDummyConfig() : nullptr); + return std::make_unique(std::move(subscription)); } }; DeltaDummyConfigSubscription::DeltaDummyConfigSubscription( const uint64_t manager_identifier, Server::Configuration::FactoryContext& factory_context, DeltaDummyConfigProviderManager& config_provider_manager) - : DeltaConfigSubscriptionInstance( - "Dummy", manager_identifier, config_provider_manager, factory_context.timeSource(), - factory_context.timeSource().systemTime(), factory_context.localInfo()) {} - -void DeltaDummyConfigSubscription::onConfigUpdate( - const Protobuf::RepeatedPtrField& resources, - const std::string& version_info) { - if (resources.empty()) { - return; - } - - // For simplicity, there is no logic here to track updates and/or removals to the existing config - // proto set (i.e., this is append only). Real xDS APIs will need to track additions, updates and - // removals to the config set and apply the diffs to the underlying config implementations. - for (const auto& resource_any : resources) { - auto dummy_config = TestUtility::anyConvert(resource_any); - proto_map_[version_info] = dummy_config; - // Propagate the new config proto to all worker threads. - applyDeltaConfigUpdate([&dummy_config](const ConfigSharedPtr& config) { - auto* thread_local_dummy_config = static_cast(config.get()); - // Per above, append only for now. - thread_local_dummy_config->addProto(dummy_config); - }); - } - - ConfigSubscriptionCommonBase::onConfigUpdate(); - setLastConfigInfo(absl::optional({absl::nullopt, version_info})); + : DeltaConfigSubscriptionInstance("Dummy", manager_identifier, config_provider_manager, + factory_context) { + initialize( + []() -> ConfigProvider::ConfigConstSharedPtr { return std::make_shared(); }); } class DeltaConfigProviderImplTest : public testing::Test { @@ -721,7 +689,7 @@ TEST_F(DeltaConfigProviderImplTest, MultipleDeltaSubscriptions) { config_source_proto, factory_context_, "dummy_prefix", ConfigProviderManager::NullOptionalArg()); - // Providers, config implementations (i.e., the ThreadLocalDummyConfig) and config protos are + // Providers, config implementations (i.e., the DummyConfig) and config protos are // expected to be shared for a given subscription. EXPECT_EQ(&dynamic_cast(*provider1).subscription(), &dynamic_cast(*provider2).subscription()); @@ -729,17 +697,17 @@ TEST_F(DeltaConfigProviderImplTest, MultipleDeltaSubscriptions) { EXPECT_EQ( provider1->configProtoInfoVector().value().config_protos_, provider2->configProtoInfoVector().value().config_protos_); - EXPECT_EQ(provider1->config().get(), - provider2->config().get()); + EXPECT_EQ(provider1->config().get(), + provider2->config().get()); // Validate that the config protos are propagated to the thread local config implementation. - EXPECT_EQ(provider1->config()->numProtos(), 2); + EXPECT_EQ(provider1->config()->numProtos(), 2); // Issue a second config update to validate that having multiple providers bound to the // subscription causes a single update to the underlying shared config implementation. subscription.onConfigUpdate(untyped_dummy_configs, "2"); // NOTE: the config implementation is append only and _does not_ track updates/removals to the // config proto set, so the expectation is to double the size of the set. - EXPECT_EQ(provider1->config()->numProtos(), 4); + EXPECT_EQ(provider1->config()->numProtos(), 4); EXPECT_EQ(provider1->configProtoInfoVector().value().version_, "2"); } diff --git a/test/mocks/config/mocks.cc b/test/mocks/config/mocks.cc index c5bee0ccb920..4a3e3099e0c1 100644 --- a/test/mocks/config/mocks.cc +++ b/test/mocks/config/mocks.cc @@ -47,12 +47,5 @@ MockGrpcMuxCallbacks::MockGrpcMuxCallbacks() { MockGrpcMuxCallbacks::~MockGrpcMuxCallbacks() = default; -MockMutableConfigProviderBase::MockMutableConfigProviderBase( - std::shared_ptr&& subscription, - ConfigProvider::ConfigConstSharedPtr, Server::Configuration::FactoryContext& factory_context) - : MutableConfigProviderBase(std::move(subscription), factory_context, ApiType::Full) { - subscription_->bindConfigProvider(this); -} - } // namespace Config } // namespace Envoy diff --git a/test/mocks/config/mocks.h b/test/mocks/config/mocks.h index 8ced0b8a96a5..ee7c9291782b 100644 --- a/test/mocks/config/mocks.h +++ b/test/mocks/config/mocks.h @@ -109,20 +109,6 @@ class MockGrpcStreamCallbacks : public GrpcStreamCallbacks&& subscription, - ConfigProvider::ConfigConstSharedPtr initial_config, - Server::Configuration::FactoryContext& factory_context); - - MOCK_CONST_METHOD0(getConfig, ConfigConstSharedPtr()); - MOCK_METHOD1(onConfigProtoUpdate, ConfigConstSharedPtr(const Protobuf::Message& config_proto)); - MOCK_METHOD1(initialize, void(const ConfigConstSharedPtr& initial_config)); - MOCK_METHOD1(onConfigUpdate, void(const ConfigConstSharedPtr& config)); - - ConfigSubscriptionCommonBase& subscription() { return *subscription_.get(); } -}; - class MockConfigProviderManager : public ConfigProviderManager { public: MockConfigProviderManager() = default;