Skip to content
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

[xds] refactor config provider framework #7704

Merged
merged 29 commits into from
Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6a3f13b
add scope key-builder impl and test
stevenzzzz Jun 11, 2019
cc806d7
Merge branch 'master' into add-key-builder
stevenzzzz Jun 11, 2019
bb55a44
fix typo
stevenzzzz Jun 11, 2019
8d7b4da
move impl code from header to cc file.
stevenzzzz Jun 12, 2019
8bcddce
add review fixes and unit test case for keybuidler
stevenzzzz Jun 12, 2019
b1d0d5c
clang-tidy fix
stevenzzzz Jun 12, 2019
1007ee0
use expect_debug_death for assertion test
stevenzzzz Jun 12, 2019
184ff2f
fix failed test in opt mode
stevenzzzz Jun 12, 2019
fe6b643
add assert around addFragment and test, and a few review fix
stevenzzzz Jun 13, 2019
fc98e56
Merge branch 'master' into add-key-builder
stevenzzzz Jun 19, 2019
951bd28
Merge branch 'master' into add-key-builder
stevenzzzz Jun 20, 2019
75718d9
fix based on feedbacks
stevenzzzz Jun 21, 2019
d84839d
fix nits
stevenzzzz Jun 25, 2019
27ff0a3
switch from constructing proto memeber by value(copy-elision) to more…
stevenzzzz Jun 25, 2019
467a6a1
refactor config provider framework
stevenzzzz Jul 24, 2019
7dea1a0
some renames and stale comment fix
stevenzzzz Jul 24, 2019
2b5f572
Merge branch 'master' of https://github.com/envoyproxy/envoy into add…
stevenzzzz Jul 25, 2019
86c455e
fixes for review feedbacks
stevenzzzz Jul 30, 2019
60dd433
fix comment
stevenzzzz Jul 30, 2019
c31de28
Merge branch 'master' of https://github.com/envoyproxy/envoy into CLEAN
stevenzzzz Jul 30, 2019
dad2d59
snowp comment, merge with upstream master
stevenzzzz Jul 30, 2019
6b6a0ad
Merge branch 'master' into config-provider-update
stevenzzzz Jul 30, 2019
fb28731
fix tidy format error
stevenzzzz Jul 31, 2019
1bd43be
fixes per htuch review feedbacks
stevenzzzz Jul 31, 2019
f074e9d
improve the comment per htuch's suggestion.
stevenzzzz Jul 31, 2019
7cbb6ae
fix comment nit
stevenzzzz Jul 31, 2019
fb7867b
move updateConfigCb and add a description for it.
stevenzzzz Jul 31, 2019
47a417d
Merge branch 'master' of https://github.com/envoyproxy/envoy
stevenzzzz Aug 1, 2019
e328d46
Merge branch 'master' into config-provider-update
stevenzzzz Aug 1, 2019
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
61 changes: 3 additions & 58 deletions source/common/config/config_provider_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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<MutableConfigProviderBase*>(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<void(const ConfigSharedPtr&)>& 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<DeltaMutableConfigProviderBase*>(*mutable_config_providers_.begin())
->getConfig() == static_cast<DeltaMutableConfigProviderBase*>(
*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<DeltaMutableConfigProviderBase*>(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_ =
Expand Down
292 changes: 111 additions & 181 deletions source/common/config/config_provider_impl.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions source/common/router/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 3 additions & 4 deletions source/common/router/scoped_config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,11 @@ ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const {
return std::make_unique<ScopeKey>(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<const NullConfigImpl>();
}

Expand Down
4 changes: 2 additions & 2 deletions source/common/router/scoped_config_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
69 changes: 34 additions & 35 deletions source/common/router/scoped_rds.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,21 @@ InlineScopedRoutesConfigProvider::InlineScopedRoutesConfigProvider(
ConfigProviderInstanceType::Inline,
ConfigProvider::ApiType::Delta),
name_(std::move(name)),
config_(std::make_shared<ThreadLocalScopedConfigImpl>(std::move(scope_key_builder))),
config_(std::make_shared<ScopedConfigImpl>(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)) {}

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()) {
Expand All @@ -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<ScopedConfigImpl>(
envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder(
scope_key_builder));
});
}

void ScopedRdsConfigSubscription::onConfigUpdate(
Expand Down Expand Up @@ -124,46 +131,41 @@ 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<ThreadLocalScopedConfigImpl*>(
static_cast<const ThreadLocalScopedConfigImpl*>(config.get()));
applyConfigUpdate([scoped_route_info](const ConfigProvider::ConfigConstSharedPtr& config)
-> ConfigProvider::ConfigConstSharedPtr {
auto* thread_local_scoped_config =
const_cast<ScopedConfigImpl*>(static_cast<const ScopedConfigImpl*>(config.get()));
thread_local_scoped_config->addOrUpdateRoutingScope(scoped_route_info);
return config;
});
}

for (const auto& scoped_route : scoped_routes_to_remove) {
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<ThreadLocalScopedConfigImpl*>(
static_cast<const ThreadLocalScopedConfigImpl*>(config.get()));
applyConfigUpdate([scoped_route_name](const ConfigProvider::ConfigConstSharedPtr& config)
-> ConfigProvider::ConfigConstSharedPtr {
// In place update.
auto* thread_local_scoped_config =
const_cast<ScopedConfigImpl*>(static_cast<const ScopedConfigImpl*>(config.get()));
thread_local_scoped_config->removeRoutingScope(scoped_route_name);
return config;
});
}

ConfigSubscriptionCommonBase::onConfigUpdate();
DeltaConfigSubscriptionInstance::onConfigUpdate();
setLastConfigInfo(absl::optional<LastConfigInfo>({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<ScopedRdsConfigSubscription*>(
MutableConfigProviderCommonBase::subscription_.get())),
rds_config_source_(std::move(rds_config_source)) {
initialize([scope_key_builder](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr {
return std::make_shared<ThreadLocalScopedConfigImpl>(
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<envoy::admin::v2alpha::ScopedRoutesConfigDump>();
Expand Down Expand Up @@ -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<const ScopedRoutesConfigProviderManagerOptArg&>(optarg);
ScopedRdsConfigSubscriptionSharedPtr subscription =
ConfigProviderManagerImplBase::getSubscription<ScopedRdsConfigSubscription>(
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<ScopedRdsConfigSubscription>(
scoped_rds_config_source, manager_identifier,
static_cast<const ScopedRoutesConfigProviderManagerOptArg&>(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<ScopedRoutesConfigProviderManager&>(config_provider_manager));
});

const auto& typed_optarg = static_cast<const ScopedRoutesConfigProviderManagerOptArg&>(optarg);
return std::make_unique<ScopedRdsConfigProvider>(std::move(subscription), factory_context,
typed_optarg.rds_config_source_,
typed_optarg.scope_key_builder_);
return std::make_unique<ScopedRdsConfigProvider>(std::move(subscription),
typed_optarg.rds_config_source_);
}

ConfigProviderPtr ScopedRoutesConfigProviderManager::createStaticConfigProvider(
Expand Down
24 changes: 8 additions & 16 deletions source/common/router/scoped_rds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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
Expand All @@ -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<envoy::api::v2::ScopedRouteConfiguration>(resource,
Expand All @@ -119,6 +121,8 @@ class ScopedRdsConfigSubscription : public Envoy::Config::DeltaConfigSubscriptio

const std::string name_;
std::unique_ptr<Envoy::Config::Subscription> subscription_;
const envoy::config::filter::network::http_connection_manager::v2::ScopedRoutes::ScopeKeyBuilder
scope_key_builder_;
Stats::ScopePtr scope_;
ScopedRdsStats stats_;
ScopedConfigManager scoped_config_manager_;
Expand All @@ -129,25 +133,13 @@ using ScopedRdsConfigSubscriptionSharedPtr = std::shared_ptr<ScopedRdsConfigSubs

// A ConfigProvider for scoped RDS that dynamically fetches scoped routing configuration via a
// subscription.
class ScopedRdsConfigProvider : public Envoy::Config::DeltaMutableConfigProviderBase {
class ScopedRdsConfigProvider : public Envoy::Config::MutableConfigProviderCommonBase {
public:
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);
envoy::api::v2::core::ConfigSource rds_config_source);

ScopedRdsConfigSubscription& subscription() { return *subscription_; }

// getConfig() is overloaded (const/non-const only). Make all base getConfig()s visible to avoid
// compiler warnings.
using DeltaMutableConfigProviderBase::getConfig;

// Envoy::Config::DeltaMutableConfigProviderBase
Envoy::Config::ConfigSharedPtr getConfig() override {
return std::dynamic_pointer_cast<Envoy::Config::ConfigProvider::Config>(tls_->get());
}

private:
ScopedRdsConfigSubscription* subscription_;
const envoy::api::v2::core::ConfigSource rds_config_source_;
Expand Down
Loading