From 74480703e9f898918e0f1109923529749204c4f5 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Mon, 9 Aug 2021 18:55:10 +0800 Subject: [PATCH 01/31] Adding xDS RDS support for thrift protocol. The implementation is mostly copy form source/common/router/ minus the unnecessary parts. Unfortunatly no common base classes to share code. Signed-off-by: Tamas Kovacs --- .../thrift_proxy/v3/thrift_proxy.proto | 12 +- .../thrift_proxy/v4alpha/thrift_proxy.proto | 15 +- .../thrift_proxy/v3/thrift_proxy.proto | 11 +- .../filters/network/thrift_proxy/BUILD | 1 + .../filters/network/thrift_proxy/config.cc | 27 +- .../filters/network/thrift_proxy/config.h | 2 + .../filters/network/thrift_proxy/router/BUILD | 41 ++ .../network/thrift_proxy/router/config.h | 21 + .../filters/network/thrift_proxy/router/rds.h | 64 ++ .../network/thrift_proxy/router/rds_impl.cc | 278 +++++++++ .../network/thrift_proxy/router/rds_impl.h | 223 +++++++ .../router/route_config_provider_manager.h | 70 +++ .../router/route_config_update_receiver.h | 84 +++ .../route_config_update_receiver_impl.cc | 42 ++ .../route_config_update_receiver_impl.h | 61 ++ .../filters/network/thrift_proxy/BUILD | 16 + .../network/thrift_proxy/config_test.cc | 1 + .../network/thrift_proxy/rds_impl_test.cc | 583 ++++++++++++++++++ 18 files changed, 1545 insertions(+), 7 deletions(-) create mode 100644 source/extensions/filters/network/thrift_proxy/router/rds.h create mode 100644 source/extensions/filters/network/thrift_proxy/router/rds_impl.cc create mode 100644 source/extensions/filters/network/thrift_proxy/router/rds_impl.h create mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h create mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h create mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc create mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h create mode 100644 test/extensions/filters/network/thrift_proxy/rds_impl_test.cc diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index 4916330ec5f3a..829636097da9a 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.extensions.filters.network.thrift_proxy.v3; +import "envoy/config/core/v3/config_source.proto"; import "envoy/extensions/filters/network/thrift_proxy/v3/route.proto"; import "google/protobuf/any.proto"; @@ -58,7 +59,7 @@ enum ProtocolType { TWITTER = 4; } -// [#next-free-field: 8] +// [#next-free-field: 9] message ThriftProxy { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.thrift_proxy.v2alpha1.ThriftProxy"; @@ -92,6 +93,9 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; + + // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. + Rds rds = 8; } // ThriftFilter configures a Thrift filter. @@ -138,3 +142,9 @@ message ThriftProtocolOptions { // which is the default, causes the proxy to use the same protocol as the downstream connection. ProtocolType protocol = 2 [(validate.rules).enum = {defined_only: true}]; } + +message Rds { + config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + + string route_config_name = 2; +} diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto index de399582869a0..ccc681061b222 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.extensions.filters.network.thrift_proxy.v4alpha; +import "envoy/config/core/v4alpha/config_source.proto"; import "envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto"; import "google/protobuf/any.proto"; @@ -58,7 +59,7 @@ enum ProtocolType { TWITTER = 4; } -// [#next-free-field: 8] +// [#next-free-field: 9] message ThriftProxy { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.network.thrift_proxy.v3.ThriftProxy"; @@ -92,6 +93,9 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; + + // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. + Rds rds = 8; } // ThriftFilter configures a Thrift filter. @@ -138,3 +142,12 @@ message ThriftProtocolOptions { // which is the default, causes the proxy to use the same protocol as the downstream connection. ProtocolType protocol = 2 [(validate.rules).enum = {defined_only: true}]; } + +message Rds { + option (udpa.annotations.versioning).previous_message_type = + "envoy.extensions.filters.network.thrift_proxy.v3.Rds"; + + config.core.v4alpha.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + + string route_config_name = 2; +} diff --git a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index a03251a2ee3b0..45215985eaf65 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package envoy.extensions.filters.network.thrift_proxy.v3; import "envoy/extensions/filters/network/thrift_proxy/v3/route.proto"; +import "envoy/config/core/v3/config_source.proto"; import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; @@ -60,7 +61,7 @@ enum ProtocolType { TWITTER = 4; } -// [#next-free-field: 8] +// [#next-free-field: 9] message ThriftProxy { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.thrift_proxy.v2alpha1.ThriftProxy"; @@ -94,6 +95,9 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; + + // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. + Rds rds = 8; } // ThriftFilter configures a Thrift filter. @@ -139,3 +143,8 @@ message ThriftProtocolOptions { // which is the default, causes the proxy to use the same protocol as the downstream connection. ProtocolType protocol = 2 [(validate.rules).enum = {defined_only: true}]; } + +message Rds { + config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + string route_config_name = 2; +} diff --git a/source/extensions/filters/network/thrift_proxy/BUILD b/source/extensions/filters/network/thrift_proxy/BUILD index 8b6e66a083881..e7bb08b9c72e7 100644 --- a/source/extensions/filters/network/thrift_proxy/BUILD +++ b/source/extensions/filters/network/thrift_proxy/BUILD @@ -55,6 +55,7 @@ envoy_cc_extension( "//source/extensions/filters/network:well_known_names", "//source/extensions/filters/network/common:factory_base_lib", "//source/extensions/filters/network/thrift_proxy/filters:filter_config_interface", + "//source/extensions/filters/network/thrift_proxy/router:rds_lib", "//source/extensions/filters/network/thrift_proxy/router:router_lib", "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", ], diff --git a/source/extensions/filters/network/thrift_proxy/config.cc b/source/extensions/filters/network/thrift_proxy/config.cc index bd0cf021f079e..eaff39ef51f2f 100644 --- a/source/extensions/filters/network/thrift_proxy/config.cc +++ b/source/extensions/filters/network/thrift_proxy/config.cc @@ -16,6 +16,7 @@ #include "source/extensions/filters/network/thrift_proxy/decoder.h" #include "source/extensions/filters/network/thrift_proxy/filters/filter_config.h" #include "source/extensions/filters/network/thrift_proxy/framed_transport_impl.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" #include "source/extensions/filters/network/thrift_proxy/stats.h" #include "source/extensions/filters/network/thrift_proxy/unframed_transport_impl.h" @@ -96,12 +97,22 @@ ProtocolType ProtocolOptionsConfigImpl::protocol(ProtocolType downstream_protoco return (protocol_ == ProtocolType::Auto) ? downstream_protocol : protocol_; } +SINGLETON_MANAGER_REGISTRATION(thrift_route_config_provider_manager); + Network::FilterFactoryCb ThriftProxyFilterConfigFactory::createFilterFactoryFromProtoTyped( const envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy& proto_config, Server::Configuration::FactoryContext& context) { - std::shared_ptr filter_config(new ConfigImpl(proto_config, context)); + std::shared_ptr route_config_provider_manager = + context.singletonManager().getTyped( + SINGLETON_MANAGER_REGISTERED_NAME(thrift_route_config_provider_manager), [&context] { + return std::make_shared(context.admin()); + }); + + std::shared_ptr filter_config( + new ConfigImpl(proto_config, context, *route_config_provider_manager)); - return [filter_config, &context](Network::FilterManager& filter_manager) -> void { + return [route_config_provider_manager, filter_config, + &context](Network::FilterManager& filter_manager) -> void { filter_manager.addReadFilter(std::make_shared( *filter_config, context.api().randomGenerator(), context.dispatcher().timeSource())); }; @@ -115,11 +126,11 @@ REGISTER_FACTORY(ThriftProxyFilterConfigFactory, ConfigImpl::ConfigImpl( const envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy& config, - Server::Configuration::FactoryContext& context) + Server::Configuration::FactoryContext& context, + Router::RouteConfigProviderManager& route_config_provider_manager) : context_(context), stats_prefix_(fmt::format("thrift.{}.", config.stat_prefix())), stats_(ThriftFilterStats::generateStats(stats_prefix_, context_.scope())), transport_(lookupTransport(config.transport())), proto_(lookupProtocol(config.protocol())), - route_matcher_(new Router::RouteMatcher(config.route_config())), payload_passthrough_(config.payload_passthrough()), max_requests_per_connection_(config.max_requests_per_connection().value()) { @@ -134,6 +145,14 @@ ConfigImpl::ConfigImpl( processFilter(filter); } } + + if (config.has_rds()) { + route_config_provider_ = route_config_provider_manager.createRdsRouteConfigProvider( + config.rds(), context_.getServerFactoryContext(), stats_prefix_, context_.initManager()); + } else { + route_config_provider_ = route_config_provider_manager.createStaticRouteConfigProvider( + config.route_config(), context_.getServerFactoryContext()); + } } void ConfigImpl::createFilterChain(ThriftFilters::FilterChainFactoryCallbacks& callbacks) { diff --git a/source/extensions/filters/network/thrift_proxy/config.h b/source/extensions/filters/network/thrift_proxy/config.h index 1eea3cc9e6c8f..65f4dafba84fa 100644 --- a/source/extensions/filters/network/thrift_proxy/config.h +++ b/source/extensions/filters/network/thrift_proxy/config.h @@ -10,6 +10,8 @@ #include "source/extensions/filters/network/thrift_proxy/conn_manager.h" #include "source/extensions/filters/network/thrift_proxy/filters/filter.h" #include "source/extensions/filters/network/thrift_proxy/protocol_options_config.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds.h" +#include "source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h" #include "source/extensions/filters/network/thrift_proxy/router/router_impl.h" #include "source/extensions/filters/network/well_known_names.h" diff --git a/source/extensions/filters/network/thrift_proxy/router/BUILD b/source/extensions/filters/network/thrift_proxy/router/BUILD index 7809f34af81b2..02499bbfc23f2 100644 --- a/source/extensions/filters/network/thrift_proxy/router/BUILD +++ b/source/extensions/filters/network/thrift_proxy/router/BUILD @@ -103,3 +103,44 @@ envoy_cc_library( "@envoy_api//envoy/config/route/v3:pkg_cc_proto", ], ) + +envoy_cc_library( + name = "rds_interface", + hdrs = ["rds.h"], + deps = [ + ":router_interface", + "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", + ], +) + +envoy_cc_library( + name = "rds_lib", + srcs = [ + "rds_impl.cc", + "route_config_update_receiver_impl.cc", + ], + hdrs = [ + "rds_impl.h", + "route_config_provider_manager.h", + "route_config_update_receiver.h", + "route_config_update_receiver_impl.h", + ], + deps = [ + ":config", + ":rds_interface", + "//envoy/common:time_interface", + "//envoy/config:subscription_interface", + "//envoy/local_info:local_info_interface", + "//source/common/config:api_version_lib", + "//source/common/config:subscription_base_interface", + "//source/common/config:utility_lib", + "//source/common/init:manager_lib", + "//source/common/init:target_lib", + "//source/common/protobuf:utility_lib", + "@envoy_api//envoy/admin/v3:pkg_cc_proto", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + "@envoy_api//envoy/config/route/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", + "@envoy_api//envoy/service/discovery/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/filters/network/thrift_proxy/router/config.h b/source/extensions/filters/network/thrift_proxy/router/config.h index 9441e2cb0c647..be55c08b7e4db 100644 --- a/source/extensions/filters/network/thrift_proxy/router/config.h +++ b/source/extensions/filters/network/thrift_proxy/router/config.h @@ -4,6 +4,7 @@ #include "envoy/extensions/filters/network/thrift_proxy/router/v3/router.pb.validate.h" #include "source/extensions/filters/network/thrift_proxy/filters/factory_base.h" +#include "source/extensions/filters/network/thrift_proxy/router/router_impl.h" namespace Envoy { namespace Extensions { @@ -23,6 +24,26 @@ class RouterFilterConfig const std::string& stat_prefix, Server::Configuration::FactoryContext& context) override; }; +class ConfigImpl : public Config, Logger::Loggable { +public: + ConfigImpl( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config) + : route_matcher_(new RouteMatcher(config)) {} + + // Config + RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const override { + return route_matcher_->route(metadata, random_value); + } + +private: + std::unique_ptr route_matcher_; +}; + +class NullConfigImpl : public Config { +public: + RouteConstSharedPtr route(const MessageMetadata&, uint64_t) const override { return nullptr; } +}; + } // namespace Router } // namespace ThriftProxy } // namespace NetworkFilters diff --git a/source/extensions/filters/network/thrift_proxy/router/rds.h b/source/extensions/filters/network/thrift_proxy/router/rds.h new file mode 100644 index 0000000000000..b76b003cb2aab --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/rds.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" + +#include "source/extensions/filters/network/thrift_proxy/router/router.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { + +/** + * A provider for constant route configurations. + */ +class RouteConfigProvider { +public: + struct ConfigInfo { + // A reference to the currently loaded route configuration. Do not hold this reference beyond + // the caller of configInfo()'s scope. + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config_; + + // The discovery version that supplied this route. This will be set to "" in the case of + // static clusters. + std::string version_; + }; + + virtual ~RouteConfigProvider() = default; + + /** + * @return Router::ConfigConstSharedPtr a route configuration for use during a single request. The + * returned config may be different on a subsequent call, so a new config should be acquired for + * each request flow. + */ + virtual ConfigConstSharedPtr config() PURE; + + /** + * @return the configuration information for the currently loaded route configuration. Note that + * if the provider has not yet performed an initial configuration load, no information will be + * returned. + */ + virtual absl::optional configInfo() const PURE; + + /** + * @return the last time this RouteConfigProvider was updated. Used for config dumps. + */ + virtual SystemTime lastUpdated() const PURE; + + /** + * Callback used to notify RouteConfigProvider about configuration changes. + */ + virtual void onConfigUpdate() PURE; +}; + +using RouteConfigProviderPtr = std::unique_ptr; +using RouteConfigProviderSharedPtr = std::shared_ptr; + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc new file mode 100644 index 0000000000000..d8223123e0983 --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc @@ -0,0 +1,278 @@ +#include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" + +#include +#include +#include +#include + +#include "envoy/admin/v3/config_dump.pb.h" +#include "envoy/config/core/v3/config_source.pb.h" +#include "envoy/service/discovery/v3/discovery.pb.h" + +#include "source/common/common/assert.h" +#include "source/common/common/fmt.h" +#include "source/common/config/api_version.h" +#include "source/common/config/utility.h" +#include "source/common/config/version_converter.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/network/thrift_proxy/router/config.h" +#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { + +StaticRouteConfigProviderImpl::StaticRouteConfigProviderImpl( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config, + Server::Configuration::ServerFactoryContext& factory_context, + RouteConfigProviderManagerImpl& route_config_provider_manager) + : config_(new ConfigImpl(config)), route_config_proto_{config}, + last_updated_(factory_context.timeSource().systemTime()), + route_config_provider_manager_(route_config_provider_manager) { + route_config_provider_manager_.static_route_config_providers_.insert(this); +} + +StaticRouteConfigProviderImpl::~StaticRouteConfigProviderImpl() { + route_config_provider_manager_.static_route_config_providers_.erase(this); +} + +// TODO(htuch): If support for multiple clusters is added per #1170 cluster_name_ +RdsRouteConfigSubscription::RdsRouteConfigSubscription( + const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + const uint64_t manager_identifier, Server::Configuration::ServerFactoryContext& factory_context, + const std::string& stat_prefix, RouteConfigProviderManagerImpl& route_config_provider_manager) + : Envoy::Config::SubscriptionBase< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>( + rds.config_source().resource_api_version(), + factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), + route_config_name_(rds.route_config_name()), + scope_(factory_context.scope().createScope(stat_prefix + "rds." + route_config_name_ + ".")), + factory_context_(factory_context), + parent_init_target_(fmt::format("RdsRouteConfigSubscription init {}", route_config_name_), + [this]() { local_init_manager_.initialize(local_init_watcher_); }), + local_init_watcher_(fmt::format("RDS local-init-watcher {}", rds.route_config_name()), + [this]() { parent_init_target_.ready(); }), + local_init_target_( + fmt::format("RdsRouteConfigSubscription local-init-target {}", route_config_name_), + [this]() { subscription_->start({route_config_name_}); }), + local_init_manager_(fmt::format("RDS local-init-manager {}", route_config_name_)), + stat_prefix_(stat_prefix), + stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}), + route_config_provider_manager_(route_config_provider_manager), + manager_identifier_(manager_identifier) { + const auto resource_name = getResourceName(); + subscription_ = + factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( + rds.config_source(), Grpc::Common::typeUrl(resource_name), *scope_, *this, + resource_decoder_, {}); + local_init_manager_.add(local_init_target_); + config_update_info_ = std::make_unique(factory_context); +} + +RdsRouteConfigSubscription::~RdsRouteConfigSubscription() { + // If we get destroyed during initialization, make sure we signal that we "initialized". + local_init_target_.ready(); + + // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that + // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the + // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get + // cleaned by the RdsRouteConfigProvider's destructor. + route_config_provider_manager_.dynamic_route_config_providers_.erase(manager_identifier_); +} + +void RdsRouteConfigSubscription::onConfigUpdate( + const std::vector& resources, + const std::string& version_info) { + if (!validateUpdateSize(resources.size())) { + return; + } + const auto& route_config = dynamic_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>( + resources[0].get().resource()); + if (route_config.name() != route_config_name_) { + throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}", + route_config_name_, route_config.name())); + } + if (config_update_info_->onRdsUpdate(route_config, version_info)) { + stats_.config_reload_.inc(); + stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); + + ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_, + config_update_info_->configHash()); + + if (route_config_provider_opt_.has_value()) { + route_config_provider_opt_.value()->onConfigUpdate(); + } + } + + local_init_target_.ready(); +} + +void RdsRouteConfigSubscription::onConfigUpdate( + const std::vector& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, const std::string&) { + if (!removed_resources.empty()) { + // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense + // (see discussion in #6879), and so we should do something other than ignoring here. + ENVOY_LOG( + error, + "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", + removed_resources[0]); + } + if (!added_resources.empty()) { + onConfigUpdate(added_resources, added_resources[0].get().version()); + } +} + +void RdsRouteConfigSubscription::onConfigUpdateFailed( + Envoy::Config::ConfigUpdateFailureReason reason, const EnvoyException*) { + ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason); + // We need to allow server startup to continue, even if we have a bad + // config. + local_init_target_.ready(); +} + +bool RdsRouteConfigSubscription::validateUpdateSize(int num_resources) { + if (num_resources == 0) { + ENVOY_LOG(debug, "Missing RouteConfiguration for {} in onConfigUpdate()", route_config_name_); + stats_.update_empty_.inc(); + local_init_target_.ready(); + return false; + } + if (num_resources != 1) { + throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", num_resources)); + // (would be a return false here) + } + return true; +} + +RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( + RdsRouteConfigSubscriptionSharedPtr&& subscription, + Server::Configuration::ServerFactoryContext& factory_context) + : subscription_(std::move(subscription)), + config_update_info_(subscription_->routeConfigUpdate()), tls_(factory_context.threadLocal()) { + ConfigConstSharedPtr initial_config; + if (config_update_info_->configInfo().has_value()) { + initial_config = std::make_shared(config_update_info_->protobufConfiguration()); + } else { + initial_config = std::make_shared(); + } + tls_.set([initial_config](Event::Dispatcher&) { + return std::make_shared(initial_config); + }); + // It should be 1:1 mapping due to shared rds config. + ASSERT(!subscription_->routeConfigProvider().has_value()); + subscription_->routeConfigProvider().emplace(this); +} + +RdsRouteConfigProviderImpl::~RdsRouteConfigProviderImpl() { + ASSERT(subscription_->routeConfigProvider().has_value()); + subscription_->routeConfigProvider().reset(); +} + +ConfigConstSharedPtr RdsRouteConfigProviderImpl::config() { return tls_->config_; } + +void RdsRouteConfigProviderImpl::onConfigUpdate() { + tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( + OptRef tls) { tls->config_ = new_config; }); +} + +RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) { + config_tracker_entry_ = + admin.getConfigTracker().add("routes", [this](const Matchers::StringMatcher& matcher) { + return dumpRouteConfigs(matcher); + }); + // ConfigTracker keys must be unique. We are asserting that no one has stolen the "routes" key + // from us, since the returned entry will be nullptr if the key already exists. + RELEASE_ASSERT(config_tracker_entry_, ""); +} + +RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + Init::Manager& init_manager) { + // RdsRouteConfigSubscriptions are unique based on their serialized RDS config. + const uint64_t manager_identifier = MessageUtil::hash(rds); + auto it = dynamic_route_config_providers_.find(manager_identifier); + + if (it == dynamic_route_config_providers_.end()) { + // std::make_shared does not work for classes with private constructors. There are ways + // around it. However, since this is not a performance critical path we err on the side + // of simplicity. + RdsRouteConfigSubscriptionSharedPtr subscription(new RdsRouteConfigSubscription( + rds, manager_identifier, factory_context, stat_prefix, *this)); + init_manager.add(subscription->parent_init_target_); + RdsRouteConfigProviderImplSharedPtr new_provider{ + new RdsRouteConfigProviderImpl(std::move(subscription), factory_context)}; + dynamic_route_config_providers_.insert( + {manager_identifier, std::weak_ptr(new_provider)}); + return new_provider; + } else { + // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up + // in the RdsRouteConfigSubscription destructor, and the single threaded nature + // of this code, locking the weak_ptr will not fail. + auto existing_provider = it->second.lock(); + RELEASE_ASSERT(existing_provider != nullptr, + absl::StrCat("cannot find subscribed rds resource ", rds.route_config_name())); + init_manager.add(existing_provider->subscription_->parent_init_target_); + return existing_provider; + } +} + +RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, + Server::Configuration::ServerFactoryContext& factory_context) { + auto provider = + std::make_unique(route_config, factory_context, *this); + static_route_config_providers_.insert(provider.get()); + return provider; +} + +std::unique_ptr +RouteConfigProviderManagerImpl::dumpRouteConfigs( + const Matchers::StringMatcher& name_matcher) const { + auto config_dump = std::make_unique(); + + for (const auto& element : dynamic_route_config_providers_) { + const auto& subscription = element.second.lock()->subscription_; + // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up + // in the RdsRouteConfigSubscription destructor, and the single threaded nature + // of this code, locking the weak_ptr will not fail. + ASSERT(subscription); + ASSERT(subscription->route_config_provider_opt_.has_value()); + + if (subscription->routeConfigUpdate()->configInfo()) { + if (!name_matcher.match(subscription->routeConfigUpdate()->protobufConfiguration().name())) { + continue; + } + auto* dynamic_config = config_dump->mutable_dynamic_route_configs()->Add(); + dynamic_config->set_version_info(subscription->routeConfigUpdate()->configVersion()); + dynamic_config->mutable_route_config()->PackFrom( + API_RECOVER_ORIGINAL(subscription->routeConfigUpdate()->protobufConfiguration())); + TimestampUtil::systemClockToTimestamp(subscription->routeConfigUpdate()->lastUpdated(), + *dynamic_config->mutable_last_updated()); + } + } + + for (const auto& provider : static_route_config_providers_) { + ASSERT(provider->configInfo()); + if (!name_matcher.match(provider->configInfo().value().config_.name())) { + continue; + } + auto* static_config = config_dump->mutable_static_route_configs()->Add(); + static_config->mutable_route_config()->PackFrom( + API_RECOVER_ORIGINAL(provider->configInfo().value().config_)); + TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), + *static_config->mutable_last_updated()); + } + + return config_dump; +} + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h new file mode 100644 index 0000000000000..18ed509f51647 --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h @@ -0,0 +1,223 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "envoy/admin/v3/config_dump.pb.h" +#include "envoy/config/core/v3/config_source.pb.h" +#include "envoy/config/subscription.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.validate.h" +#include "envoy/http/codes.h" +#include "envoy/local_info/local_info.h" +#include "envoy/server/admin.h" +#include "envoy/server/filter_config.h" +#include "envoy/service/discovery/v3/discovery.pb.h" +#include "envoy/singleton/instance.h" +#include "envoy/stats/scope.h" +#include "envoy/thread_local/thread_local.h" + +#include "source/common/common/cleanup.h" +#include "source/common/common/logger.h" +#include "source/common/config/subscription_base.h" +#include "source/common/init/manager_impl.h" +#include "source/common/init/target_impl.h" +#include "source/common/init/watcher_impl.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds.h" +#include "source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h" +#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h" + +#include "absl/container/node_hash_map.h" +#include "absl/container/node_hash_set.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { + +/** + * Route configuration provider utilities. + */ +class RouteConfigProviderManagerImpl; + +/** + * Implementation of RouteConfigProvider that holds a static route configuration. + */ +class StaticRouteConfigProviderImpl : public RouteConfigProvider { +public: + StaticRouteConfigProviderImpl( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config, + Server::Configuration::ServerFactoryContext& factory_context, + RouteConfigProviderManagerImpl& route_config_provider_manager); + ~StaticRouteConfigProviderImpl() override; + + // Router::RouteConfigProvider + ConfigConstSharedPtr config() override { return config_; } + absl::optional configInfo() const override { + return ConfigInfo{route_config_proto_, ""}; + } + SystemTime lastUpdated() const override { return last_updated_; } + void onConfigUpdate() override {} + +private: + ConfigConstSharedPtr config_; + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration route_config_proto_; + SystemTime last_updated_; + RouteConfigProviderManagerImpl& route_config_provider_manager_; +}; + +/** + * All RDS stats. @see stats_macros.h + */ +#define ALL_RDS_STATS(COUNTER, GAUGE) \ + COUNTER(config_reload) \ + COUNTER(update_empty) \ + GAUGE(config_reload_time_ms, NeverImport) + +/** + * Struct definition for all RDS stats. @see stats_macros.h + */ +struct RdsStats { + ALL_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) +}; + +class RdsRouteConfigProviderImpl; + +/** + * A class that fetches the route configuration dynamically using the RDS API and updates them to + * RDS config providers. + */ +class RdsRouteConfigSubscription + : Envoy::Config::SubscriptionBase< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>, + Logger::Loggable { +public: + ~RdsRouteConfigSubscription() override; + + absl::optional& routeConfigProvider() { return route_config_provider_opt_; } + RouteConfigUpdatePtr& routeConfigUpdate() { return config_update_info_; } + +private: + // Config::SubscriptionCallbacks + void onConfigUpdate(const std::vector& resources, + const std::string& version_info) override; + void onConfigUpdate(const std::vector& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string& system_version_info) override; + void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, + const EnvoyException* e) override; + + RdsRouteConfigSubscription(const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + const uint64_t manager_identifier, + Server::Configuration::ServerFactoryContext& factory_context, + const std::string& stat_prefix, + RouteConfigProviderManagerImpl& route_config_provider_manager); + + bool validateUpdateSize(int num_resources); + + const std::string route_config_name_; + // This scope must outlive the subscription_ below as the subscription has derived stats. + Stats::ScopePtr scope_; + Envoy::Config::SubscriptionPtr subscription_; + Server::Configuration::ServerFactoryContext& factory_context_; + + // Init target used to notify the parent init manager that the subscription [and its sub resource] + // is ready. + Init::SharedTargetImpl parent_init_target_; + // Init watcher on RDS and VHDS ready event. This watcher marks parent_init_target_ ready. + Init::WatcherImpl local_init_watcher_; + // Target which starts the RDS subscription. + Init::TargetImpl local_init_target_; + Init::ManagerImpl local_init_manager_; + std::string stat_prefix_; + RdsStats stats_; + RouteConfigProviderManagerImpl& route_config_provider_manager_; + const uint64_t manager_identifier_; + absl::optional route_config_provider_opt_; + RouteConfigUpdatePtr config_update_info_; + + friend class RouteConfigProviderManagerImpl; +}; + +using RdsRouteConfigSubscriptionSharedPtr = std::shared_ptr; + +/** + * Implementation of RouteConfigProvider that fetches the route configuration dynamically using + * the subscription. + */ +class RdsRouteConfigProviderImpl : public RouteConfigProvider, + Logger::Loggable { +public: + ~RdsRouteConfigProviderImpl() override; + + RdsRouteConfigSubscription& subscription() { return *subscription_; } + + // Router::RouteConfigProvider + ConfigConstSharedPtr config() override; + absl::optional configInfo() const override { + return config_update_info_->configInfo(); + } + SystemTime lastUpdated() const override { return config_update_info_->lastUpdated(); } + void onConfigUpdate() override; + +private: + struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { + ThreadLocalConfig(ConfigConstSharedPtr initial_config) : config_(std::move(initial_config)) {} + ConfigConstSharedPtr config_; + }; + + RdsRouteConfigProviderImpl(RdsRouteConfigSubscriptionSharedPtr&& subscription, + Server::Configuration::ServerFactoryContext& factory_context); + + RdsRouteConfigSubscriptionSharedPtr subscription_; + RouteConfigUpdatePtr& config_update_info_; + ThreadLocal::TypedSlot tls_; + + friend class RouteConfigProviderManagerImpl; +}; + +using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; + +class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, + public Singleton::Instance { +public: + RouteConfigProviderManagerImpl(Server::Admin& admin); + + std::unique_ptr + dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const; + + // RouteConfigProviderManager + RouteConfigProviderSharedPtr createRdsRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + Init::Manager& init_manager) override; + + RouteConfigProviderPtr createStaticRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, + Server::Configuration::ServerFactoryContext& factory_context) override; + +private: + // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map + // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists + // Then the lifetime management stuff is centralized and opaque. + absl::node_hash_map> + dynamic_route_config_providers_; + absl::node_hash_set static_route_config_providers_; + Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; + + friend class RdsRouteConfigSubscription; + friend class StaticRouteConfigProviderImpl; +}; + +using RouteConfigProviderManagerImplPtr = std::unique_ptr; + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h b/source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h new file mode 100644 index 0000000000000..95332b188b63c --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +#include "envoy/config/core/v3/extension.pb.h" +#include "envoy/event/dispatcher.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.pb.h" +#include "envoy/local_info/local_info.h" +#include "envoy/runtime/runtime.h" +#include "envoy/server/filter_config.h" +#include "envoy/thread_local/thread_local.h" +#include "envoy/upstream/cluster_manager.h" + +#include "source/extensions/filters/network/thrift_proxy/router/rds.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { +/** + * The RouteConfigProviderManager exposes the ability to get a RouteConfigProvider. This interface + * is exposed to the Server's FactoryContext in order to allow HttpConnectionManagers to get + * RouteConfigProviders. + */ +class RouteConfigProviderManager { +public: + virtual ~RouteConfigProviderManager() = default; + + /** + * Get a RouteConfigProviderPtr for a route from RDS. Ownership of the RouteConfigProvider is the + * HttpConnectionManagers who calls this function. The RouteConfigProviderManager holds raw + * pointers to the RouteConfigProviders. Clean up of the pointers happen from the destructor of + * the RouteConfigProvider. This method creates a RouteConfigProvider which may share the + * underlying RDS subscription with the same (route_config_name, cluster). + * @param rds supplies the proto configuration of an RDS-configured RouteConfigProvider. + * @param optional_http_filters a set of optional http filter names. + * @param factory_context is the context to use for the route config provider. + * @param stat_prefix supplies the stat_prefix to use for the provider stats. + * @param init_manager the Init::Manager used to coordinate initialization of a the underlying RDS + * subscription. + */ + virtual RouteConfigProviderSharedPtr createRdsRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + Init::Manager& init_manager) PURE; + + /** + * Get a RouteConfigSharedPtr for a statically defined route. Ownership is as described for + * getRdsRouteConfigProvider above. This method always create a new RouteConfigProvider. + * @param route_config supplies the RouteConfiguration for this route + * @param optional_http_filters a set of optional http filter names. + * @param factory_context is the context to use for the route config provider. + * @param validator is the message validator for route config. + */ + virtual RouteConfigProviderPtr createStaticRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, + Server::Configuration::ServerFactoryContext& factory_context) PURE; +}; + +using RouteConfigProviderManagerPtr = std::unique_ptr; +using RouteConfigProviderManagerSharedPtr = std::shared_ptr; + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h new file mode 100644 index 0000000000000..a2108c5e24d85 --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h @@ -0,0 +1,84 @@ +#pragma once + +#include + +#include "envoy/common/pure.h" +#include "envoy/common/time.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" +#include "envoy/service/discovery/v3/discovery.pb.h" + +#include "source/common/protobuf/protobuf.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { + +/** + * A primitive that keeps track of updates to a RouteConfiguration. + */ +class RouteConfigUpdateReceiver { +public: + virtual ~RouteConfigUpdateReceiver() = default; + + /** + * Called on updates via RDS. + * @param rc supplies the RouteConfiguration. + * @param version_info supplies RouteConfiguration version. + * @return bool whether RouteConfiguration has been updated. + */ + virtual bool + onRdsUpdate(const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc, + const std::string& version_info) PURE; + + /** + * @return std::string& the name of RouteConfiguration. + */ + virtual const std::string& routeConfigName() const PURE; + + /** + * @return std::string& the version of RouteConfiguration. + */ + virtual const std::string& configVersion() const PURE; + + /** + * @return uint64_t the hash value of RouteConfiguration. + */ + virtual uint64_t configHash() const PURE; + + /** + * @return absl::optional containing an instance of + * RouteConfigProvider::ConfigInfo if RouteConfiguration has been updated at least once. Otherwise + * returns an empty absl::optional. + */ + virtual absl::optional configInfo() const PURE; + + /** + * @return envoy::config::route::v3::RouteConfiguration& current RouteConfiguration. + */ + virtual const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& + protobufConfiguration() PURE; + + /** + * @return Router::ConfigConstSharedPtr a parsed and validated copy of current RouteConfiguration. + * @see protobufConfiguration() + */ + virtual ConfigConstSharedPtr parsedConfiguration() const PURE; + + /** + * @return SystemTime the time of the last update. + */ + virtual SystemTime lastUpdated() const PURE; +}; + +using RouteConfigUpdatePtr = std::unique_ptr; + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc new file mode 100644 index 0000000000000..281d57fd75ab6 --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc @@ -0,0 +1,42 @@ +#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h" + +#include + +#include "envoy/config/route/v3/route.pb.h" +#include "envoy/service/discovery/v3/discovery.pb.h" + +#include "source/common/common/assert.h" +#include "source/common/common/fmt.h" +#include "source/common/common/thread.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/network/thrift_proxy/router/config.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { + +bool RouteConfigUpdateReceiverImpl::onRdsUpdate( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc, + const std::string& version_info) { + const uint64_t new_hash = MessageUtil::hash(rc); + if (new_hash == last_config_hash_) { + return false; + } + route_config_proto_ = + std::make_unique( + rc); + last_config_hash_ = new_hash; + config_ = std::make_shared(*route_config_proto_); + last_config_version_ = version_info; + last_updated_ = time_source_.systemTime(); + config_info_.emplace(RouteConfigProvider::ConfigInfo{*route_config_proto_, last_config_version_}); + return true; +} + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h new file mode 100644 index 0000000000000..4ba96a4a89cdf --- /dev/null +++ b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +#include "envoy/server/factory_context.h" +#include "envoy/service/discovery/v3/discovery.pb.h" + +#include "source/common/common/logger.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h" + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { + +class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { +public: + RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context) + : time_source_(factory_context.timeSource()), + route_config_proto_( + std::make_unique< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>()), + last_config_hash_(0ull) {} + + // Router::RouteConfigUpdateReceiver + bool + onRdsUpdate(const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc, + const std::string& version_info) override; + const std::string& routeConfigName() const override { return route_config_proto_->name(); } + const std::string& configVersion() const override { return last_config_version_; } + uint64_t configHash() const override { return last_config_hash_; } + absl::optional configInfo() const override { + return config_info_; + } + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& + protobufConfiguration() override { + return static_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>( + *route_config_proto_); + } + ConfigConstSharedPtr parsedConfiguration() const override { return config_; } + SystemTime lastUpdated() const override { return last_updated_; } + +private: + TimeSource& time_source_; + std::unique_ptr + route_config_proto_; + uint64_t last_config_hash_; + std::string last_config_version_; + SystemTime last_updated_; + absl::optional config_info_; + ConfigConstSharedPtr config_; +}; + +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/network/thrift_proxy/BUILD b/test/extensions/filters/network/thrift_proxy/BUILD index 6e6cb31a06288..58131960c021f 100644 --- a/test/extensions/filters/network/thrift_proxy/BUILD +++ b/test/extensions/filters/network/thrift_proxy/BUILD @@ -360,3 +360,19 @@ envoy_extension_cc_test( "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", ], ) + +envoy_extension_cc_test( + name = "rds_impl_test", + srcs = ["rds_impl_test.cc"], + extension_names = ["envoy.filters.network.thrift_proxy"], + deps = [ + ":mocks", + "//source/extensions/filters/network/thrift_proxy:config", + "//source/extensions/filters/network/thrift_proxy/router:config", + "//test/mocks/matcher:matcher_mocks", + "//test/mocks/server:factory_context_mocks", + "@envoy_api//envoy/admin/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", + "@envoy_api//envoy/service/discovery/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/filters/network/thrift_proxy/config_test.cc b/test/extensions/filters/network/thrift_proxy/config_test.cc index 9ff67f65ef2b9..66d2bcb3fa5d8 100644 --- a/test/extensions/filters/network/thrift_proxy/config_test.cc +++ b/test/extensions/filters/network/thrift_proxy/config_test.cc @@ -64,6 +64,7 @@ class ThriftFilterConfigTestBase { cb(connection); } + Event::SimulatedTimeSystem time_system_; NiceMock context_; ThriftProxyFilterConfigFactory factory_; }; diff --git a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc new file mode 100644 index 0000000000000..6a6bf7689d134 --- /dev/null +++ b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc @@ -0,0 +1,583 @@ +#include +#include +#include + +#include "envoy/admin/v3/config_dump.pb.h" +#include "envoy/admin/v3/config_dump.pb.validate.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.pb.h" +#include "envoy/service/discovery/v3/discovery.pb.h" +#include "envoy/stats/scope.h" + +#include "source/common/config/utility.h" +#include "source/common/json/json_loader.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" + +#include "test/mocks/init/mocks.h" +#include "test/mocks/local_info/mocks.h" +#include "test/mocks/matcher/mocks.h" +#include "test/mocks/protobuf/mocks.h" +#include "test/mocks/server/instance.h" +#include "test/mocks/thread_local/mocks.h" +#include "test/test_common/printers.h" +#include "test/test_common/simulated_time_system.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::_; +using testing::Eq; +using testing::InSequence; +using testing::Invoke; +using testing::ReturnRef; +using testing::SaveArg; + +namespace Envoy { +namespace Extensions { +namespace NetworkFilters { +namespace ThriftProxy { +namespace Router { +namespace { + +using ::Envoy::Matchers::MockStringMatcher; +using ::Envoy::Matchers::UniversalStringMatcher; + +envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy +parseThriftProxyFromYaml(const std::string& yaml_string) { + envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy thrift_proxy; + TestUtility::loadFromYaml(yaml_string, thrift_proxy); + return thrift_proxy; +} + +class RdsTestBase : public testing::Test { +public: + RdsTestBase() { + // For server_factory_context + ON_CALL(server_factory_context_, scope()).WillByDefault(ReturnRef(scope_)); + ON_CALL(server_factory_context_, messageValidationContext()) + .WillByDefault(ReturnRef(validation_context_)); + EXPECT_CALL(validation_context_, dynamicValidationVisitor()) + .WillRepeatedly(ReturnRef(validation_visitor_)); + + ON_CALL(outer_init_manager_, add(_)).WillByDefault(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + ON_CALL(outer_init_manager_, initialize(_)) + .WillByDefault(Invoke( + [this](const Init::Watcher& watcher) { init_target_handle_->initialize(watcher); })); + } + + Event::SimulatedTimeSystem& timeSystem() { return time_system_; } + + Event::SimulatedTimeSystem time_system_; + NiceMock validation_context_; + NiceMock validation_visitor_; + NiceMock outer_init_manager_; + NiceMock server_factory_context_; + Init::ExpectableWatcherImpl init_watcher_; + Init::TargetHandlePtr init_target_handle_; + Envoy::Config::SubscriptionCallbacks* rds_callbacks_{}; + NiceMock scope_; +}; + +class RdsImplTest : public RdsTestBase { +public: + RdsImplTest() { + EXPECT_CALL(server_factory_context_.admin_.config_tracker_, add_("routes", _)); + route_config_provider_manager_ = + std::make_unique(server_factory_context_.admin_); + } + ~RdsImplTest() override { server_factory_context_.thread_local_.shutdownThread(); } + + void setup() { + std::string config_yaml = R"EOF( +rds: + config_source: + api_config_source: + api_type: REST + cluster_names: + - foo_cluster + refresh_delay: 1s + route_config_name: foo_route_config + )EOF"; + + EXPECT_CALL(outer_init_manager_, add(_)); + rds_ = route_config_provider_manager_->createRdsRouteConfigProvider( + parseThriftProxyFromYaml(config_yaml).rds(), server_factory_context_, "foo.", + outer_init_manager_); + rds_callbacks_ = server_factory_context_.cluster_manager_.subscription_factory_.callbacks_; + EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, + start(_)); + outer_init_manager_.initialize(init_watcher_); + } + + RouteConstSharedPtr route(const MessageMetadata& metadata) { + return rds_->config()->route(metadata, 12345); + } + + RouteConfigProviderManagerImplPtr route_config_provider_manager_; + RouteConfigProviderSharedPtr rds_; +}; + +TEST_F(RdsImplTest, DestroyDuringInitialize) { + InSequence s; + setup(); + EXPECT_CALL(init_watcher_, ready()); + rds_.reset(); +} + +TEST_F(RdsImplTest, Basic) { + InSequence s; + Buffer::OwnedImpl empty; + Buffer::OwnedImpl data; + + setup(); + + // Make sure the initial empty route table works. + MessageMetadata md; + md.setMethodName("foo"); + EXPECT_EQ(nullptr, route(md)); + + // Initial request. + const std::string response1_json = R"EOF( +{ + "version_info": "1", + "resources": [ + { + "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", + "name": "foo_route_config", + "routes": null + } + ] +} +)EOF"; + auto response1 = + TestUtility::parseYaml(response1_json); + const auto decoded_resources = TestUtility::decodeResources< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response1); + + EXPECT_CALL(init_watcher_, ready()); + rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()); + md.setMethodName("bar"); + EXPECT_EQ(nullptr, route(md)); + + // 2nd request with same response. Based on hash should not reload config. + rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()); + EXPECT_EQ(nullptr, route(md)); + + // Load the config and verified shared count. + // ConfigConstSharedPtr is shared between: RouteConfigUpdateReceiverImpl, rds_ (via tls_), and + // config local var below. + ConfigConstSharedPtr config = rds_->config(); + EXPECT_EQ(3, config.use_count()); + + // Third request. + const std::string response2_json = R"EOF( +{ + "version_info": "2", + "resources": [ + { + "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", + "name": "foo_route_config", + "routes": [ + { + "match": + { + "method_name": "bar" + }, + "route": + { + "cluster": "foo" + } + } + ] + } + ] +} + )EOF"; + auto response2 = + TestUtility::parseYaml(response2_json); + const auto decoded_resources_2 = TestUtility::decodeResources< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response2); + + // Make sure we don't lookup/verify clusters. + EXPECT_CALL(server_factory_context_.cluster_manager_, getThreadLocalCluster(Eq("bar"))).Times(0); + rds_callbacks_->onConfigUpdate(decoded_resources_2.refvec_, response2.version_info()); + EXPECT_EQ("foo", route(md)->routeEntry()->clusterName()); + + // Old config use count should be 1 now. + EXPECT_EQ(1, config.use_count()); + EXPECT_EQ(2UL, scope_.counter("foo.rds.foo_route_config.config_reload").value()); + EXPECT_TRUE(scope_.findGaugeByString("foo.rds.foo_route_config.config_reload_time_ms")); +} + +// Validate behavior when the config is delivered but it fails PGV validation. +TEST_F(RdsImplTest, FailureInvalidConfig) { + InSequence s; + + setup(); + + const std::string response1_json = R"EOF( +{ + "version_info": "1", + "resources": [ + { + "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", + "name": "INVALID_NAME_FOR_route_config", + "routes": null + } + ] +} +)EOF"; + auto response1 = + TestUtility::parseYaml(response1_json); + const auto decoded_resources = TestUtility::decodeResources< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response1); + + EXPECT_CALL(init_watcher_, ready()); + EXPECT_THROW_WITH_MESSAGE( + rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()), + EnvoyException, + "Unexpected RDS configuration (expecting foo_route_config): INVALID_NAME_FOR_route_config"); +} + +// Validate behavior when the config fails delivery at the subscription level. +TEST_F(RdsImplTest, FailureSubscription) { + InSequence s; + + setup(); + + EXPECT_CALL(init_watcher_, ready()); + // onConfigUpdateFailed() should not be called for gRPC stream connection failure + rds_callbacks_->onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason::FetchTimedout, {}); +} + +class RouteConfigProviderManagerImplTest : public RdsTestBase { +public: + void setup() { + // Get a RouteConfigProvider. This one should create an entry in the RouteConfigProviderManager. + rds_.set_route_config_name("foo_route_config"); + rds_.mutable_config_source()->set_path("foo_path"); + provider_ = route_config_provider_manager_->createRdsRouteConfigProvider( + rds_, server_factory_context_, "foo_prefix.", outer_init_manager_); + rds_callbacks_ = server_factory_context_.cluster_manager_.subscription_factory_.callbacks_; + } + + RouteConfigProviderManagerImplTest() { + EXPECT_CALL(server_factory_context_.admin_.config_tracker_, add_("routes", _)); + route_config_provider_manager_ = + std::make_unique(server_factory_context_.admin_); + } + + ~RouteConfigProviderManagerImplTest() override { + server_factory_context_.thread_local_.shutdownThread(); + } + + envoy::extensions::filters::network::thrift_proxy::v3::Rds rds_; + RouteConfigProviderManagerImplPtr route_config_provider_manager_; + RouteConfigProviderSharedPtr provider_; +}; + +envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration +parseRouteConfigurationFromV3Yaml(const std::string& yaml, bool avoid_boosting = true) { + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration route_config; + TestUtility::loadFromYaml(yaml, route_config, true, avoid_boosting); + return route_config; +} + +TEST_F(RouteConfigProviderManagerImplTest, ConfigDump) { + UniversalStringMatcher universal_name_matcher; + auto message_ptr = + server_factory_context_.admin_.config_tracker_.config_tracker_callbacks_["routes"]( + universal_name_matcher); + const auto& route_config_dump = + TestUtility::downcastAndValidate(*message_ptr); + + // No routes at all, no last_updated timestamp + envoy::admin::v3::RoutesConfigDump expected_route_config_dump; + TestUtility::loadFromYaml(R"EOF( +static_route_configs: +dynamic_route_configs: +)EOF", + expected_route_config_dump); + EXPECT_EQ(expected_route_config_dump.DebugString(), route_config_dump.DebugString()); + + const std::string config_yaml = R"EOF( +name: foo +routes: + - match: + method_name: bar + route: + cluster: baz +)EOF"; + + timeSystem().setSystemTime(std::chrono::milliseconds(1234567891234)); + + // Only static route. + server_factory_context_.cluster_manager_.initializeClusters({"baz"}, {}); + RouteConfigProviderPtr static_config = + route_config_provider_manager_->createStaticRouteConfigProvider( + parseRouteConfigurationFromV3Yaml(config_yaml), server_factory_context_); + message_ptr = server_factory_context_.admin_.config_tracker_.config_tracker_callbacks_["routes"]( + universal_name_matcher); + const auto& route_config_dump2 = + TestUtility::downcastAndValidate(*message_ptr); + TestUtility::loadFromYaml(R"EOF( +static_route_configs: + - route_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration + name: foo + routes: + - match: + method_name: bar + route: + cluster: baz + last_updated: + seconds: 1234567891 + nanos: 234000000 +dynamic_route_configs: +)EOF", + expected_route_config_dump); + EXPECT_EQ(expected_route_config_dump.DebugString(), route_config_dump2.DebugString()); + + // Static + dynamic. + setup(); + EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, + start(_)); + outer_init_manager_.initialize(init_watcher_); + + const std::string response1_json = R"EOF( +{ + "version_info": "1", + "resources": [ + { + "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", + "name": "foo_route_config", + "routes": null + } + ] +} +)EOF"; + auto response1 = + TestUtility::parseYaml(response1_json); + const auto decoded_resources = TestUtility::decodeResources< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response1); + + EXPECT_CALL(init_watcher_, ready()); + rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()); + message_ptr = server_factory_context_.admin_.config_tracker_.config_tracker_callbacks_["routes"]( + universal_name_matcher); + const auto& route_config_dump3 = + TestUtility::downcastAndValidate(*message_ptr); + TestUtility::loadFromYaml(R"EOF( +static_route_configs: + - route_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration + name: foo + routes: + - match: + method_name: bar + route: + cluster: baz + last_updated: + seconds: 1234567891 + nanos: 234000000 +dynamic_route_configs: + - version_info: "1" + route_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration + name: foo_route_config + routes: + last_updated: + seconds: 1234567891 + nanos: 234000000 +)EOF", + expected_route_config_dump); + EXPECT_EQ(expected_route_config_dump.DebugString(), route_config_dump3.DebugString()); + + MockStringMatcher mock_name_matcher; + EXPECT_CALL(mock_name_matcher, match("foo")).WillOnce(Return(true)); + EXPECT_CALL(mock_name_matcher, match("foo_route_config")).WillOnce(Return(false)); + message_ptr = server_factory_context_.admin_.config_tracker_.config_tracker_callbacks_["routes"]( + mock_name_matcher); + const auto& route_config_dump4 = + TestUtility::downcastAndValidate(*message_ptr); + TestUtility::loadFromYaml(R"EOF( +static_route_configs: + - route_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration + name: foo + routes: + - match: + method_name: bar + route: + cluster: baz + last_updated: + seconds: 1234567891 + nanos: 234000000 +)EOF", + expected_route_config_dump); + EXPECT_EQ(expected_route_config_dump.DebugString(), route_config_dump4.DebugString()); + + EXPECT_CALL(mock_name_matcher, match("foo")).WillOnce(Return(false)); + EXPECT_CALL(mock_name_matcher, match("foo_route_config")).WillOnce(Return(true)); + message_ptr = server_factory_context_.admin_.config_tracker_.config_tracker_callbacks_["routes"]( + mock_name_matcher); + const auto& route_config_dump5 = + TestUtility::downcastAndValidate(*message_ptr); + TestUtility::loadFromYaml(R"EOF( +dynamic_route_configs: + - version_info: "1" + route_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration + name: foo_route_config + routes: + last_updated: + seconds: 1234567891 + nanos: 234000000 +)EOF", + expected_route_config_dump); + EXPECT_EQ(expected_route_config_dump.DebugString(), route_config_dump5.DebugString()); +} + +TEST_F(RouteConfigProviderManagerImplTest, Basic) { + Buffer::OwnedImpl data; + + // Get a RouteConfigProvider. This one should create an entry in the RouteConfigProviderManager. + setup(); + + EXPECT_FALSE(provider_->configInfo().has_value()); + + const auto route_config = parseRouteConfigurationFromV3Yaml(R"EOF( +name: foo_route_config +routes: + - match: + method_name: bar + route: + cluster: baz +)EOF"); + const auto decoded_resources = TestUtility::decodeResources({route_config}); + + server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( + decoded_resources.refvec_, "1"); + + RouteConfigProviderSharedPtr provider2 = + route_config_provider_manager_->createRdsRouteConfigProvider( + rds_, server_factory_context_, "foo_prefix", outer_init_manager_); + + // provider2 should have route config immediately after create + EXPECT_TRUE(provider2->configInfo().has_value()); + + EXPECT_EQ(provider_, provider2) << "fail to obtain the same rds config provider object"; + + // So this means that both provider have same subscription. + EXPECT_EQ(&dynamic_cast(*provider_).subscription(), + &dynamic_cast(*provider2).subscription()); + EXPECT_EQ(&provider_->configInfo().value().config_, &provider2->configInfo().value().config_); + + envoy::extensions::filters::network::thrift_proxy::v3::Rds rds2; + rds2.set_route_config_name("foo_route_config"); + rds2.mutable_config_source()->set_path("bar_path"); + RouteConfigProviderSharedPtr provider3 = + route_config_provider_manager_->createRdsRouteConfigProvider( + rds2, server_factory_context_, "foo_prefix", outer_init_manager_); + EXPECT_NE(provider3, provider_); + server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( + decoded_resources.refvec_, "provider3"); + UniversalStringMatcher universal_name_matcher; + EXPECT_EQ(2UL, route_config_provider_manager_->dumpRouteConfigs(universal_name_matcher) + ->dynamic_route_configs() + .size()); + + provider_.reset(); + provider2.reset(); + + // All shared_ptrs to the provider pointed at by provider1, and provider2 have been deleted, so + // now we should only have the provider pointed at by provider3. + auto dynamic_route_configs = + route_config_provider_manager_->dumpRouteConfigs(universal_name_matcher) + ->dynamic_route_configs(); + EXPECT_EQ(1UL, dynamic_route_configs.size()); + + // Make sure the left one is provider3 + EXPECT_EQ("provider3", dynamic_route_configs[0].version_info()); + + provider3.reset(); + + EXPECT_EQ(0UL, route_config_provider_manager_->dumpRouteConfigs(universal_name_matcher) + ->dynamic_route_configs() + .size()); +} + +TEST_F(RouteConfigProviderManagerImplTest, SameProviderOnTwoInitManager) { + Buffer::OwnedImpl data; + // Get a RouteConfigProvider. This one should create an entry in the RouteConfigProviderManager. + setup(); + + EXPECT_FALSE(provider_->configInfo().has_value()); + + NiceMock mock_factory_context2; + + Init::WatcherImpl real_watcher("real", []() {}); + Init::ManagerImpl real_init_manager("real"); + + RouteConfigProviderSharedPtr provider2 = + route_config_provider_manager_->createRdsRouteConfigProvider(rds_, mock_factory_context2, + "foo_prefix", real_init_manager); + + EXPECT_FALSE(provider2->configInfo().has_value()); + + EXPECT_EQ(provider_, provider2) << "fail to obtain the same rds config provider object"; + real_init_manager.initialize(real_watcher); + EXPECT_EQ(Init::Manager::State::Initializing, real_init_manager.state()); + + { + const auto route_config = parseRouteConfigurationFromV3Yaml(R"EOF( +name: foo_route_config +routes: + - match: + method_name: bar + route: + cluster: baz +)EOF"); + const auto decoded_resources = TestUtility::decodeResources({route_config}); + + server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( + decoded_resources.refvec_, "1"); + + EXPECT_TRUE(provider_->configInfo().has_value()); + EXPECT_TRUE(provider2->configInfo().has_value()); + EXPECT_EQ(Init::Manager::State::Initialized, real_init_manager.state()); + } +} + +TEST_F(RouteConfigProviderManagerImplTest, OnConfigUpdateEmpty) { + setup(); + EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, + start(_)); + outer_init_manager_.initialize(init_watcher_); + EXPECT_CALL(init_watcher_, ready()); + server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate({}, ""); +} + +TEST_F(RouteConfigProviderManagerImplTest, OnConfigUpdateWrongSize) { + setup(); + EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, + start(_)); + outer_init_manager_.initialize(init_watcher_); + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration route_config; + const auto decoded_resources = TestUtility::decodeResources({route_config, route_config}); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_THROW_WITH_MESSAGE( + server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( + decoded_resources.refvec_, ""), + EnvoyException, "Unexpected RDS resource length: 2"); +} + +} // namespace +} // namespace Router +} // namespace ThriftProxy +} // namespace NetworkFilters +} // namespace Extensions +} // namespace Envoy From eb5dc2140c56ec07c6430ca5daab349c4e12682b Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 11 Aug 2021 13:13:07 +0800 Subject: [PATCH 02/31] Fix generated_api_shadow Signed-off-by: Tamas Kovacs --- .../network/thrift_proxy/v3/thrift_proxy.proto | 3 ++- .../thrift_proxy/v4alpha/thrift_proxy.proto | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index 45215985eaf65..7c92c4959e819 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -2,8 +2,8 @@ syntax = "proto3"; package envoy.extensions.filters.network.thrift_proxy.v3; -import "envoy/extensions/filters/network/thrift_proxy/v3/route.proto"; import "envoy/config/core/v3/config_source.proto"; +import "envoy/extensions/filters/network/thrift_proxy/v3/route.proto"; import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; @@ -146,5 +146,6 @@ message ThriftProtocolOptions { message Rds { config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + string route_config_name = 2; } diff --git a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto index de399582869a0..ccc681061b222 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/thrift_proxy.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package envoy.extensions.filters.network.thrift_proxy.v4alpha; +import "envoy/config/core/v4alpha/config_source.proto"; import "envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto"; import "google/protobuf/any.proto"; @@ -58,7 +59,7 @@ enum ProtocolType { TWITTER = 4; } -// [#next-free-field: 8] +// [#next-free-field: 9] message ThriftProxy { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.network.thrift_proxy.v3.ThriftProxy"; @@ -92,6 +93,9 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; + + // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. + Rds rds = 8; } // ThriftFilter configures a Thrift filter. @@ -138,3 +142,12 @@ message ThriftProtocolOptions { // which is the default, causes the proxy to use the same protocol as the downstream connection. ProtocolType protocol = 2 [(validate.rules).enum = {defined_only: true}]; } + +message Rds { + option (udpa.annotations.versioning).previous_message_type = + "envoy.extensions.filters.network.thrift_proxy.v3.Rds"; + + config.core.v4alpha.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + + string route_config_name = 2; +} From d1e2124ea64efd6c07f59c688bda17902444eb93 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 11 Aug 2021 09:10:03 +0000 Subject: [PATCH 03/31] Fix missed file Signed-off-by: Tamas Kovacs --- source/extensions/filters/network/thrift_proxy/config.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/extensions/filters/network/thrift_proxy/config.h b/source/extensions/filters/network/thrift_proxy/config.h index 65f4dafba84fa..24e651163995d 100644 --- a/source/extensions/filters/network/thrift_proxy/config.h +++ b/source/extensions/filters/network/thrift_proxy/config.h @@ -67,7 +67,8 @@ class ConfigImpl : public Config, Logger::Loggable { public: ConfigImpl(const envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy& config, - Server::Configuration::FactoryContext& context); + Server::Configuration::FactoryContext& context, + Router::RouteConfigProviderManager& route_config_provider_manager); // ThriftFilters::FilterChainFactory void createFilterChain(ThriftFilters::FilterChainFactoryCallbacks& callbacks) override; @@ -75,7 +76,7 @@ class ConfigImpl : public Config, // Router::Config Router::RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const override { - return route_matcher_->route(metadata, random_value); + return route_config_provider_->config()->route(metadata, random_value); } // Config @@ -96,7 +97,7 @@ class ConfigImpl : public Config, ThriftFilterStats stats_; const TransportType transport_; const ProtocolType proto_; - std::unique_ptr route_matcher_; + Router::RouteConfigProviderSharedPtr route_config_provider_; std::list filter_factories_; const bool payload_passthrough_; From 4609c0279ef790998d88b730ae2665f6096cf208 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 11 Aug 2021 10:28:41 +0000 Subject: [PATCH 04/31] Fix conn_manager_test Signed-off-by: Tamas Kovacs --- .../network/thrift_proxy/conn_manager_test.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc b/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc index 7ac6ee7bf94b8..82679872a25fd 100644 --- a/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc +++ b/test/extensions/filters/network/thrift_proxy/conn_manager_test.cc @@ -10,6 +10,7 @@ #include "source/extensions/filters/network/thrift_proxy/conn_manager.h" #include "source/extensions/filters/network/thrift_proxy/framed_transport_impl.h" #include "source/extensions/filters/network/thrift_proxy/header_transport_impl.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" #include "test/common/stats/stat_test_utility.h" #include "test/extensions/filters/network/thrift_proxy/mocks.h" @@ -38,8 +39,10 @@ class TestConfigImpl : public ConfigImpl { public: TestConfigImpl(envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy proto_config, Server::Configuration::MockFactoryContext& context, + Router::RouteConfigProviderManager& route_config_provider_manager, ThriftFilters::DecoderFilterSharedPtr decoder_filter, ThriftFilterStats& stats) - : ConfigImpl(proto_config, context), decoder_filter_(decoder_filter), stats_(stats) {} + : ConfigImpl(proto_config, context, route_config_provider_manager), + decoder_filter_(decoder_filter), stats_(stats) {} // ConfigImpl ThriftFilterStats& stats() override { return stats_; } @@ -71,7 +74,10 @@ class TestConfigImpl : public ConfigImpl { class ThriftConnectionManagerTest : public testing::Test { public: - ThriftConnectionManagerTest() : stats_(ThriftFilterStats::generateStats("test.", store_)) {} + ThriftConnectionManagerTest() : stats_(ThriftFilterStats::generateStats("test.", store_)) { + route_config_provider_manager_ = + std::make_unique(context_.admin_); + } ~ThriftConnectionManagerTest() override { filter_callbacks_.connection_.dispatcher_.clearDeferredDeleteList(); } @@ -97,7 +103,8 @@ class ThriftConnectionManagerTest : public testing::Test { decoder_filter_ = std::make_shared>(); - config_ = std::make_unique(proto_config_, context_, decoder_filter_, stats_); + config_ = std::make_unique( + proto_config_, context_, *route_config_provider_manager_, decoder_filter_, stats_); if (custom_transport_) { config_->transport_ = custom_transport_; } @@ -344,6 +351,7 @@ class ThriftConnectionManagerTest : public testing::Test { ThriftFilterStats stats_; envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy proto_config_; + Router::RouteConfigProviderManagerImplPtr route_config_provider_manager_; std::unique_ptr config_; Buffer::OwnedImpl buffer_; From f48daedbc4f0a12c4b91fa53a4bfb83f820ed082 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 11 Aug 2021 11:33:02 +0000 Subject: [PATCH 05/31] Fix router_ratelimit_test Signed-off-by: Tamas Kovacs --- .../network/thrift_proxy/router_ratelimit_test.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc b/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc index cb44c2df41349..6ed8a3ab5cb72 100644 --- a/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc +++ b/test/extensions/filters/network/thrift_proxy/router_ratelimit_test.cc @@ -10,6 +10,7 @@ #include "source/common/protobuf/utility.h" #include "source/extensions/filters/network/thrift_proxy/config.h" #include "source/extensions/filters/network/thrift_proxy/metadata.h" +#include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.h" #include "test/extensions/filters/network/thrift_proxy/mocks.h" @@ -31,6 +32,11 @@ namespace { class ThriftRateLimitConfigurationTest : public testing::Test { public: + ThriftRateLimitConfigurationTest() { + route_config_provider_manager_ = + std::make_unique(factory_context_.admin_); + } + void initialize(const std::string& yaml, bool avoid_boosting = true) { envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy config; TestUtility::loadFromYaml(yaml, config, false, avoid_boosting); @@ -38,7 +44,8 @@ class ThriftRateLimitConfigurationTest : public testing::Test { } void initialize(envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy& config) { - config_ = std::make_unique(config, factory_context_); + config_ = std::make_unique(config, factory_context_, + *route_config_provider_manager_); } MessageMetadata& genMetadata(const std::string& method_name) { @@ -48,6 +55,7 @@ class ThriftRateLimitConfigurationTest : public testing::Test { } NiceMock factory_context_; + RouteConfigProviderManagerImplPtr route_config_provider_manager_; std::unique_ptr config_; Network::Address::Ipv4Instance default_remote_address_{"10.0.0.1"}; MessageMetadataSharedPtr metadata_; From 0022eeddb05d2bac21438f54aec15c7c05504e4f Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 12 Aug 2021 10:06:13 +0000 Subject: [PATCH 06/31] Fix clang_tidy Signed-off-by: Tamas Kovacs --- test/extensions/filters/network/thrift_proxy/rds_impl_test.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc index 6a6bf7689d134..2029a34494233 100644 --- a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc +++ b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc @@ -31,7 +31,6 @@ using testing::Eq; using testing::InSequence; using testing::Invoke; using testing::ReturnRef; -using testing::SaveArg; namespace Envoy { namespace Extensions { From 32351846cb41ff09d3af750e82e2c1d1638432be Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 18 Aug 2021 14:13:47 +0800 Subject: [PATCH 07/31] More type urls can identify the same RouteDiscoveryService endpoint Signed-off-by: Tamas Kovacs --- api/envoy/annotations/resource.proto | 4 +++ .../filters/network/thrift_proxy/v3/BUILD | 1 + .../network/thrift_proxy/v3/route.proto | 2 ++ .../network/thrift_proxy/v4alpha/BUILD | 1 + .../network/thrift_proxy/v4alpha/route.proto | 2 ++ .../envoy/annotations/resource.proto | 4 +++ .../network/thrift_proxy/v3/route.proto | 2 ++ .../network/thrift_proxy/v4alpha/BUILD | 1 + .../network/thrift_proxy/v4alpha/route.proto | 2 ++ source/common/config/type_to_endpoint.cc | 29 +++++++++++++++++-- 10 files changed, 45 insertions(+), 3 deletions(-) diff --git a/api/envoy/annotations/resource.proto b/api/envoy/annotations/resource.proto index bd794c68dd7a6..f57b262bbee63 100644 --- a/api/envoy/annotations/resource.proto +++ b/api/envoy/annotations/resource.proto @@ -11,6 +11,10 @@ extend google.protobuf.ServiceOptions { ResourceAnnotation resource = 265073217; } +extend google.protobuf.MessageOptions { + ResourceAnnotation resource_alias = 265073217; +} + message ResourceAnnotation { // Annotation for xDS services that indicates the fully-qualified Protobuf type for the resource // type. diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD b/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD index ccacc55735afa..cdb143507f644 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD @@ -6,6 +6,7 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ + "//envoy/annotations:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/filter/network/thrift_proxy/v2alpha1:pkg", "//envoy/config/route/v3:pkg", diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto index b79c9bc9619ea..82a03812352e8 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto @@ -7,6 +7,7 @@ import "envoy/config/route/v3/route_components.proto"; import "google/protobuf/wrappers.proto"; +import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -22,6 +23,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; message RouteConfiguration { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.thrift_proxy.v2alpha1.RouteConfiguration"; + option (envoy.annotations.resource_alias).type = "envoy.config.route.v3.RouteConfiguration"; // The name of the route configuration. Reserved for future use in asynchronous route discovery. string name = 1; diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD b/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD index 995c04093a7da..9207268c265c0 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD +++ b/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD @@ -6,6 +6,7 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ + "//envoy/annotations:pkg", "//envoy/config/core/v4alpha:pkg", "//envoy/config/route/v4alpha:pkg", "//envoy/extensions/filters/network/thrift_proxy/v3:pkg", diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto b/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto index 48caaadf2b75b..d93c774dad960 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto @@ -7,6 +7,7 @@ import "envoy/config/route/v4alpha/route_components.proto"; import "google/protobuf/wrappers.proto"; +import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -22,6 +23,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO message RouteConfiguration { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration"; + option (envoy.annotations.resource_alias).type = "envoy.config.route.v3.RouteConfiguration"; // The name of the route configuration. Reserved for future use in asynchronous route discovery. string name = 1; diff --git a/generated_api_shadow/envoy/annotations/resource.proto b/generated_api_shadow/envoy/annotations/resource.proto index b9dcf658e5226..94133e22c8a9f 100644 --- a/generated_api_shadow/envoy/annotations/resource.proto +++ b/generated_api_shadow/envoy/annotations/resource.proto @@ -9,6 +9,10 @@ extend google.protobuf.ServiceOptions { ResourceAnnotation resource = 265073217; } +extend google.protobuf.MessageOptions { + ResourceAnnotation resource_alias = 265073217; +} + message ResourceAnnotation { // Annotation for xDS services that indicates the fully-qualified Protobuf type for the resource // type. diff --git a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/route.proto b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/route.proto index b79c9bc9619ea..82a03812352e8 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/route.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v3/route.proto @@ -7,6 +7,7 @@ import "envoy/config/route/v3/route_components.proto"; import "google/protobuf/wrappers.proto"; +import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -22,6 +23,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; message RouteConfiguration { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.thrift_proxy.v2alpha1.RouteConfiguration"; + option (envoy.annotations.resource_alias).type = "envoy.config.route.v3.RouteConfiguration"; // The name of the route configuration. Reserved for future use in asynchronous route discovery. string name = 1; diff --git a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD index 995c04093a7da..9207268c265c0 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD +++ b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/BUILD @@ -6,6 +6,7 @@ licenses(["notice"]) # Apache 2 api_proto_package( deps = [ + "//envoy/annotations:pkg", "//envoy/config/core/v4alpha:pkg", "//envoy/config/route/v4alpha:pkg", "//envoy/extensions/filters/network/thrift_proxy/v3:pkg", diff --git a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto index 48caaadf2b75b..d93c774dad960 100644 --- a/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto +++ b/generated_api_shadow/envoy/extensions/filters/network/thrift_proxy/v4alpha/route.proto @@ -7,6 +7,7 @@ import "envoy/config/route/v4alpha/route_components.proto"; import "google/protobuf/wrappers.proto"; +import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -22,6 +23,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO message RouteConfiguration { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration"; + option (envoy.annotations.resource_alias).type = "envoy.config.route.v3.RouteConfiguration"; // The name of the route configuration. Reserved for future use in asynchronous route discovery. string name = 1; diff --git a/source/common/config/type_to_endpoint.cc b/source/common/config/type_to_endpoint.cc index 2ac9af5b27f54..2b9db3c883020 100644 --- a/source/common/config/type_to_endpoint.cc +++ b/source/common/config/type_to_endpoint.cc @@ -231,12 +231,35 @@ effectiveTransportApiVersion(envoy::config::core::v3::ApiVersion transport_api_v return transport_api_version; } +TypeUrlToVersionedServiceMap::iterator findVersionedService(const std::string& type_url) { + const auto it = typeUrlToVersionedServiceMap().find(type_url); + if (it != typeUrlToVersionedServiceMap().cend()) { + return it; + } + std::string message_name = type_url; + const std::string& typeUrlPrefix = Grpc::Common::typeUrlPrefix(); + if (message_name.compare(0, typeUrlPrefix.length(), typeUrlPrefix) == 0) { + if (message_name[typeUrlPrefix.length()] == '/') { + message_name.erase(0, typeUrlPrefix.length() + 1); + } + } + const auto* message_desc = + Protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(message_name); + if (message_desc != nullptr && + message_desc->options().HasExtension(envoy::annotations::resource_alias)) { + const std::string& resource = + message_desc->options().GetExtension(envoy::annotations::resource_alias).type(); + return typeUrlToVersionedServiceMap().find(Grpc::Common::typeUrl(resource)); + } + return typeUrlToVersionedServiceMap().end(); +} + } // namespace const Protobuf::MethodDescriptor& deltaGrpcMethod(absl::string_view type_url, envoy::config::core::v3::ApiVersion transport_api_version) { - const auto it = typeUrlToVersionedServiceMap().find(static_cast(type_url)); + const auto it = findVersionedService(static_cast(type_url)); ASSERT(it != typeUrlToVersionedServiceMap().cend()); return *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( it->second.delta_grpc_.methods_[effectiveTransportApiVersion(transport_api_version)]); @@ -245,7 +268,7 @@ deltaGrpcMethod(absl::string_view type_url, const Protobuf::MethodDescriptor& sotwGrpcMethod(absl::string_view type_url, envoy::config::core::v3::ApiVersion transport_api_version) { - const auto it = typeUrlToVersionedServiceMap().find(static_cast(type_url)); + const auto it = findVersionedService(static_cast(type_url)); ASSERT(it != typeUrlToVersionedServiceMap().cend()); return *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( it->second.sotw_grpc_.methods_[effectiveTransportApiVersion(transport_api_version)]); @@ -253,7 +276,7 @@ sotwGrpcMethod(absl::string_view type_url, const Protobuf::MethodDescriptor& restMethod(absl::string_view type_url, envoy::config::core::v3::ApiVersion transport_api_version) { - const auto it = typeUrlToVersionedServiceMap().find(static_cast(type_url)); + const auto it = findVersionedService(static_cast(type_url)); ASSERT(it != typeUrlToVersionedServiceMap().cend()); return *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( it->second.rest_.methods_[effectiveTransportApiVersion(transport_api_version)]); From 6506f2071c417cedc89dd6d06fa829b854a8f3a4 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sat, 21 Aug 2021 15:17:16 +0000 Subject: [PATCH 08/31] Fix merge conflict resolution, add test Signed-off-by: Tamas Kovacs --- source/common/config/type_to_endpoint.cc | 10 ++++++---- test/common/config/BUILD | 1 + test/common/config/type_to_endpoint_test.cc | 14 +++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/source/common/config/type_to_endpoint.cc b/source/common/config/type_to_endpoint.cc index 3a661aa37cd41..d1d191e97d003 100644 --- a/source/common/config/type_to_endpoint.cc +++ b/source/common/config/type_to_endpoint.cc @@ -91,8 +91,8 @@ TypeUrlToV3ServiceMap& typeUrlToV3ServiceMap() { } TypeUrlToV3ServiceMap::iterator findV3Service(const std::string& type_url) { - const auto it = TypeUrlToV3ServiceMap().find(type_url); - if (it != TypeUrlToV3ServiceMap().cend()) { + const auto it = typeUrlToV3ServiceMap().find(type_url); + if (it != typeUrlToV3ServiceMap().cend()) { return it; } std::string message_name = type_url; @@ -104,13 +104,15 @@ TypeUrlToV3ServiceMap::iterator findV3Service(const std::string& type_url) { } const auto* message_desc = Protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(message_name); + printf("XXXX %p\n", message_desc); if (message_desc != nullptr && message_desc->options().HasExtension(envoy::annotations::resource_alias)) { const std::string& resource = message_desc->options().GetExtension(envoy::annotations::resource_alias).type(); - return TypeUrlToV3ServiceMap().find(Grpc::Common::typeUrl(resource)); + printf("XXXX %s\n", resource.c_str()); + return typeUrlToV3ServiceMap().find(Grpc::Common::typeUrl(resource)); } - return TypeUrlToV3ServiceMap().end(); + return typeUrlToV3ServiceMap().end(); } } // namespace diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 7f2f20924956e..edb97a62ce787 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -357,6 +357,7 @@ envoy_cc_test( "//source/common/config:type_to_endpoint_lib", "//test/config:v2_link_hacks", "@envoy_api//envoy/api/v2:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", "@envoy_api//envoy/service/route/v3:pkg_cc_proto", ], ) diff --git a/test/common/config/type_to_endpoint_test.cc b/test/common/config/type_to_endpoint_test.cc index 0a1d877bb6131..966336780de0c 100644 --- a/test/common/config/type_to_endpoint_test.cc +++ b/test/common/config/type_to_endpoint_test.cc @@ -1,4 +1,5 @@ #include "envoy/api/v2/rds.pb.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" #include "envoy/service/route/v3/rds.pb.h" #include "source/common/config/type_to_endpoint.h" @@ -38,7 +39,6 @@ TEST(TypeToEndpoint, All) { sotwGrpcMethod("type.googleapis.com/envoy.config.route.v3.RouteConfiguration", envoy::config::core::v3::ApiVersion::V3) .full_name()); - // REST endpoints. EXPECT_EQ("envoy.service.route.v3.RouteDiscoveryService.FetchRoutes", restMethod("type.googleapis.com/envoy.config.route.v3.RouteConfiguration", @@ -50,6 +50,18 @@ TEST(TypeToEndpoint, All) { .full_name()); } +TEST(TypeToEndpoint, Alias) { + // The dummy messages are included for link purposes only. + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration _route_config_dummy; + + EXPECT_EQ( + "envoy.service.route.v3.RouteDiscoveryService.StreamRoutes", + sotwGrpcMethod( + "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", + envoy::config::core::v3::ApiVersion::V3) + .full_name()); +} + } // namespace } // namespace Config } // namespace Envoy From e9bb5140e69b0f91d5a3601d78a3e2eb965cb1d2 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sat, 21 Aug 2021 23:55:27 +0800 Subject: [PATCH 09/31] Dummy Signed-off-by: Tamas Kovacs From fbf27dc9ec8b796fbc247836aabb3b8c20b74415 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Fri, 10 Sep 2021 23:26:25 +0800 Subject: [PATCH 10/31] Template base classes for rds handling. Adding template base classes for rds handling Use base classes instead previsous copy-pasted solution in thrift. Rework existing rds implementation for http to use the new base classes. Signed-off-by: Tamas Kovacs --- envoy/router/BUILD | 9 + envoy/router/rds.h | 49 +-- envoy/router/rds/route_config_provider.h | 66 ++++ .../rds}/route_config_update_receiver.h | 31 +- envoy/router/route_config_update_receiver.h | 56 +--- source/common/router/BUILD | 20 ++ source/common/router/rds/config_factory.h | 19 ++ .../rds/rds_route_config_provider_impl.h | 86 ++++++ .../rds/rds_route_config_subscription.h | 208 +++++++++++++ .../rds/route_config_provider_manager.h | 24 ++ .../rds/route_config_provider_manager_impl.h | 127 ++++++++ .../rds/route_config_update_receiver_impl.h | 78 +++++ .../rds/static_route_config_provider_impl.h | 50 +++ source/common/router/rds_impl.cc | 285 ++++-------------- source/common/router/rds_impl.h | 152 +++------- .../route_config_update_receiver_impl.cc | 44 ++- .../route_config_update_receiver_impl.h | 42 +-- source/common/router/vhds.cc | 2 +- source/common/router/vhds.h | 5 +- .../filters/network/thrift_proxy/config.h | 1 - .../filters/network/thrift_proxy/router/BUILD | 11 +- .../filters/network/thrift_proxy/router/rds.h | 74 +++-- .../network/thrift_proxy/router/rds_impl.cc | 267 +++------------- .../network/thrift_proxy/router/rds_impl.h | 199 +----------- .../router/route_config_provider_manager.h | 70 ----- .../route_config_update_receiver_impl.cc | 42 --- .../route_config_update_receiver_impl.h | 61 ---- test/common/router/BUILD | 10 + test/common/router/rds_impl_test.cc | 13 + test/common/router/rds_template_test.cc | 157 ++++++++++ test/common/router/vhds_test.cc | 10 +- .../network/thrift_proxy/rds_impl_test.cc | 204 +------------ 32 files changed, 1149 insertions(+), 1323 deletions(-) create mode 100644 envoy/router/rds/route_config_provider.h rename {source/extensions/filters/network/thrift_proxy/router => envoy/router/rds}/route_config_update_receiver.h (65%) create mode 100644 source/common/router/rds/config_factory.h create mode 100644 source/common/router/rds/rds_route_config_provider_impl.h create mode 100644 source/common/router/rds/rds_route_config_subscription.h create mode 100644 source/common/router/rds/route_config_provider_manager.h create mode 100644 source/common/router/rds/route_config_provider_manager_impl.h create mode 100644 source/common/router/rds/route_config_update_receiver_impl.h create mode 100644 source/common/router/rds/static_route_config_provider_impl.h delete mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h delete mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc delete mode 100644 source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h create mode 100644 test/common/router/rds_template_test.cc diff --git a/envoy/router/BUILD b/envoy/router/BUILD index 86bc52bc99f04..5725ff4484e72 100644 --- a/envoy/router/BUILD +++ b/envoy/router/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( deps = [ ":router_interface", "//envoy/http:filter_interface", + "//envoy/router:rds_template_interface", "@envoy_api//envoy/config/route/v3:pkg_cc_proto", ], ) @@ -129,3 +130,11 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", ], ) + +envoy_cc_library( + name = "rds_template_interface", + hdrs = [ + "rds/route_config_provider.h", + "rds/route_config_update_receiver.h", + ], +) diff --git a/envoy/router/rds.h b/envoy/router/rds.h index 486a95050f9e8..d2702923069c5 100644 --- a/envoy/router/rds.h +++ b/envoy/router/rds.h @@ -4,58 +4,15 @@ #include "envoy/config/route/v3/route.pb.h" #include "envoy/http/filter.h" +#include "envoy/router/rds/route_config_provider.h" #include "envoy/router/router.h" namespace Envoy { namespace Router { -/** - * A provider for constant route configurations. - */ -class RouteConfigProvider { +class RouteConfigProvider + : public Rds::RouteConfigProvider { public: - struct ConfigInfo { - // A reference to the currently loaded route configuration. Do not hold this reference beyond - // the caller of configInfo()'s scope. - const envoy::config::route::v3::RouteConfiguration& config_; - - // The discovery version that supplied this route. This will be set to "" in the case of - // static clusters. - std::string version_; - }; - - virtual ~RouteConfigProvider() = default; - - /** - * @return Router::ConfigConstSharedPtr a route configuration for use during a single request. The - * returned config may be different on a subsequent call, so a new config should be acquired for - * each request flow. - */ - virtual Router::ConfigConstSharedPtr config() PURE; - - /** - * @return the configuration information for the currently loaded route configuration. Note that - * if the provider has not yet performed an initial configuration load, no information will be - * returned. - */ - virtual absl::optional configInfo() const PURE; - - /** - * @return the last time this RouteConfigProvider was updated. Used for config dumps. - */ - virtual SystemTime lastUpdated() const PURE; - - /** - * Callback used to notify RouteConfigProvider about configuration changes. - */ - virtual void onConfigUpdate() PURE; - - /** - * Validate if the route configuration can be applied to the context of the route config provider. - */ - virtual void - validateConfig(const envoy::config::route::v3::RouteConfiguration& config) const PURE; - /** * Callback used to request an update to the route configuration from the management server. * @param for_domain supplies the domain name that virtual hosts must match on diff --git a/envoy/router/rds/route_config_provider.h b/envoy/router/rds/route_config_provider.h new file mode 100644 index 0000000000000..b2808e1386b67 --- /dev/null +++ b/envoy/router/rds/route_config_provider.h @@ -0,0 +1,66 @@ +#pragma once + +#include + +#include "envoy/common/time.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +/** + * A provider for constant route configurations. + */ +template class RouteConfigProvider { +public: + struct ConfigInfo { + // A reference to the currently loaded route configuration. Do not hold this reference beyond + // the caller of configInfo()'s scope. + const RouteConfiguration& config_; + + // The discovery version that supplied this route. This will be set to "" in the case of + // static clusters. + std::string version_; + }; + + virtual ~RouteConfigProvider() = default; + + /** + * @return Router::ConfigConstSharedPtr a route configuration for use during a single request. The + * returned config may be different on a subsequent call, so a new config should be acquired for + * each request flow. + */ + virtual std::shared_ptr config() PURE; + + /** + * @return the configuration information for the currently loaded route configuration. Note that + * if the provider has not yet performed an initial configuration load, no information will be + * returned. + */ + virtual absl::optional configInfo() const PURE; + + /** + * @return the last time this RouteConfigProvider was updated. Used for config dumps. + */ + virtual SystemTime lastUpdated() const PURE; + + /** + * Callback used to notify RouteConfigProvider about configuration changes. + */ + virtual void onConfigUpdate() PURE; + + /** + * Validate if the route configuration can be applied to the context of the route config provider. + */ + virtual void validateConfig(const RouteConfiguration& config) const PURE; +}; + +template +using RouteConfigProviderPtr = std::unique_ptr>; +template +using RouteConfigProviderSharedPtr = + std::shared_ptr>; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h b/envoy/router/rds/route_config_update_receiver.h similarity index 65% rename from source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h rename to envoy/router/rds/route_config_update_receiver.h index a2108c5e24d85..cd780605faba4 100644 --- a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h +++ b/envoy/router/rds/route_config_update_receiver.h @@ -4,24 +4,18 @@ #include "envoy/common/pure.h" #include "envoy/common/time.h" -#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" -#include "envoy/service/discovery/v3/discovery.pb.h" - -#include "source/common/protobuf/protobuf.h" -#include "source/extensions/filters/network/thrift_proxy/router/rds.h" +#include "envoy/router/rds/route_config_provider.h" #include "absl/types/optional.h" namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace ThriftProxy { namespace Router { +namespace Rds { /** * A primitive that keeps track of updates to a RouteConfiguration. */ -class RouteConfigUpdateReceiver { +template class RouteConfigUpdateReceiver { public: virtual ~RouteConfigUpdateReceiver() = default; @@ -31,9 +25,7 @@ class RouteConfigUpdateReceiver { * @param version_info supplies RouteConfiguration version. * @return bool whether RouteConfiguration has been updated. */ - virtual bool - onRdsUpdate(const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc, - const std::string& version_info) PURE; + virtual bool onRdsUpdate(const RouteConfiguration& rc, const std::string& version_info) PURE; /** * @return std::string& the name of RouteConfiguration. @@ -55,19 +47,19 @@ class RouteConfigUpdateReceiver { * RouteConfigProvider::ConfigInfo if RouteConfiguration has been updated at least once. Otherwise * returns an empty absl::optional. */ - virtual absl::optional configInfo() const PURE; + virtual absl::optional::ConfigInfo> + configInfo() const PURE; /** * @return envoy::config::route::v3::RouteConfiguration& current RouteConfiguration. */ - virtual const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& - protobufConfiguration() PURE; + virtual const RouteConfiguration& protobufConfiguration() PURE; /** * @return Router::ConfigConstSharedPtr a parsed and validated copy of current RouteConfiguration. * @see protobufConfiguration() */ - virtual ConfigConstSharedPtr parsedConfiguration() const PURE; + virtual std::shared_ptr parsedConfiguration() const PURE; /** * @return SystemTime the time of the last update. @@ -75,10 +67,9 @@ class RouteConfigUpdateReceiver { virtual SystemTime lastUpdated() const PURE; }; -using RouteConfigUpdatePtr = std::unique_ptr; +template +using RouteConfigUpdatePtr = std::unique_ptr>; +} // namespace Rds } // namespace Router -} // namespace ThriftProxy -} // namespace NetworkFilters -} // namespace Extensions } // namespace Envoy diff --git a/envoy/router/route_config_update_receiver.h b/envoy/router/route_config_update_receiver.h index 13ab7c45cefb5..79fb5328ae8a3 100644 --- a/envoy/router/route_config_update_receiver.h +++ b/envoy/router/route_config_update_receiver.h @@ -6,6 +6,7 @@ #include "envoy/common/time.h" #include "envoy/config/route/v3/route.pb.h" #include "envoy/router/rds.h" +#include "envoy/router/rds/route_config_update_receiver.h" #include "envoy/service/discovery/v3/discovery.pb.h" #include "source/common/protobuf/protobuf.h" @@ -15,22 +16,9 @@ namespace Envoy { namespace Router { -/** - * A primitive that keeps track of updates to a RouteConfiguration. - */ -class RouteConfigUpdateReceiver { +class RouteConfigUpdateReceiver + : public Rds::RouteConfigUpdateReceiver { public: - virtual ~RouteConfigUpdateReceiver() = default; - - /** - * Called on updates via RDS. - * @param rc supplies the RouteConfiguration. - * @param version_info supplies RouteConfiguration version. - * @return bool whether RouteConfiguration has been updated. - */ - virtual bool onRdsUpdate(const envoy::config::route::v3::RouteConfiguration& rc, - const std::string& version_info) PURE; - using VirtualHostRefVector = std::vector>; @@ -47,16 +35,6 @@ class RouteConfigUpdateReceiver { const Protobuf::RepeatedPtrField& removed_resources, const std::string& version_info) PURE; - /** - * @return std::string& the name of RouteConfiguration. - */ - virtual const std::string& routeConfigName() const PURE; - - /** - * @return std::string& the version of RouteConfiguration. - */ - virtual const std::string& configVersion() const PURE; - /** * @return bool return whether VHDS configuration has been changed in the last RDS update. */ @@ -65,34 +43,6 @@ class RouteConfigUpdateReceiver { // intent and the lifecycle of the "last update state" less muddled. virtual bool vhdsConfigurationChanged() const PURE; - /** - * @return uint64_t the hash value of RouteConfiguration. - */ - virtual uint64_t configHash() const PURE; - - /** - * @return absl::optional containing an instance of - * RouteConfigProvider::ConfigInfo if RouteConfiguration has been updated at least once. Otherwise - * returns an empty absl::optional. - */ - virtual absl::optional configInfo() const PURE; - - /** - * @return envoy::config::route::v3::RouteConfiguration& current RouteConfiguration. - */ - virtual const envoy::config::route::v3::RouteConfiguration& protobufConfiguration() PURE; - - /** - * @return Router::ConfigConstSharedPtr a parsed and validated copy of current RouteConfiguration. - * @see protobufConfiguration() - */ - virtual ConfigConstSharedPtr parsedConfiguration() const PURE; - - /** - * @return SystemTime the time of the last update. - */ - virtual SystemTime lastUpdated() const PURE; - /** * @return the union of all resource names and aliases (if any) received with the last VHDS * update. diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 4e0bbe9145706..8c7ce4f820d03 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -125,6 +125,7 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", "//source/common/protobuf:utility_lib", + "//source/common/router:rds_template_lib", "@envoy_api//envoy/config/route/v3:pkg_cc_proto", "@envoy_api//envoy/service/discovery/v3:pkg_cc_proto", ], @@ -185,6 +186,7 @@ envoy_cc_library( "//source/common/init:target_lib", "//source/common/init:watcher_lib", "//source/common/protobuf:utility_lib", + "//source/common/router:rds_template_lib", "//source/common/router:route_config_update_impl_lib", "//source/common/router:vhds_lib", "@envoy_api//envoy/admin/v3:pkg_cc_proto", @@ -421,3 +423,21 @@ envoy_cc_library( "//envoy/router:router_interface", ], ) + +envoy_cc_library( + name = "rds_template_lib", + hdrs = [ + "rds/config_factory.h", + "rds/rds_route_config_provider_impl.h", + "rds/rds_route_config_subscription.h", + "rds/route_config_provider_manager.h", + "rds/route_config_provider_manager_impl.h", + "rds/route_config_update_receiver_impl.h", + "rds/static_route_config_provider_impl.h", + ], + deps = [ + "//envoy/router:rds_template_interface", + "@envoy_api//envoy/admin/v3:pkg_cc_proto", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) diff --git a/source/common/router/rds/config_factory.h b/source/common/router/rds/config_factory.h new file mode 100644 index 0000000000000..56ecea8f10da4 --- /dev/null +++ b/source/common/router/rds/config_factory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "envoy/common/pure.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +template class ConfigFactory { +public: + virtual ~ConfigFactory() = default; + + virtual std::shared_ptr createConfig(const RouteConfiguration& rc) const PURE; + virtual std::shared_ptr createConfig() const PURE; +}; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds/rds_route_config_provider_impl.h b/source/common/router/rds/rds_route_config_provider_impl.h new file mode 100644 index 0000000000000..2da071a569402 --- /dev/null +++ b/source/common/router/rds/rds_route_config_provider_impl.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include + +#include "envoy/router/rds/route_config_provider.h" +#include "envoy/router/rds/route_config_update_receiver.h" +#include "envoy/server/factory_context.h" +#include "envoy/thread_local/thread_local.h" + +#include "source/common/common/logger.h" +#include "source/common/router/rds/config_factory.h" +#include "source/common/router/rds/rds_route_config_subscription.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +/** + * Implementation of RouteConfigProvider that fetches the route configuration dynamically using + * the subscription. + */ +template +class RdsRouteConfigProviderImpl : public RouteConfigProvider, + Logger::Loggable { +public: + RdsRouteConfigProviderImpl( + RdsRouteConfigSubscriptionSharedPtr&& subscription, + Server::Configuration::ServerFactoryContext& factory_context, + ConfigFactory& config_factory) + : subscription_(std::move(subscription)), + config_update_info_(subscription_->routeConfigUpdate()), + tls_(factory_context.threadLocal()) { + + std::shared_ptr initial_config; + if (config_update_info_->configInfo().has_value()) { + initial_config = + config_factory.createConfig(subscription->routeConfigUpdate()->protobufConfiguration()); + } else { + initial_config = config_factory.createConfig(); + } + + tls_.set([initial_config](Event::Dispatcher&) { + return std::make_shared(initial_config); + }); + // It should be 1:1 mapping due to shared rds config. + ASSERT(!subscription_->routeConfigProvider().has_value()); + subscription_->routeConfigProvider().emplace(this); + } + + ~RdsRouteConfigProviderImpl() override { + ASSERT(subscription_->routeConfigProvider().has_value()); + subscription_->routeConfigProvider().reset(); + } + + RdsRouteConfigSubscription& subscription() { return *subscription_; } + + // Rds::RouteConfigProvider + std::shared_ptr config() override { return tls_->config_; } + + absl::optional::ConfigInfo> + configInfo() const override { + return config_update_info_->configInfo(); + } + SystemTime lastUpdated() const override { return config_update_info_->lastUpdated(); } + void onConfigUpdate() override { + tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( + OptRef tls) { tls->config_ = new_config; }); + } + void validateConfig(const RouteConfiguration&) const override {} + +private: + struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { + ThreadLocalConfig(std::shared_ptr initial_config) + : config_(std::move(initial_config)) {} + std::shared_ptr config_; + }; + + RdsRouteConfigSubscriptionSharedPtr subscription_; + RouteConfigUpdatePtr& config_update_info_; + ThreadLocal::TypedSlot tls_; +}; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds/rds_route_config_subscription.h b/source/common/router/rds/rds_route_config_subscription.h new file mode 100644 index 0000000000000..8c2b98b88453f --- /dev/null +++ b/source/common/router/rds/rds_route_config_subscription.h @@ -0,0 +1,208 @@ +#pragma once + +#include +#include + +#include "envoy/config/core/v3/config_source.pb.h" +#include "envoy/router/rds/route_config_provider.h" +#include "envoy/router/rds/route_config_update_receiver.h" +#include "envoy/server/factory_context.h" +#include "envoy/stats/scope.h" + +#include "source/common/common/logger.h" +#include "source/common/config/subscription_base.h" +#include "source/common/grpc/common.h" +#include "source/common/init/manager_impl.h" +#include "source/common/init/target_impl.h" +#include "source/common/init/watcher_impl.h" +#include "source/common/router/rds/route_config_provider_manager.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +/** + * All RDS stats. @see stats_macros.h + */ +#define ALL_RDS_STATS(COUNTER, GAUGE) \ + COUNTER(config_reload) \ + COUNTER(update_empty) \ + GAUGE(config_reload_time_ms, NeverImport) + +/** + * Struct definition for all RDS stats. @see stats_macros.h + */ +struct RdsStats { + ALL_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) +}; + +/** + * A class that fetches the route configuration dynamically using the RDS API and updates them to + * RDS config providers. + */ +template +class RdsRouteConfigSubscription : Envoy::Config::SubscriptionBase, + protected Logger::Loggable { +public: + RdsRouteConfigSubscription( + RouteConfigUpdatePtr&& config_update, + const envoy::config::core::v3::ConfigSource& config_source, + const std::string& route_config_name, const uint64_t manager_identifier, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + RouteConfigProviderManager& route_config_provider_manager) + : Envoy::Config::SubscriptionBase( + factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), + route_config_name_(route_config_name), + scope_( + factory_context.scope().createScope(stat_prefix + "rds." + route_config_name_ + ".")), + factory_context_(factory_context), + parent_init_target_(fmt::format("RdsRouteConfigSubscription init {}", route_config_name_), + [this]() { local_init_manager_.initialize(local_init_watcher_); }), + local_init_watcher_(fmt::format("RDS local-init-watcher {}", route_config_name_), + [this]() { parent_init_target_.ready(); }), + local_init_target_( + fmt::format("RdsRouteConfigSubscription local-init-target {}", route_config_name_), + [this]() { subscription_->start({route_config_name_}); }), + local_init_manager_(fmt::format("RDS local-init-manager {}", route_config_name_)), + stat_prefix_(stat_prefix), + stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}), + route_config_provider_manager_(route_config_provider_manager), + manager_identifier_(manager_identifier), config_update_info_(std::move(config_update)) { + const auto resource_name = + Envoy::Config::SubscriptionBase::getResourceName(); + subscription_ = + factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( + config_source, Envoy::Grpc::Common::typeUrl(resource_name), *scope_, *this, + Envoy::Config::SubscriptionBase::resource_decoder_, {}); + local_init_manager_.add(local_init_target_); + } + + ~RdsRouteConfigSubscription() override { + // If we get destroyed during initialization, make sure we signal that we "initialized". + local_init_target_.ready(); + + // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that + // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the + // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get + // cleaned by the RdsRouteConfigProvider's destructor. + route_config_provider_manager_.eraseDynamicProvider(manager_identifier_); + } + + absl::optional*>& routeConfigProvider() { + return route_config_provider_opt_; + } + RouteConfigUpdatePtr& routeConfigUpdate() { + return config_update_info_; + } + + const Init::Target& initTarget() { return parent_init_target_; } + +private: + // Config::SubscriptionCallbacks + void onConfigUpdate(const std::vector& resources, + const std::string& version_info) override { + if (!validateUpdateSize(resources.size())) { + return; + } + const auto& route_config = + dynamic_cast(resources[0].get().resource()); + if (route_config.name() != route_config_name_) { + // check_format.py complains about throw, dummy comment helps to ignore + /**/ throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}", + route_config_name_, route_config.name())); + } + if (route_config_provider_opt_.has_value()) { + route_config_provider_opt_.value()->validateConfig(route_config); + } + if (config_update_info_->onRdsUpdate(route_config, version_info)) { + stats_.config_reload_.inc(); + stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); + + beforeProviderUpdate(); + + ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_, + config_update_info_->configHash()); + + if (route_config_provider_opt_.has_value()) { + route_config_provider_opt_.value()->onConfigUpdate(); + } + + afterProviderUpdate(); + } + + local_init_target_.ready(); + } + + void onConfigUpdate(const std::vector& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string&) override { + if (!removed_resources.empty()) { + // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense + // (see discussion in #6879), and so we should do something other than ignoring here. + ENVOY_LOG( + error, + "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", + removed_resources[0]); + } + if (!added_resources.empty()) { + onConfigUpdate(added_resources, added_resources[0].get().version()); + } + } + + void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, + const EnvoyException*) override { + ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason); + // We need to allow server startup to continue, even if we have a bad + // config. + local_init_target_.ready(); + } + + bool validateUpdateSize(int num_resources) { + if (num_resources == 0) { + ENVOY_LOG(debug, "Missing RouteConfiguration for {} in onConfigUpdate()", route_config_name_); + stats_.update_empty_.inc(); + local_init_target_.ready(); + return false; + } + if (num_resources != 1) { + /**/ throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", num_resources)); + // (would be a return false here) + } + return true; + } + + virtual void beforeProviderUpdate() {} + virtual void afterProviderUpdate() {} + +protected: + const std::string route_config_name_; + // This scope must outlive the subscription_ below as the subscription has derived stats. + Stats::ScopePtr scope_; + Envoy::Config::SubscriptionPtr subscription_; + Server::Configuration::ServerFactoryContext& factory_context_; + + // Init target used to notify the parent init manager that the subscription [and its sub resource] + // is ready. + Init::SharedTargetImpl parent_init_target_; + // Init watcher on RDS and VHDS ready event. This watcher marks parent_init_target_ ready. + Init::WatcherImpl local_init_watcher_; + // Target which starts the RDS subscription. + Init::TargetImpl local_init_target_; + Init::ManagerImpl local_init_manager_; + std::string stat_prefix_; + RdsStats stats_; + RouteConfigProviderManager& route_config_provider_manager_; + const uint64_t manager_identifier_; + absl::optional*> route_config_provider_opt_; + RouteConfigUpdatePtr config_update_info_; +}; + +template +using RdsRouteConfigSubscriptionSharedPtr = + std::shared_ptr>; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds/route_config_provider_manager.h b/source/common/router/rds/route_config_provider_manager.h new file mode 100644 index 0000000000000..81e0909d5ae87 --- /dev/null +++ b/source/common/router/rds/route_config_provider_manager.h @@ -0,0 +1,24 @@ +#pragma once + +#include "envoy/router/rds/route_config_provider.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +/** + * The RouteConfigProviderManager exposes the ability to get a RouteConfigProvider. This interface + * is exposed to the Server's FactoryContext in order to allow HttpConnectionManagers to get + * RouteConfigProviders. + */ +template class RouteConfigProviderManager { +public: + virtual ~RouteConfigProviderManager() = default; + + virtual void eraseStaticProvider(RouteConfigProvider* provider) PURE; + virtual void eraseDynamicProvider(int64_t manager_identifier) PURE; +}; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds/route_config_provider_manager_impl.h b/source/common/router/rds/route_config_provider_manager_impl.h new file mode 100644 index 0000000000000..bb51f5dadd0ae --- /dev/null +++ b/source/common/router/rds/route_config_provider_manager_impl.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include + +#include "envoy/admin/v3/config_dump.pb.h" +#include "envoy/init/manager.h" +#include "envoy/init/target.h" +#include "envoy/server/admin.h" + +#include "source/common/common/matchers.h" +#include "source/common/protobuf/utility.h" +#include "source/common/router/rds/route_config_provider_manager.h" + +#include "absl/container/node_hash_map.h" +#include "absl/container/node_hash_set.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +template +class RouteConfigProviderManagerImpl + : public RouteConfigProviderManager { +public: + RouteConfigProviderManagerImpl(Server::Admin& admin) { + config_tracker_entry_ = + admin.getConfigTracker().add("routes", [this](const Matchers::StringMatcher& matcher) { + return dumpRouteConfigs(matcher); + }); + // ConfigTracker keys must be unique. We are asserting that no one has stolen the "routes" key + // from us, since the returned entry will be nullptr if the key already exists. + RELEASE_ASSERT(config_tracker_entry_, ""); + } + + void eraseStaticProvider(RouteConfigProvider* provider) override { + static_route_config_providers_.erase(provider); + } + + void eraseDynamicProvider(int64_t manager_identifier) override { + dynamic_route_config_providers_.erase(manager_identifier); + } + + std::unique_ptr + dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const { + auto config_dump = std::make_unique(); + + for (const auto& element : dynamic_route_config_providers_) { + const auto provider = element.second.first.lock(); + // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up + // in the RdsRouteConfigSubscription destructor, and the single threaded nature + // of this code, locking the weak_ptr will not fail. + ASSERT(provider); + + if (provider->configInfo()) { + if (!name_matcher.match(provider->configInfo().value().config_.name())) { + continue; + } + auto* dynamic_config = config_dump->mutable_dynamic_route_configs()->Add(); + dynamic_config->set_version_info(provider->configInfo().value().version_); + dynamic_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); + TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), + *dynamic_config->mutable_last_updated()); + } + } + + for (const auto& provider : static_route_config_providers_) { + ASSERT(provider->configInfo()); + if (!name_matcher.match(provider->configInfo().value().config_.name())) { + continue; + } + auto* static_config = config_dump->mutable_static_route_configs()->Add(); + static_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); + TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), + *static_config->mutable_last_updated()); + } + + return config_dump; + } + +protected: + void insertStaticProvider(RouteConfigProvider* provider) { + static_route_config_providers_.insert(provider); + } + + void insertDynamicProvider(int64_t manager_identifier, + RouteConfigProviderSharedPtr provider, + const Init::Target* init_target) { + dynamic_route_config_providers_.insert( + {manager_identifier, + std::make_pair(std::weak_ptr>(provider), + init_target)}); + } + + RouteConfigProviderSharedPtr + reuseDynamicProvider(uint64_t manager_identifier, Init::Manager& init_manager, + const std::string& route_config_name) { + auto it = dynamic_route_config_providers_.find(manager_identifier); + if (it == dynamic_route_config_providers_.end()) { + return RouteConfigProviderSharedPtr(); + } + // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up + // in the RdsRouteConfigSubscription destructor, and the single threaded nature + // of this code, locking the weak_ptr will not fail. + auto existing_provider = it->second.first.lock(); + RELEASE_ASSERT(existing_provider != nullptr, + absl::StrCat("cannot find subscribed rds resource ", route_config_name)); + init_manager.add(*it->second.second); + return existing_provider; + } + +private: + // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map + // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists + // Then the lifetime management stuff is centralized and opaque. + absl::node_hash_map>, + const Init::Target*>> + dynamic_route_config_providers_; + absl::node_hash_set*> + static_route_config_providers_; + Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; +}; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds/route_config_update_receiver_impl.h b/source/common/router/rds/route_config_update_receiver_impl.h new file mode 100644 index 0000000000000..56e7903632652 --- /dev/null +++ b/source/common/router/rds/route_config_update_receiver_impl.h @@ -0,0 +1,78 @@ +#pragma once + +#include + +#include "envoy/router/rds/route_config_update_receiver.h" +#include "envoy/server/factory_context.h" + +#include "source/common/router/rds/config_factory.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +template +class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { +public: + RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context, + ConfigFactory& config_factory) + : time_source_(factory_context.timeSource()), + route_config_proto_(std::make_unique()), last_config_hash_(0ull), + config_factory_(config_factory) {} + + bool updateHash(const RouteConfiguration& rc) { + const uint64_t new_hash = MessageUtil::hash(rc); + if (new_hash == last_config_hash_) { + return false; + } + last_config_hash_ = new_hash; + return true; + } + + void updateConfig(std::unique_ptr&& route_config_proto) { + route_config_proto_ = std::move(route_config_proto); + config_ = config_factory_.createConfig(*route_config_proto_); + } + + void onUpdateCommon(const std::string& version_info) { + last_config_version_ = version_info; + last_updated_ = time_source_.systemTime(); + config_info_.emplace(typename RouteConfigProvider::ConfigInfo{ + *route_config_proto_, last_config_version_}); + } + + // Rds::RouteConfigUpdateReceiver + bool onRdsUpdate(const RouteConfiguration& rc, const std::string& version_info) override { + if (!updateHash(rc)) { + return false; + } + updateConfig(std::make_unique(rc)); + onUpdateCommon(version_info); + return true; + } + + const std::string& routeConfigName() const override { return route_config_proto_->name(); } + const std::string& configVersion() const override { return last_config_version_; } + uint64_t configHash() const override { return last_config_hash_; } + absl::optional::ConfigInfo> + configInfo() const override { + return config_info_; + } + const RouteConfiguration& protobufConfiguration() override { return *route_config_proto_; } + std::shared_ptr parsedConfiguration() const override { return config_; } + SystemTime lastUpdated() const override { return last_updated_; } + +private: + TimeSource& time_source_; + std::unique_ptr route_config_proto_; + uint64_t last_config_hash_; + std::string last_config_version_; + SystemTime last_updated_; + absl::optional::ConfigInfo> config_info_; + std::shared_ptr config_; + ConfigFactory& config_factory_; +}; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds/static_route_config_provider_impl.h b/source/common/router/rds/static_route_config_provider_impl.h new file mode 100644 index 0000000000000..58a0b9c8ae88f --- /dev/null +++ b/source/common/router/rds/static_route_config_provider_impl.h @@ -0,0 +1,50 @@ +#pragma once + +#include "envoy/router/rds/route_config_provider.h" +#include "envoy/server/factory_context.h" + +#include "source/common/router/rds/route_config_provider_manager.h" + +namespace Envoy { +namespace Router { +namespace Rds { + +/** + * Implementation of RouteConfigProvider that holds a static route configuration. + */ +template +class StaticRouteConfigProviderImpl : public RouteConfigProvider { +public: + StaticRouteConfigProviderImpl( + std::shared_ptr config, const RouteConfiguration& route_config_proto, + Server::Configuration::ServerFactoryContext& factory_context, + RouteConfigProviderManager& route_config_provider_manager) + : config_(config), route_config_proto_{route_config_proto}, + last_updated_(factory_context.timeSource().systemTime()), + route_config_provider_manager_(route_config_provider_manager) {} + + ~StaticRouteConfigProviderImpl() override { + route_config_provider_manager_.eraseStaticProvider(this); + } + + // Router::RouteConfigProvider + std::shared_ptr config() override { return config_; } + absl::optional::ConfigInfo> + configInfo() const override { + return typename RouteConfigProvider::ConfigInfo{route_config_proto_, + ""}; + } + SystemTime lastUpdated() const override { return last_updated_; } + void onConfigUpdate() override {} + void validateConfig(const RouteConfiguration&) const override {} + +private: + std::shared_ptr config_; + RouteConfiguration route_config_proto_; + SystemTime last_updated_; + RouteConfigProviderManager& route_config_provider_manager_; +}; + +} // namespace Rds +} // namespace Router +} // namespace Envoy diff --git a/source/common/router/rds_impl.cc b/source/common/router/rds_impl.cc index 62f47d9221a11..26d4ed3020046 100644 --- a/source/common/router/rds_impl.cc +++ b/source/common/router/rds_impl.cc @@ -17,6 +17,7 @@ #include "source/common/http/header_map_impl.h" #include "source/common/protobuf/utility.h" #include "source/common/router/config_impl.h" +#include "source/common/router/route_config_update_receiver_impl.h" namespace Envoy { namespace Router { @@ -56,108 +57,49 @@ StaticRouteConfigProviderImpl::StaticRouteConfigProviderImpl( Server::Configuration::ServerFactoryContext& factory_context, ProtobufMessage::ValidationVisitor& validator, RouteConfigProviderManagerImpl& route_config_provider_manager) - : config_(new ConfigImpl(config, optional_http_filters, factory_context, validator, true)), - route_config_proto_{config}, last_updated_(factory_context.timeSource().systemTime()), - route_config_provider_manager_(route_config_provider_manager) { - route_config_provider_manager_.static_route_config_providers_.insert(this); -} + : base_(std::make_shared(config, optional_http_filters, factory_context, validator, + true), + config, factory_context, route_config_provider_manager), + route_config_provider_manager_(route_config_provider_manager) {} StaticRouteConfigProviderImpl::~StaticRouteConfigProviderImpl() { - route_config_provider_manager_.static_route_config_providers_.erase(this); + route_config_provider_manager_.eraseStaticProvider(this); } // TODO(htuch): If support for multiple clusters is added per #1170 cluster_name_ RdsRouteConfigSubscription::RdsRouteConfigSubscription( + RouteConfigUpdateReceiver* config_update, const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, const uint64_t manager_identifier, Server::Configuration::ServerFactoryContext& factory_context, - const std::string& stat_prefix, const OptionalHttpFilters& optional_http_filters, - Envoy::Router::RouteConfigProviderManagerImpl& route_config_provider_manager) - : Envoy::Config::SubscriptionBase( - factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), - route_config_name_(rds.route_config_name()), - scope_(factory_context.scope().createScope(stat_prefix + "rds." + route_config_name_ + ".")), - factory_context_(factory_context), - parent_init_target_(fmt::format("RdsRouteConfigSubscription init {}", route_config_name_), - [this]() { local_init_manager_.initialize(local_init_watcher_); }), - local_init_watcher_(fmt::format("RDS local-init-watcher {}", rds.route_config_name()), - [this]() { parent_init_target_.ready(); }), - local_init_target_( - fmt::format("RdsRouteConfigSubscription local-init-target {}", route_config_name_), - [this]() { subscription_->start({route_config_name_}); }), - local_init_manager_(fmt::format("RDS local-init-manager {}", route_config_name_)), - stat_prefix_(stat_prefix), - stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}), - route_config_provider_manager_(route_config_provider_manager), - manager_identifier_(manager_identifier), optional_http_filters_(optional_http_filters) { - const auto resource_name = getResourceName(); - subscription_ = - factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( - rds.config_source(), Grpc::Common::typeUrl(resource_name), *scope_, *this, - resource_decoder_, {}); - local_init_manager_.add(local_init_target_); - config_update_info_ = - std::make_unique(factory_context, optional_http_filters_); -} - -RdsRouteConfigSubscription::~RdsRouteConfigSubscription() { - // If we get destroyed during initialization, make sure we signal that we "initialized". - local_init_target_.ready(); - - // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that - // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the - // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get - // cleaned by the RdsRouteConfigProvider's destructor. - route_config_provider_manager_.dynamic_route_config_providers_.erase(manager_identifier_); -} - -void RdsRouteConfigSubscription::onConfigUpdate( - const std::vector& resources, - const std::string& version_info) { - if (!validateUpdateSize(resources.size())) { - return; - } - const auto& route_config = dynamic_cast( - resources[0].get().resource()); - if (route_config.name() != route_config_name_) { - throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}", - route_config_name_, route_config.name())); - } - if (route_config_provider_opt_.has_value()) { - route_config_provider_opt_.value()->validateConfig(route_config); + const std::string& stat_prefix, RouteConfigProviderManagerImpl& route_config_provider_manager) + : Rds::RdsRouteConfigSubscription( + RouteConfigUpdatePtr(config_update), rds.config_source(), rds.route_config_name(), + manager_identifier, factory_context, stat_prefix, route_config_provider_manager), + config_update_info_(config_update) {} + +void RdsRouteConfigSubscription::beforeProviderUpdate() { + if (config_update_info_->protobufConfiguration().has_vhds() && + config_update_info_->vhdsConfigurationChanged()) { + std::unique_ptr noop_init_manager; + std::unique_ptr resume_rds; + ENVOY_LOG(debug, + "rds: vhds configuration present/changed, (re)starting vhds: config_name={} hash={}", + route_config_name_, config_update_info_->configHash()); + maybeCreateInitManager(config_update_info_->configVersion(), noop_init_manager, resume_rds); + vhds_subscription_ = std::make_unique( + config_update_info_, factory_context_, stat_prefix_, route_config_provider_opt_); + vhds_subscription_->registerInitTargetWithInitManager( + noop_init_manager == nullptr ? local_init_manager_ : *noop_init_manager); } - std::unique_ptr noop_init_manager; - std::unique_ptr resume_rds; - if (config_update_info_->onRdsUpdate(route_config, version_info)) { - stats_.config_reload_.inc(); - stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); - if (config_update_info_->protobufConfiguration().has_vhds() && - config_update_info_->vhdsConfigurationChanged()) { - ENVOY_LOG( - debug, - "rds: vhds configuration present/changed, (re)starting vhds: config_name={} hash={}", - route_config_name_, config_update_info_->configHash()); - maybeCreateInitManager(version_info, noop_init_manager, resume_rds); - vhds_subscription_ = std::make_unique( - config_update_info_, factory_context_, stat_prefix_, route_config_provider_opt_); - vhds_subscription_->registerInitTargetWithInitManager( - noop_init_manager == nullptr ? local_init_manager_ : *noop_init_manager); - } - - ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_, - config_update_info_->configHash()); - - if (route_config_provider_opt_.has_value()) { - route_config_provider_opt_.value()->onConfigUpdate(); - } - // RDS update removed VHDS configuration - if (!config_update_info_->protobufConfiguration().has_vhds()) { - vhds_subscription_.release(); - } +} - update_callback_manager_.runCallbacks(); +void RdsRouteConfigSubscription::afterProviderUpdate() { + // RDS update removed VHDS configuration + if (!config_update_info_->protobufConfiguration().has_vhds()) { + vhds_subscription_.release(); } - local_init_target_.ready(); + update_callback_manager_.runCallbacks(); } // Initialize a no-op InitManager in case the one in the factory_context has completed @@ -181,30 +123,6 @@ void RdsRouteConfigSubscription::maybeCreateInitManager( } } -void RdsRouteConfigSubscription::onConfigUpdate( - const std::vector& added_resources, - const Protobuf::RepeatedPtrField& removed_resources, const std::string&) { - if (!removed_resources.empty()) { - // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense - // (see discussion in #6879), and so we should do something other than ignoring here. - ENVOY_LOG( - error, - "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", - removed_resources[0]); - } - if (!added_resources.empty()) { - onConfigUpdate(added_resources, added_resources[0].get().version()); - } -} - -void RdsRouteConfigSubscription::onConfigUpdateFailed( - Envoy::Config::ConfigUpdateFailureReason reason, const EnvoyException*) { - ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason); - // We need to allow server startup to continue, even if we have a bad - // config. - local_init_target_.ready(); -} - void RdsRouteConfigSubscription::updateOnDemand(const std::string& aliases) { if (vhds_subscription_.get() == nullptr) { return; @@ -212,41 +130,13 @@ void RdsRouteConfigSubscription::updateOnDemand(const std::string& aliases) { vhds_subscription_->updateOnDemand(aliases); } -bool RdsRouteConfigSubscription::validateUpdateSize(int num_resources) { - if (num_resources == 0) { - ENVOY_LOG(debug, "Missing RouteConfiguration for {} in onConfigUpdate()", route_config_name_); - stats_.update_empty_.inc(); - local_init_target_.ready(); - return false; - } - if (num_resources != 1) { - throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", num_resources)); - // (would be a return false here) - } - return true; -} - RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( - RdsRouteConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::ServerFactoryContext& factory_context, - const OptionalHttpFilters& optional_http_filters) - : subscription_(std::move(subscription)), - config_update_info_(subscription_->routeConfigUpdate()), factory_context_(factory_context), - validator_(factory_context.messageValidationContext().dynamicValidationVisitor()), - tls_(factory_context.threadLocal()), optional_http_filters_(optional_http_filters) { - ConfigConstSharedPtr initial_config; - if (config_update_info_->configInfo().has_value()) { - initial_config = - std::make_shared(config_update_info_->protobufConfiguration(), - optional_http_filters_, factory_context_, validator_, false); - } else { - initial_config = std::make_shared(); - } - tls_.set([initial_config](Event::Dispatcher&) { - return std::make_shared(initial_config); - }); - // It should be 1:1 mapping due to shared rds config. - ASSERT(!subscription_->routeConfigProvider().has_value()); + RdsRouteConfigSubscription* subscription, + Server::Configuration::ServerFactoryContext& factory_context, ConfigFactory& config_factory) + : base_(RdsRouteConfigSubscriptionSharedPtr(subscription), factory_context, config_factory), + subscription_(subscription), config_update_info_(subscription->routeConfigUpdate()), + config_factory_(config_factory), factory_context_(factory_context) { + base_.subscription().routeConfigProvider().emplace(this); subscription_->routeConfigProvider().emplace(this); } @@ -255,11 +145,8 @@ RdsRouteConfigProviderImpl::~RdsRouteConfigProviderImpl() { subscription_->routeConfigProvider().reset(); } -Router::ConfigConstSharedPtr RdsRouteConfigProviderImpl::config() { return tls_->config_; } - void RdsRouteConfigProviderImpl::onConfigUpdate() { - tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( - OptRef tls) { tls->config_ = new_config; }); + base_.onConfigUpdate(); const auto aliases = config_update_info_->resourceIdsInLastVhdsUpdate(); // Regular (non-VHDS) RDS updates don't populate aliases fields in resources. @@ -295,7 +182,7 @@ void RdsRouteConfigProviderImpl::onConfigUpdate() { void RdsRouteConfigProviderImpl::validateConfig( const envoy::config::route::v3::RouteConfiguration& config) const { // TODO(lizan): consider cache the config here until onConfigUpdate. - ConfigImpl validation_config(config, optional_http_filters_, factory_context_, validator_, false); + config_factory_.createConfig(config); } // Schedules a VHDS request on the main thread and queues up the callback to use when the VHDS @@ -321,15 +208,9 @@ void RdsRouteConfigProviderImpl::requestVirtualHostsUpdate( }); } -RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) { - config_tracker_entry_ = - admin.getConfigTracker().add("routes", [this](const Matchers::StringMatcher& matcher) { - return dumpRouteConfigs(matcher); - }); - // ConfigTracker keys must be unique. We are asserting that no one has stolen the "routes" key - // from us, since the returned entry will be nullptr if the key already exists. - RELEASE_ASSERT(config_tracker_entry_, ""); -} +RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) + : Rds::RouteConfigProviderManagerImpl( + admin) {} Router::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, @@ -338,29 +219,25 @@ Router::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRo Init::Manager& init_manager) { // RdsRouteConfigSubscriptions are unique based on their serialized RDS config. const uint64_t manager_identifier = MessageUtil::hash(rds); - auto it = dynamic_route_config_providers_.find(manager_identifier); - - if (it == dynamic_route_config_providers_.end()) { - // std::make_shared does not work for classes with private constructors. There are ways - // around it. However, since this is not a performance critical path we err on the side - // of simplicity. - RdsRouteConfigSubscriptionSharedPtr subscription(new RdsRouteConfigSubscription( - rds, manager_identifier, factory_context, stat_prefix, optional_http_filters, *this)); - init_manager.add(subscription->parent_init_target_); - RdsRouteConfigProviderImplSharedPtr new_provider{new RdsRouteConfigProviderImpl( - std::move(subscription), factory_context, optional_http_filters)}; - dynamic_route_config_providers_.insert( - {manager_identifier, std::weak_ptr(new_provider)}); + auto existing_provider = + reuseDynamicProvider(manager_identifier, init_manager, rds.route_config_name()); + + if (!existing_provider) { + RouteConfigUpdateReceiverImpl* config_update( + new RouteConfigUpdateReceiverImpl(factory_context, optional_http_filters)); + RdsRouteConfigSubscription* subscription(new RdsRouteConfigSubscription( + config_update, rds, manager_identifier, factory_context, stat_prefix, *this)); + init_manager.add(subscription->initTarget()); + RdsRouteConfigProviderImplSharedPtr new_provider{ + new RdsRouteConfigProviderImpl(subscription, factory_context, *config_update)}; + insertDynamicProvider(manager_identifier, new_provider, + &new_provider->subscription().initTarget()); return new_provider; } else { - // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up - // in the RdsRouteConfigSubscription destructor, and the single threaded nature - // of this code, locking the weak_ptr will not fail. - auto existing_provider = it->second.lock(); - RELEASE_ASSERT(existing_provider != nullptr, - absl::StrCat("cannot find subscribed rds resource ", rds.route_config_name())); - init_manager.add(existing_provider->subscription_->parent_init_target_); - return existing_provider; + RouteConfigProviderSharedPtr existing_provider_downcasted = + std::dynamic_pointer_cast(existing_provider); + ASSERT(existing_provider_downcasted); + return existing_provider_downcasted; } } @@ -371,49 +248,9 @@ RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigPr ProtobufMessage::ValidationVisitor& validator) { auto provider = std::make_unique( route_config, optional_http_filters, factory_context, validator, *this); - static_route_config_providers_.insert(provider.get()); + insertStaticProvider(provider.get()); return provider; } -std::unique_ptr -RouteConfigProviderManagerImpl::dumpRouteConfigs( - const Matchers::StringMatcher& name_matcher) const { - auto config_dump = std::make_unique(); - - for (const auto& element : dynamic_route_config_providers_) { - const auto& subscription = element.second.lock()->subscription_; - // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up - // in the RdsRouteConfigSubscription destructor, and the single threaded nature - // of this code, locking the weak_ptr will not fail. - ASSERT(subscription); - ASSERT(subscription->route_config_provider_opt_.has_value()); - - if (subscription->routeConfigUpdate()->configInfo()) { - if (!name_matcher.match(subscription->routeConfigUpdate()->protobufConfiguration().name())) { - continue; - } - auto* dynamic_config = config_dump->mutable_dynamic_route_configs()->Add(); - dynamic_config->set_version_info(subscription->routeConfigUpdate()->configVersion()); - dynamic_config->mutable_route_config()->PackFrom( - subscription->routeConfigUpdate()->protobufConfiguration()); - TimestampUtil::systemClockToTimestamp(subscription->routeConfigUpdate()->lastUpdated(), - *dynamic_config->mutable_last_updated()); - } - } - - for (const auto& provider : static_route_config_providers_) { - ASSERT(provider->configInfo()); - if (!name_matcher.match(provider->configInfo().value().config_.name())) { - continue; - } - auto* static_config = config_dump->mutable_static_route_configs()->Add(); - static_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); - TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), - *static_config->mutable_last_updated()); - } - - return config_dump; -} - } // namespace Router } // namespace Envoy diff --git a/source/common/router/rds_impl.h b/source/common/router/rds_impl.h index 4c4df57d4482b..596859ecc1c9f 100644 --- a/source/common/router/rds_impl.h +++ b/source/common/router/rds_impl.h @@ -31,7 +31,11 @@ #include "source/common/init/target_impl.h" #include "source/common/init/watcher_impl.h" #include "source/common/protobuf/utility.h" -#include "source/common/router/route_config_update_receiver_impl.h" +#include "source/common/router/rds/rds_route_config_provider_impl.h" +#include "source/common/router/rds/rds_route_config_subscription.h" +#include "source/common/router/rds/route_config_provider_manager_impl.h" +#include "source/common/router/rds/route_config_update_receiver_impl.h" +#include "source/common/router/rds/static_route_config_provider_impl.h" #include "source/common/router/vhds.h" #include "absl/container/node_hash_map.h" @@ -61,6 +65,7 @@ class RouteConfigProviderUtil { }; class RouteConfigProviderManagerImpl; +using ConfigFactory = Rds::ConfigFactory; /** * Implementation of RouteConfigProvider that holds a static route configuration. @@ -68,19 +73,17 @@ class RouteConfigProviderManagerImpl; class StaticRouteConfigProviderImpl : public RouteConfigProvider { public: StaticRouteConfigProviderImpl(const envoy::config::route::v3::RouteConfiguration& config, - const OptionalHttpFilters& http_filters, + const RouteConfigProviderManager::OptionalHttpFilters& http_filters, Server::Configuration::ServerFactoryContext& factory_context, ProtobufMessage::ValidationVisitor& validator, RouteConfigProviderManagerImpl& route_config_provider_manager); ~StaticRouteConfigProviderImpl() override; // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override { return config_; } - absl::optional configInfo() const override { - return ConfigInfo{route_config_proto_, ""}; - } - SystemTime lastUpdated() const override { return last_updated_; } - void onConfigUpdate() override {} + Router::ConfigConstSharedPtr config() override { return base_.config(); } + absl::optional configInfo() const override { return base_.configInfo(); } + SystemTime lastUpdated() const override { return base_.lastUpdated(); } + void onConfigUpdate() override { base_.onConfigUpdate(); } void validateConfig(const envoy::config::route::v3::RouteConfiguration&) const override {} void requestVirtualHostsUpdate(const std::string&, Event::Dispatcher&, std::weak_ptr) override { @@ -88,94 +91,48 @@ class StaticRouteConfigProviderImpl : public RouteConfigProvider { } private: - ConfigConstSharedPtr config_; - envoy::config::route::v3::RouteConfiguration route_config_proto_; - SystemTime last_updated_; + Rds::StaticRouteConfigProviderImpl base_; RouteConfigProviderManagerImpl& route_config_provider_manager_; }; -/** - * All RDS stats. @see stats_macros.h - */ -#define ALL_RDS_STATS(COUNTER, GAUGE) \ - COUNTER(config_reload) \ - COUNTER(update_empty) \ - GAUGE(config_reload_time_ms, NeverImport) - -/** - * Struct definition for all RDS stats. @see stats_macros.h - */ -struct RdsStats { - ALL_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) -}; - -class RdsRouteConfigProviderImpl; - /** * A class that fetches the route configuration dynamically using the RDS API and updates them to * RDS config providers. */ + class RdsRouteConfigSubscription - : Envoy::Config::SubscriptionBase, - Logger::Loggable { + : public Rds::RdsRouteConfigSubscription { public: - ~RdsRouteConfigSubscription() override; + RdsRouteConfigSubscription( + RouteConfigUpdateReceiver* config_update, + const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, + const uint64_t manager_identifier, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + RouteConfigProviderManagerImpl& route_config_provider_manager); absl::optional& routeConfigProvider() { return route_config_provider_opt_; } - RouteConfigUpdatePtr& routeConfigUpdate() { return config_update_info_; } + RouteConfigUpdateReceiver* routeConfigUpdate() { return config_update_info_; } void updateOnDemand(const std::string& aliases); void maybeCreateInitManager(const std::string& version_info, std::unique_ptr& init_manager, std::unique_ptr& resume_rds); private: - // Config::SubscriptionCallbacks - void onConfigUpdate(const std::vector& resources, - const std::string& version_info) override; - void onConfigUpdate(const std::vector& added_resources, - const Protobuf::RepeatedPtrField& removed_resources, - const std::string& system_version_info) override; - void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, - const EnvoyException* e) override; + void beforeProviderUpdate() override; + void afterProviderUpdate() override; ABSL_MUST_USE_RESULT Common::CallbackHandlePtr addUpdateCallback(std::function callback) { return update_callback_manager_.add(callback); } - RdsRouteConfigSubscription( - const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, - const uint64_t manager_identifier, - Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, - const OptionalHttpFilters& optional_http_filters, - RouteConfigProviderManagerImpl& route_config_provider_manager); - - bool validateUpdateSize(int num_resources); - - const std::string route_config_name_; - // This scope must outlive the subscription_ below as the subscription has derived stats. - Stats::ScopePtr scope_; - Envoy::Config::SubscriptionPtr subscription_; - Server::Configuration::ServerFactoryContext& factory_context_; - - // Init target used to notify the parent init manager that the subscription [and its sub resource] - // is ready. - Init::SharedTargetImpl parent_init_target_; - // Init watcher on RDS and VHDS ready event. This watcher marks parent_init_target_ ready. - Init::WatcherImpl local_init_watcher_; - // Target which starts the RDS subscription. - Init::TargetImpl local_init_target_; - Init::ManagerImpl local_init_manager_; - std::string stat_prefix_; - RdsStats stats_; - RouteConfigProviderManagerImpl& route_config_provider_manager_; - const uint64_t manager_identifier_; absl::optional route_config_provider_opt_; + // The pointer is owned by the base class, here it is just stored as raw pointer to avoid + // downcasting. + RouteConfigUpdateReceiver* config_update_info_; + VhdsSubscriptionPtr vhds_subscription_; - RouteConfigUpdatePtr config_update_info_; Common::CallbackManager<> update_callback_manager_; - const OptionalHttpFilters optional_http_filters_; - friend class RouteConfigProviderManagerImpl; // Access to addUpdateCallback friend class ScopedRdsConfigSubscription; }; @@ -195,16 +152,19 @@ struct UpdateOnDemandCallback { class RdsRouteConfigProviderImpl : public RouteConfigProvider, Logger::Loggable { public: + RdsRouteConfigProviderImpl(RdsRouteConfigSubscription* subscription, + Server::Configuration::ServerFactoryContext& factory_context, + ConfigFactory& config_factory); + ~RdsRouteConfigProviderImpl() override; RdsRouteConfigSubscription& subscription() { return *subscription_; } // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override; - absl::optional configInfo() const override { - return config_update_info_->configInfo(); - } - SystemTime lastUpdated() const override { return config_update_info_->lastUpdated(); } + Router::ConfigConstSharedPtr config() override { return base_.config(); } + absl::optional configInfo() const override { return base_.configInfo(); } + SystemTime lastUpdated() const override { return base_.lastUpdated(); } + void onConfigUpdate() override; void requestVirtualHostsUpdate( const std::string& for_domain, Event::Dispatcher& thread_local_dispatcher, @@ -212,39 +172,31 @@ class RdsRouteConfigProviderImpl : public RouteConfigProvider, void validateConfig(const envoy::config::route::v3::RouteConfiguration& config) const override; private: - struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { - ThreadLocalConfig(ConfigConstSharedPtr initial_config) : config_(std::move(initial_config)) {} - ConfigConstSharedPtr config_; - }; + Rds::RdsRouteConfigProviderImpl base_; - RdsRouteConfigProviderImpl(RdsRouteConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::ServerFactoryContext& factory_context, - const OptionalHttpFilters& optional_http_filters); + // The pointer is owned by base_, here it is just stored as raw pointer to avoid downcasting. + RdsRouteConfigSubscription* subscription_; + + RouteConfigUpdateReceiver* config_update_info_; + ConfigFactory& config_factory_; - RdsRouteConfigSubscriptionSharedPtr subscription_; - RouteConfigUpdatePtr& config_update_info_; Server::Configuration::ServerFactoryContext& factory_context_; - ProtobufMessage::ValidationVisitor& validator_; - ThreadLocal::TypedSlot tls_; std::list config_update_callbacks_; // A flag used to determine if this instance of RdsRouteConfigProviderImpl hasn't been // deallocated. Please also see a comment in requestVirtualHostsUpdate() method implementation. std::shared_ptr still_alive_{std::make_shared(true)}; - const OptionalHttpFilters optional_http_filters_; - - friend class RouteConfigProviderManagerImpl; }; using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; -class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, - public Singleton::Instance { +class RouteConfigProviderManagerImpl + : public RouteConfigProviderManager, + public Singleton::Instance, + public Rds::RouteConfigProviderManagerImpl { public: RouteConfigProviderManagerImpl(Server::Admin& admin); - std::unique_ptr - dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const; - // RouteConfigProviderManager RouteConfigProviderSharedPtr createRdsRouteConfigProvider( const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, @@ -257,18 +209,6 @@ class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, const OptionalHttpFilters& optional_http_filters, Server::Configuration::ServerFactoryContext& factory_context, ProtobufMessage::ValidationVisitor& validator) override; - -private: - // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map - // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists - // Then the lifetime management stuff is centralized and opaque. - absl::node_hash_map> - dynamic_route_config_providers_; - absl::node_hash_set static_route_config_providers_; - Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; - - friend class RdsRouteConfigSubscription; - friend class StaticRouteConfigProviderImpl; }; using RouteConfigProviderManagerImplPtr = std::unique_ptr; diff --git a/source/common/router/route_config_update_receiver_impl.cc b/source/common/router/route_config_update_receiver_impl.cc index 61d451ce62910..58b7f116f90dc 100644 --- a/source/common/router/route_config_update_receiver_impl.cc +++ b/source/common/router/route_config_update_receiver_impl.cc @@ -16,23 +16,19 @@ namespace Router { bool RouteConfigUpdateReceiverImpl::onRdsUpdate( const envoy::config::route::v3::RouteConfiguration& rc, const std::string& version_info) { - const uint64_t new_hash = MessageUtil::hash(rc); - if (new_hash == last_config_hash_) { + if (!base_.updateHash(rc)) { return false; } - route_config_proto_ = std::make_unique(rc); - last_config_hash_ = new_hash; const uint64_t new_vhds_config_hash = rc.has_vhds() ? MessageUtil::hash(rc.vhds()) : 0ul; vhds_configuration_changed_ = new_vhds_config_hash != last_vhds_config_hash_; last_vhds_config_hash_ = new_vhds_config_hash; - initializeRdsVhosts(*route_config_proto_); + initializeRdsVhosts(rc); - rebuildRouteConfig(rds_virtual_hosts_, *vhds_virtual_hosts_, *route_config_proto_); - config_ = std::make_shared( - *route_config_proto_, optional_http_filters_, factory_context_, - factory_context_.messageValidationContext().dynamicValidationVisitor(), false); + auto route_config_proto = std::make_unique(rc); + rebuildRouteConfig(rds_virtual_hosts_, *vhds_virtual_hosts_, *route_config_proto); + base_.updateConfig(std::move(route_config_proto)); - onUpdateCommon(version_info); + base_.onUpdateCommon(version_info); return true; } @@ -49,30 +45,19 @@ bool RouteConfigUpdateReceiverImpl::onVhdsUpdate( auto route_config_after_this_update = std::make_unique(); - route_config_after_this_update->CopyFrom(*route_config_proto_); + route_config_after_this_update->CopyFrom(base_.protobufConfiguration()); rebuildRouteConfig(rds_virtual_hosts_, *vhosts_after_this_update, *route_config_after_this_update); - auto new_config = std::make_shared( - *route_config_after_this_update, optional_http_filters_, factory_context_, - factory_context_.messageValidationContext().dynamicValidationVisitor(), false); - // No exception, route_config_after_this_update is valid, can update the state. vhds_virtual_hosts_ = std::move(vhosts_after_this_update); - route_config_proto_ = std::move(route_config_after_this_update); - config_ = new_config; + base_.updateConfig(std::move(route_config_after_this_update)); resource_ids_in_last_update_ = added_resource_ids; - onUpdateCommon(version_info); + base_.onUpdateCommon(version_info); return removed || updated || !resource_ids_in_last_update_.empty(); } -void RouteConfigUpdateReceiverImpl::onUpdateCommon(const std::string& version_info) { - last_config_version_ = version_info; - last_updated_ = time_source_.systemTime(); - config_info_.emplace(RouteConfigProvider::ConfigInfo{*route_config_proto_, last_config_version_}); -} - void RouteConfigUpdateReceiverImpl::initializeRdsVhosts( const envoy::config::route::v3::RouteConfiguration& route_configuration) { rds_virtual_hosts_.clear(); @@ -123,5 +108,16 @@ void RouteConfigUpdateReceiverImpl::rebuildRouteConfig( } } +ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::createConfig( + const envoy::config::route::v3::RouteConfiguration& rc) const { + return std::make_shared( + rc, optional_http_filters_, factory_context_, + factory_context_.messageValidationContext().dynamicValidationVisitor(), false); +} + +ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::createConfig() const { + return std::make_shared(); +} + } // namespace Router } // namespace Envoy diff --git a/source/common/router/route_config_update_receiver_impl.h b/source/common/router/route_config_update_receiver_impl.h index fc07c9f9e3f98..e7eb4c14d1184 100644 --- a/source/common/router/route_config_update_receiver_impl.h +++ b/source/common/router/route_config_update_receiver_impl.h @@ -12,17 +12,20 @@ #include "source/common/common/logger.h" #include "source/common/protobuf/utility.h" #include "source/common/router/config_impl.h" +#include "source/common/router/rds/config_factory.h" +#include "source/common/router/rds/route_config_update_receiver_impl.h" namespace Envoy { namespace Router { -class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { +class RouteConfigUpdateReceiverImpl + : public RouteConfigUpdateReceiver, + public Rds::ConfigFactory { public: RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context, const OptionalHttpFilters& optional_http_filters) - : factory_context_(factory_context), time_source_(factory_context.timeSource()), - route_config_proto_(std::make_unique()), - last_config_hash_(0ull), last_vhds_config_hash_(0ul), + : base_(factory_context, *this), factory_context_(factory_context), + last_vhds_config_hash_(0ul), vhds_virtual_hosts_( std::make_unique>()), vhds_configuration_changed_(true), optional_http_filters_(optional_http_filters) {} @@ -37,7 +40,6 @@ class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { const std::map& vhds_vhosts, envoy::config::route::v3::RouteConfiguration& route_config); bool onDemandFetchFailed(const envoy::service::discovery::v3::Resource& resource) const; - void onUpdateCommon(const std::string& version_info); // Router::RouteConfigUpdateReceiver bool onRdsUpdate(const envoy::config::route::v3::RouteConfiguration& rc, @@ -46,37 +48,37 @@ class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { const std::set& added_resource_ids, const Protobuf::RepeatedPtrField& removed_resources, const std::string& version_info) override; - const std::string& routeConfigName() const override { return route_config_proto_->name(); } - const std::string& configVersion() const override { return last_config_version_; } - uint64_t configHash() const override { return last_config_hash_; } + const std::string& routeConfigName() const override { return base_.routeConfigName(); } + const std::string& configVersion() const override { return base_.configVersion(); } + uint64_t configHash() const override { return base_.configHash(); } absl::optional configInfo() const override { - return config_info_; + return base_.configInfo(); } bool vhdsConfigurationChanged() const override { return vhds_configuration_changed_; } const envoy::config::route::v3::RouteConfiguration& protobufConfiguration() override { - return static_cast(*route_config_proto_); + return base_.protobufConfiguration(); } - ConfigConstSharedPtr parsedConfiguration() const override { return config_; } - SystemTime lastUpdated() const override { return last_updated_; } + ConfigConstSharedPtr parsedConfiguration() const override { return base_.parsedConfiguration(); } + SystemTime lastUpdated() const override { return base_.lastUpdated(); } const std::set& resourceIdsInLastVhdsUpdate() override { return resource_ids_in_last_update_; } + // Rds::ConfigFactory + ConfigConstSharedPtr + createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const override; + ConfigConstSharedPtr createConfig() const override; + private: + Rds::RouteConfigUpdateReceiverImpl base_; + Server::Configuration::ServerFactoryContext& factory_context_; - TimeSource& time_source_; - std::unique_ptr route_config_proto_; - uint64_t last_config_hash_; uint64_t last_vhds_config_hash_; - std::string last_config_version_; - SystemTime last_updated_; std::map rds_virtual_hosts_; std::unique_ptr> vhds_virtual_hosts_; - absl::optional config_info_; std::set resource_ids_in_last_update_; bool vhds_configuration_changed_; - ConfigConstSharedPtr config_; - const OptionalHttpFilters& optional_http_filters_; + const OptionalHttpFilters optional_http_filters_; }; } // namespace Router diff --git a/source/common/router/vhds.cc b/source/common/router/vhds.cc index 324d952c42b6d..859674b1b6c84 100644 --- a/source/common/router/vhds.cc +++ b/source/common/router/vhds.cc @@ -20,7 +20,7 @@ namespace Envoy { namespace Router { // Implements callbacks to handle DeltaDiscovery protocol for VirtualHostDiscoveryService -VhdsSubscription::VhdsSubscription(RouteConfigUpdatePtr& config_update_info, +VhdsSubscription::VhdsSubscription(RouteConfigUpdateReceiver* config_update_info, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, absl::optional& route_config_provider_opt) diff --git a/source/common/router/vhds.h b/source/common/router/vhds.h index e1d36da175afc..2c0599e3d64e1 100644 --- a/source/common/router/vhds.h +++ b/source/common/router/vhds.h @@ -39,10 +39,11 @@ struct VhdsStats { class VhdsSubscription : Envoy::Config::SubscriptionBase, Logger::Loggable { public: - VhdsSubscription(RouteConfigUpdatePtr& config_update_info, + VhdsSubscription(RouteConfigUpdateReceiver* config_update_info, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, absl::optional& route_config_providers); + ~VhdsSubscription() override { init_target_.ready(); } void registerInitTargetWithInitManager(Init::Manager& m) { m.add(init_target_); } @@ -67,7 +68,7 @@ class VhdsSubscription : Envoy::Config::SubscriptionBase #include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.pb.h" +#include "envoy/init/manager.h" +#include "envoy/router/rds/route_config_provider.h" +#include "envoy/server/factory_context.h" #include "source/extensions/filters/network/thrift_proxy/router/router.h" @@ -12,50 +16,54 @@ namespace NetworkFilters { namespace ThriftProxy { namespace Router { +using RouteConfigProvider = Envoy::Router::Rds::RouteConfigProvider< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; + +using RouteConfigProviderPtr = std::unique_ptr; +using RouteConfigProviderSharedPtr = std::shared_ptr; + /** - * A provider for constant route configurations. + * The RouteConfigProviderManager exposes the ability to get a RouteConfigProvider. This interface + * is exposed to the Server's FactoryContext in order to allow HttpConnectionManagers to get + * RouteConfigProviders. */ -class RouteConfigProvider { +class RouteConfigProviderManager { public: - struct ConfigInfo { - // A reference to the currently loaded route configuration. Do not hold this reference beyond - // the caller of configInfo()'s scope. - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config_; - - // The discovery version that supplied this route. This will be set to "" in the case of - // static clusters. - std::string version_; - }; - - virtual ~RouteConfigProvider() = default; - - /** - * @return Router::ConfigConstSharedPtr a route configuration for use during a single request. The - * returned config may be different on a subsequent call, so a new config should be acquired for - * each request flow. - */ - virtual ConfigConstSharedPtr config() PURE; + virtual ~RouteConfigProviderManager() = default; /** - * @return the configuration information for the currently loaded route configuration. Note that - * if the provider has not yet performed an initial configuration load, no information will be - * returned. + * Get a RouteConfigProviderPtr for a route from RDS. Ownership of the RouteConfigProvider is the + * HttpConnectionManagers who calls this function. The RouteConfigProviderManager holds raw + * pointers to the RouteConfigProviders. Clean up of the pointers happen from the destructor of + * the RouteConfigProvider. This method creates a RouteConfigProvider which may share the + * underlying RDS subscription with the same (route_config_name, cluster). + * @param rds supplies the proto configuration of an RDS-configured RouteConfigProvider. + * @param optional_http_filters a set of optional http filter names. + * @param factory_context is the context to use for the route config provider. + * @param stat_prefix supplies the stat_prefix to use for the provider stats. + * @param init_manager the Init::Manager used to coordinate initialization of a the underlying RDS + * subscription. */ - virtual absl::optional configInfo() const PURE; + virtual RouteConfigProviderSharedPtr createRdsRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + Init::Manager& init_manager) PURE; /** - * @return the last time this RouteConfigProvider was updated. Used for config dumps. + * Get a RouteConfigSharedPtr for a statically defined route. Ownership is as described for + * getRdsRouteConfigProvider above. This method always create a new RouteConfigProvider. + * @param route_config supplies the RouteConfiguration for this route + * @param optional_http_filters a set of optional http filter names. + * @param factory_context is the context to use for the route config provider. + * @param validator is the message validator for route config. */ - virtual SystemTime lastUpdated() const PURE; - - /** - * Callback used to notify RouteConfigProvider about configuration changes. - */ - virtual void onConfigUpdate() PURE; + virtual RouteConfigProviderPtr createStaticRouteConfigProvider( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, + Server::Configuration::ServerFactoryContext& factory_context) PURE; }; -using RouteConfigProviderPtr = std::unique_ptr; -using RouteConfigProviderSharedPtr = std::shared_ptr; +using RouteConfigProviderManagerPtr = std::unique_ptr; +using RouteConfigProviderManagerSharedPtr = std::shared_ptr; } // namespace Router } // namespace ThriftProxy diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc index d80b0c5f8feee..afa2033727712 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc @@ -5,17 +5,13 @@ #include #include -#include "envoy/admin/v3/config_dump.pb.h" -#include "envoy/config/core/v3/config_source.pb.h" -#include "envoy/service/discovery/v3/discovery.pb.h" +#include "envoy/router/rds/route_config_update_receiver.h" -#include "source/common/common/assert.h" -#include "source/common/common/fmt.h" -#include "source/common/config/api_version.h" -#include "source/common/config/utility.h" -#include "source/common/protobuf/utility.h" +#include "source/common/router/rds/rds_route_config_provider_impl.h" +#include "source/common/router/rds/rds_route_config_subscription.h" +#include "source/common/router/rds/route_config_update_receiver_impl.h" +#include "source/common/router/rds/static_route_config_provider_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/config.h" -#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h" namespace Envoy { namespace Extensions { @@ -23,169 +19,25 @@ namespace NetworkFilters { namespace ThriftProxy { namespace Router { -StaticRouteConfigProviderImpl::StaticRouteConfigProviderImpl( - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config, - Server::Configuration::ServerFactoryContext& factory_context, - RouteConfigProviderManagerImpl& route_config_provider_manager) - : config_(new ConfigImpl(config)), route_config_proto_{config}, - last_updated_(factory_context.timeSource().systemTime()), - route_config_provider_manager_(route_config_provider_manager) { - route_config_provider_manager_.static_route_config_providers_.insert(this); -} - -StaticRouteConfigProviderImpl::~StaticRouteConfigProviderImpl() { - route_config_provider_manager_.static_route_config_providers_.erase(this); -} - -// TODO(htuch): If support for multiple clusters is added per #1170 cluster_name_ -RdsRouteConfigSubscription::RdsRouteConfigSubscription( - const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, - const uint64_t manager_identifier, Server::Configuration::ServerFactoryContext& factory_context, - const std::string& stat_prefix, RouteConfigProviderManagerImpl& route_config_provider_manager) - : Envoy::Config::SubscriptionBase< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>( - factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), - route_config_name_(rds.route_config_name()), - scope_(factory_context.scope().createScope(stat_prefix + "rds." + route_config_name_ + ".")), - factory_context_(factory_context), - parent_init_target_(fmt::format("RdsRouteConfigSubscription init {}", route_config_name_), - [this]() { local_init_manager_.initialize(local_init_watcher_); }), - local_init_watcher_(fmt::format("RDS local-init-watcher {}", rds.route_config_name()), - [this]() { parent_init_target_.ready(); }), - local_init_target_( - fmt::format("RdsRouteConfigSubscription local-init-target {}", route_config_name_), - [this]() { subscription_->start({route_config_name_}); }), - local_init_manager_(fmt::format("RDS local-init-manager {}", route_config_name_)), - stat_prefix_(stat_prefix), - stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}), - route_config_provider_manager_(route_config_provider_manager), - manager_identifier_(manager_identifier) { - const auto resource_name = getResourceName(); - subscription_ = - factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( - rds.config_source(), Grpc::Common::typeUrl(resource_name), *scope_, *this, - resource_decoder_, {}); - local_init_manager_.add(local_init_target_); - config_update_info_ = std::make_unique(factory_context); -} - -RdsRouteConfigSubscription::~RdsRouteConfigSubscription() { - // If we get destroyed during initialization, make sure we signal that we "initialized". - local_init_target_.ready(); - - // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that - // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the - // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get - // cleaned by the RdsRouteConfigProvider's destructor. - route_config_provider_manager_.dynamic_route_config_providers_.erase(manager_identifier_); -} - -void RdsRouteConfigSubscription::onConfigUpdate( - const std::vector& resources, - const std::string& version_info) { - if (!validateUpdateSize(resources.size())) { - return; - } - const auto& route_config = dynamic_cast< - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>( - resources[0].get().resource()); - if (route_config.name() != route_config_name_) { - throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}", - route_config_name_, route_config.name())); - } - if (config_update_info_->onRdsUpdate(route_config, version_info)) { - stats_.config_reload_.inc(); - stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); - - ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_, - config_update_info_->configHash()); - - if (route_config_provider_opt_.has_value()) { - route_config_provider_opt_.value()->onConfigUpdate(); - } - } - - local_init_target_.ready(); -} - -void RdsRouteConfigSubscription::onConfigUpdate( - const std::vector& added_resources, - const Protobuf::RepeatedPtrField& removed_resources, const std::string&) { - if (!removed_resources.empty()) { - // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense - // (see discussion in #6879), and so we should do something other than ignoring here. - ENVOY_LOG( - error, - "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", - removed_resources[0]); - } - if (!added_resources.empty()) { - onConfigUpdate(added_resources, added_resources[0].get().version()); - } -} - -void RdsRouteConfigSubscription::onConfigUpdateFailed( - Envoy::Config::ConfigUpdateFailureReason reason, const EnvoyException*) { - ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason); - // We need to allow server startup to continue, even if we have a bad - // config. - local_init_target_.ready(); -} - -bool RdsRouteConfigSubscription::validateUpdateSize(int num_resources) { - if (num_resources == 0) { - ENVOY_LOG(debug, "Missing RouteConfiguration for {} in onConfigUpdate()", route_config_name_); - stats_.update_empty_.inc(); - local_init_target_.ready(); - return false; - } - if (num_resources != 1) { - throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", num_resources)); - // (would be a return false here) - } - return true; -} - -RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( - RdsRouteConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::ServerFactoryContext& factory_context) - : subscription_(std::move(subscription)), - config_update_info_(subscription_->routeConfigUpdate()), tls_(factory_context.threadLocal()) { - ConfigConstSharedPtr initial_config; - if (config_update_info_->configInfo().has_value()) { - initial_config = std::make_shared(config_update_info_->protobufConfiguration()); - } else { - initial_config = std::make_shared(); - } - tls_.set([initial_config](Event::Dispatcher&) { - return std::make_shared(initial_config); - }); - // It should be 1:1 mapping due to shared rds config. - ASSERT(!subscription_->routeConfigProvider().has_value()); - subscription_->routeConfigProvider().emplace(this); -} - -RdsRouteConfigProviderImpl::~RdsRouteConfigProviderImpl() { - ASSERT(subscription_->routeConfigProvider().has_value()); - subscription_->routeConfigProvider().reset(); -} +using RouteConfigUpdatePtr = std::unique_ptr>; +using RouteConfigUpdateReceiverImpl = Envoy::Router::Rds::RouteConfigUpdateReceiverImpl< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; -ConfigConstSharedPtr RdsRouteConfigProviderImpl::config() { return tls_->config_; } +using RdsRouteConfigSubscription = Envoy::Router::Rds::RdsRouteConfigSubscription< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; +using RdsRouteConfigSubscriptionSharedPtr = std::shared_ptr; -void RdsRouteConfigProviderImpl::onConfigUpdate() { - tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( - OptRef tls) { tls->config_ = new_config; }); -} +using StaticRouteConfigProviderImpl = Envoy::Router::Rds::StaticRouteConfigProviderImpl< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; +using RdsRouteConfigProviderImpl = Envoy::Router::Rds::RdsRouteConfigProviderImpl< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; +using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; -RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) { - config_tracker_entry_ = - admin.getConfigTracker().add("routes", [this](const Matchers::StringMatcher& matcher) { - return dumpRouteConfigs(matcher); - }); - // ConfigTracker keys must be unique. We are asserting that no one has stolen the "routes" key - // from us, since the returned entry will be nullptr if the key already exists. - RELEASE_ASSERT(config_tracker_entry_, ""); -} +RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) + : Envoy::Router::Rds::RouteConfigProviderManagerImpl< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>( + admin) {} RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, @@ -193,28 +45,27 @@ RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfi Init::Manager& init_manager) { // RdsRouteConfigSubscriptions are unique based on their serialized RDS config. const uint64_t manager_identifier = MessageUtil::hash(rds); - auto it = dynamic_route_config_providers_.find(manager_identifier); - if (it == dynamic_route_config_providers_.end()) { + auto existing_provider = + reuseDynamicProvider(manager_identifier, init_manager, rds.route_config_name()); + + if (!existing_provider) { // std::make_shared does not work for classes with private constructors. There are ways // around it. However, since this is not a performance critical path we err on the side // of simplicity. + + RouteConfigUpdatePtr config_update(new RouteConfigUpdateReceiverImpl(factory_context, *this)); RdsRouteConfigSubscriptionSharedPtr subscription(new RdsRouteConfigSubscription( - rds, manager_identifier, factory_context, stat_prefix, *this)); - init_manager.add(subscription->parent_init_target_); + std::move(config_update), rds.config_source(), rds.route_config_name(), manager_identifier, + factory_context, stat_prefix, *this)); + init_manager.add(subscription->initTarget()); + RdsRouteConfigProviderImplSharedPtr new_provider{ - new RdsRouteConfigProviderImpl(std::move(subscription), factory_context)}; - dynamic_route_config_providers_.insert( - {manager_identifier, std::weak_ptr(new_provider)}); + new RdsRouteConfigProviderImpl(std::move(subscription), factory_context, *this)}; + insertDynamicProvider(manager_identifier, new_provider, + &new_provider->subscription().initTarget()); return new_provider; } else { - // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up - // in the RdsRouteConfigSubscription destructor, and the single threaded nature - // of this code, locking the weak_ptr will not fail. - auto existing_provider = it->second.lock(); - RELEASE_ASSERT(existing_provider != nullptr, - absl::StrCat("cannot find subscribed rds resource ", rds.route_config_name())); - init_manager.add(existing_provider->subscription_->parent_init_target_); return existing_provider; } } @@ -222,50 +73,20 @@ RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfi RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, Server::Configuration::ServerFactoryContext& factory_context) { - auto provider = - std::make_unique(route_config, factory_context, *this); - static_route_config_providers_.insert(provider.get()); + auto initial_config = createConfig(route_config); + auto provider = std::make_unique(initial_config, route_config, + factory_context, *this); + insertStaticProvider(provider.get()); return provider; } -std::unique_ptr -RouteConfigProviderManagerImpl::dumpRouteConfigs( - const Matchers::StringMatcher& name_matcher) const { - auto config_dump = std::make_unique(); - - for (const auto& element : dynamic_route_config_providers_) { - const auto& subscription = element.second.lock()->subscription_; - // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up - // in the RdsRouteConfigSubscription destructor, and the single threaded nature - // of this code, locking the weak_ptr will not fail. - ASSERT(subscription); - ASSERT(subscription->route_config_provider_opt_.has_value()); - - if (subscription->routeConfigUpdate()->configInfo()) { - if (!name_matcher.match(subscription->routeConfigUpdate()->protobufConfiguration().name())) { - continue; - } - auto* dynamic_config = config_dump->mutable_dynamic_route_configs()->Add(); - dynamic_config->set_version_info(subscription->routeConfigUpdate()->configVersion()); - dynamic_config->mutable_route_config()->PackFrom( - subscription->routeConfigUpdate()->protobufConfiguration()); - TimestampUtil::systemClockToTimestamp(subscription->routeConfigUpdate()->lastUpdated(), - *dynamic_config->mutable_last_updated()); - } - } - - for (const auto& provider : static_route_config_providers_) { - ASSERT(provider->configInfo()); - if (!name_matcher.match(provider->configInfo().value().config_.name())) { - continue; - } - auto* static_config = config_dump->mutable_static_route_configs()->Add(); - static_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); - TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), - *static_config->mutable_last_updated()); - } +std::shared_ptr RouteConfigProviderManagerImpl::createConfig( + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc) const { + return std::make_shared(rc); +} - return config_dump; +std::shared_ptr RouteConfigProviderManagerImpl::createConfig() const { + return std::make_shared(); } } // namespace Router diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h index 18ed509f51647..9673b325e7942 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h @@ -1,38 +1,15 @@ #pragma once -#include -#include #include -#include -#include -#include "envoy/admin/v3/config_dump.pb.h" -#include "envoy/config/core/v3/config_source.pb.h" -#include "envoy/config/subscription.h" #include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" #include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.validate.h" -#include "envoy/http/codes.h" -#include "envoy/local_info/local_info.h" -#include "envoy/server/admin.h" -#include "envoy/server/filter_config.h" -#include "envoy/service/discovery/v3/discovery.pb.h" #include "envoy/singleton/instance.h" -#include "envoy/stats/scope.h" -#include "envoy/thread_local/thread_local.h" -#include "source/common/common/cleanup.h" -#include "source/common/common/logger.h" -#include "source/common/config/subscription_base.h" -#include "source/common/init/manager_impl.h" -#include "source/common/init/target_impl.h" -#include "source/common/init/watcher_impl.h" -#include "source/common/protobuf/utility.h" +#include "source/common/router/rds/config_factory.h" +#include "source/common/router/rds/route_config_provider_manager_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/rds.h" -#include "source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h" -#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h" - -#include "absl/container/node_hash_map.h" -#include "absl/container/node_hash_set.h" +#include "source/extensions/filters/network/thrift_proxy/router/router.h" namespace Envoy { namespace Extensions { @@ -40,157 +17,16 @@ namespace NetworkFilters { namespace ThriftProxy { namespace Router { -/** - * Route configuration provider utilities. - */ -class RouteConfigProviderManagerImpl; - -/** - * Implementation of RouteConfigProvider that holds a static route configuration. - */ -class StaticRouteConfigProviderImpl : public RouteConfigProvider { -public: - StaticRouteConfigProviderImpl( - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& config, - Server::Configuration::ServerFactoryContext& factory_context, - RouteConfigProviderManagerImpl& route_config_provider_manager); - ~StaticRouteConfigProviderImpl() override; - - // Router::RouteConfigProvider - ConfigConstSharedPtr config() override { return config_; } - absl::optional configInfo() const override { - return ConfigInfo{route_config_proto_, ""}; - } - SystemTime lastUpdated() const override { return last_updated_; } - void onConfigUpdate() override {} - -private: - ConfigConstSharedPtr config_; - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration route_config_proto_; - SystemTime last_updated_; - RouteConfigProviderManagerImpl& route_config_provider_manager_; -}; - -/** - * All RDS stats. @see stats_macros.h - */ -#define ALL_RDS_STATS(COUNTER, GAUGE) \ - COUNTER(config_reload) \ - COUNTER(update_empty) \ - GAUGE(config_reload_time_ms, NeverImport) - -/** - * Struct definition for all RDS stats. @see stats_macros.h - */ -struct RdsStats { - ALL_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) -}; - -class RdsRouteConfigProviderImpl; - -/** - * A class that fetches the route configuration dynamically using the RDS API and updates them to - * RDS config providers. - */ -class RdsRouteConfigSubscription - : Envoy::Config::SubscriptionBase< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>, - Logger::Loggable { -public: - ~RdsRouteConfigSubscription() override; - - absl::optional& routeConfigProvider() { return route_config_provider_opt_; } - RouteConfigUpdatePtr& routeConfigUpdate() { return config_update_info_; } - -private: - // Config::SubscriptionCallbacks - void onConfigUpdate(const std::vector& resources, - const std::string& version_info) override; - void onConfigUpdate(const std::vector& added_resources, - const Protobuf::RepeatedPtrField& removed_resources, - const std::string& system_version_info) override; - void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, - const EnvoyException* e) override; - - RdsRouteConfigSubscription(const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, - const uint64_t manager_identifier, - Server::Configuration::ServerFactoryContext& factory_context, - const std::string& stat_prefix, - RouteConfigProviderManagerImpl& route_config_provider_manager); - - bool validateUpdateSize(int num_resources); - - const std::string route_config_name_; - // This scope must outlive the subscription_ below as the subscription has derived stats. - Stats::ScopePtr scope_; - Envoy::Config::SubscriptionPtr subscription_; - Server::Configuration::ServerFactoryContext& factory_context_; - - // Init target used to notify the parent init manager that the subscription [and its sub resource] - // is ready. - Init::SharedTargetImpl parent_init_target_; - // Init watcher on RDS and VHDS ready event. This watcher marks parent_init_target_ ready. - Init::WatcherImpl local_init_watcher_; - // Target which starts the RDS subscription. - Init::TargetImpl local_init_target_; - Init::ManagerImpl local_init_manager_; - std::string stat_prefix_; - RdsStats stats_; - RouteConfigProviderManagerImpl& route_config_provider_manager_; - const uint64_t manager_identifier_; - absl::optional route_config_provider_opt_; - RouteConfigUpdatePtr config_update_info_; - - friend class RouteConfigProviderManagerImpl; -}; - -using RdsRouteConfigSubscriptionSharedPtr = std::shared_ptr; - -/** - * Implementation of RouteConfigProvider that fetches the route configuration dynamically using - * the subscription. - */ -class RdsRouteConfigProviderImpl : public RouteConfigProvider, - Logger::Loggable { -public: - ~RdsRouteConfigProviderImpl() override; - - RdsRouteConfigSubscription& subscription() { return *subscription_; } - - // Router::RouteConfigProvider - ConfigConstSharedPtr config() override; - absl::optional configInfo() const override { - return config_update_info_->configInfo(); - } - SystemTime lastUpdated() const override { return config_update_info_->lastUpdated(); } - void onConfigUpdate() override; - -private: - struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { - ThreadLocalConfig(ConfigConstSharedPtr initial_config) : config_(std::move(initial_config)) {} - ConfigConstSharedPtr config_; - }; - - RdsRouteConfigProviderImpl(RdsRouteConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::ServerFactoryContext& factory_context); - - RdsRouteConfigSubscriptionSharedPtr subscription_; - RouteConfigUpdatePtr& config_update_info_; - ThreadLocal::TypedSlot tls_; - - friend class RouteConfigProviderManagerImpl; -}; - -using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; - -class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, - public Singleton::Instance { +class RouteConfigProviderManagerImpl + : public RouteConfigProviderManager, + public Singleton::Instance, + public Envoy::Router::Rds::RouteConfigProviderManagerImpl< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>, + public Envoy::Router::Rds::ConfigFactory< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config> { public: RouteConfigProviderManagerImpl(Server::Admin& admin); - std::unique_ptr - dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const; - // RouteConfigProviderManager RouteConfigProviderSharedPtr createRdsRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, @@ -202,19 +38,14 @@ class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, Server::Configuration::ServerFactoryContext& factory_context) override; private: - // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map - // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists - // Then the lifetime management stuff is centralized and opaque. - absl::node_hash_map> - dynamic_route_config_providers_; - absl::node_hash_set static_route_config_providers_; - Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; - - friend class RdsRouteConfigSubscription; - friend class StaticRouteConfigProviderImpl; + std::shared_ptr + createConfig(const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc) + const override; + std::shared_ptr createConfig() const override; }; using RouteConfigProviderManagerImplPtr = std::unique_ptr; +using RouteConfigProviderManagerImplSharedPtr = std::shared_ptr; } // namespace Router } // namespace ThriftProxy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h b/source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h deleted file mode 100644 index 95332b188b63c..0000000000000 --- a/source/extensions/filters/network/thrift_proxy/router/route_config_provider_manager.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include - -#include "envoy/config/core/v3/extension.pb.h" -#include "envoy/event/dispatcher.h" -#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" -#include "envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.pb.h" -#include "envoy/local_info/local_info.h" -#include "envoy/runtime/runtime.h" -#include "envoy/server/filter_config.h" -#include "envoy/thread_local/thread_local.h" -#include "envoy/upstream/cluster_manager.h" - -#include "source/extensions/filters/network/thrift_proxy/router/rds.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace ThriftProxy { -namespace Router { -/** - * The RouteConfigProviderManager exposes the ability to get a RouteConfigProvider. This interface - * is exposed to the Server's FactoryContext in order to allow HttpConnectionManagers to get - * RouteConfigProviders. - */ -class RouteConfigProviderManager { -public: - virtual ~RouteConfigProviderManager() = default; - - /** - * Get a RouteConfigProviderPtr for a route from RDS. Ownership of the RouteConfigProvider is the - * HttpConnectionManagers who calls this function. The RouteConfigProviderManager holds raw - * pointers to the RouteConfigProviders. Clean up of the pointers happen from the destructor of - * the RouteConfigProvider. This method creates a RouteConfigProvider which may share the - * underlying RDS subscription with the same (route_config_name, cluster). - * @param rds supplies the proto configuration of an RDS-configured RouteConfigProvider. - * @param optional_http_filters a set of optional http filter names. - * @param factory_context is the context to use for the route config provider. - * @param stat_prefix supplies the stat_prefix to use for the provider stats. - * @param init_manager the Init::Manager used to coordinate initialization of a the underlying RDS - * subscription. - */ - virtual RouteConfigProviderSharedPtr createRdsRouteConfigProvider( - const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, - Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, - Init::Manager& init_manager) PURE; - - /** - * Get a RouteConfigSharedPtr for a statically defined route. Ownership is as described for - * getRdsRouteConfigProvider above. This method always create a new RouteConfigProvider. - * @param route_config supplies the RouteConfiguration for this route - * @param optional_http_filters a set of optional http filter names. - * @param factory_context is the context to use for the route config provider. - * @param validator is the message validator for route config. - */ - virtual RouteConfigProviderPtr createStaticRouteConfigProvider( - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, - Server::Configuration::ServerFactoryContext& factory_context) PURE; -}; - -using RouteConfigProviderManagerPtr = std::unique_ptr; -using RouteConfigProviderManagerSharedPtr = std::shared_ptr; - -} // namespace Router -} // namespace ThriftProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc deleted file mode 100644 index 281d57fd75ab6..0000000000000 --- a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h" - -#include - -#include "envoy/config/route/v3/route.pb.h" -#include "envoy/service/discovery/v3/discovery.pb.h" - -#include "source/common/common/assert.h" -#include "source/common/common/fmt.h" -#include "source/common/common/thread.h" -#include "source/common/protobuf/utility.h" -#include "source/extensions/filters/network/thrift_proxy/router/config.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace ThriftProxy { -namespace Router { - -bool RouteConfigUpdateReceiverImpl::onRdsUpdate( - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc, - const std::string& version_info) { - const uint64_t new_hash = MessageUtil::hash(rc); - if (new_hash == last_config_hash_) { - return false; - } - route_config_proto_ = - std::make_unique( - rc); - last_config_hash_ = new_hash; - config_ = std::make_shared(*route_config_proto_); - last_config_version_ = version_info; - last_updated_ = time_source_.systemTime(); - config_info_.emplace(RouteConfigProvider::ConfigInfo{*route_config_proto_, last_config_version_}); - return true; -} - -} // namespace Router -} // namespace ThriftProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h b/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h deleted file mode 100644 index 4ba96a4a89cdf..0000000000000 --- a/source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver_impl.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include - -#include "envoy/server/factory_context.h" -#include "envoy/service/discovery/v3/discovery.pb.h" - -#include "source/common/common/logger.h" -#include "source/common/protobuf/utility.h" -#include "source/extensions/filters/network/thrift_proxy/router/route_config_update_receiver.h" - -namespace Envoy { -namespace Extensions { -namespace NetworkFilters { -namespace ThriftProxy { -namespace Router { - -class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { -public: - RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context) - : time_source_(factory_context.timeSource()), - route_config_proto_( - std::make_unique< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>()), - last_config_hash_(0ull) {} - - // Router::RouteConfigUpdateReceiver - bool - onRdsUpdate(const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc, - const std::string& version_info) override; - const std::string& routeConfigName() const override { return route_config_proto_->name(); } - const std::string& configVersion() const override { return last_config_version_; } - uint64_t configHash() const override { return last_config_hash_; } - absl::optional configInfo() const override { - return config_info_; - } - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& - protobufConfiguration() override { - return static_cast< - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>( - *route_config_proto_); - } - ConfigConstSharedPtr parsedConfiguration() const override { return config_; } - SystemTime lastUpdated() const override { return last_updated_; } - -private: - TimeSource& time_source_; - std::unique_ptr - route_config_proto_; - uint64_t last_config_hash_; - std::string last_config_version_; - SystemTime last_updated_; - absl::optional config_info_; - ConfigConstSharedPtr config_; -}; - -} // namespace Router -} // namespace ThriftProxy -} // namespace NetworkFilters -} // namespace Extensions -} // namespace Envoy diff --git a/test/common/router/BUILD b/test/common/router/BUILD index 596a8a86e7a3f..c381a063e0435 100644 --- a/test/common/router/BUILD +++ b/test/common/router/BUILD @@ -114,6 +114,16 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "rds_template_test", + srcs = ["rds_template_test.cc"], + deps = [ + "//source/common/router:rds_template_lib", + "//test/mocks/server:instance_mocks", + "@envoy_api//envoy/config/route/v3:pkg_cc_proto", + ], +) + envoy_cc_test( name = "scoped_config_impl_test", srcs = ["scoped_config_impl_test.cc"], diff --git a/test/common/router/rds_impl_test.cc b/test/common/router/rds_impl_test.cc index 05aba26966cc4..f34ca44aa38a0 100644 --- a/test/common/router/rds_impl_test.cc +++ b/test/common/router/rds_impl_test.cc @@ -668,6 +668,19 @@ TEST_F(RdsImplTest, VirtualHostUpdateWhenProviderHasBeenDeallocated) { EXPECT_NO_THROW(post_cb()); } +TEST_F(RdsImplTest, RdsRouteConfigProviderImplSubscriptionSetup) { + setup(); + EXPECT_CALL(init_watcher_, ready()); + RdsRouteConfigSubscription& subscription = + dynamic_cast(*rds_).subscription(); + Rds::RdsRouteConfigSubscription& base = + subscription; + EXPECT_NE(static_cast(&subscription.routeConfigProvider()), + static_cast(&base.routeConfigProvider())); + EXPECT_EQ(rds_.get(), subscription.routeConfigProvider().value()); + EXPECT_EQ(rds_.get(), base.routeConfigProvider().value()); +} + class RdsRouteConfigSubscriptionTest : public RdsTestBase { public: RdsRouteConfigSubscriptionTest() { diff --git a/test/common/router/rds_template_test.cc b/test/common/router/rds_template_test.cc new file mode 100644 index 0000000000000..28fb127c87554 --- /dev/null +++ b/test/common/router/rds_template_test.cc @@ -0,0 +1,157 @@ +#include +#include +#include + +#include "envoy/config/route/v3/route.pb.h" +#include "envoy/stats/scope.h" + +#include "source/common/config/utility.h" +#include "source/common/router/rds/route_config_update_receiver_impl.h" + +#include "test/mocks/protobuf/mocks.h" +#include "test/mocks/server/instance.h" +#include "test/test_common/simulated_time_system.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::_; +using testing::Eq; +using testing::InSequence; +using testing::Invoke; +using testing::ReturnRef; + +namespace Envoy { +namespace Router { +namespace { + +class RdsTestBase : public testing::Test { +public: + RdsTestBase() { + ON_CALL(server_factory_context_, scope()).WillByDefault(ReturnRef(scope_)); + ON_CALL(server_factory_context_, messageValidationContext()) + .WillByDefault(ReturnRef(validation_context_)); + } + + Event::SimulatedTimeSystem& timeSystem() { return time_system_; } + + Event::SimulatedTimeSystem time_system_; + NiceMock validation_context_; + NiceMock server_factory_context_; + NiceMock scope_; +}; + +class Config { +public: + Config() {} + Config(const envoy::config::route::v3::RouteConfiguration& rc) : rc_(rc) {} + const std::string* route(const std::string& name) const { + for (const auto& virtual_host_config : rc_.virtual_hosts()) { + if (virtual_host_config.name() == name) { + return &virtual_host_config.name(); + } + } + return nullptr; + } + +private: + envoy::config::route::v3::RouteConfiguration rc_; +}; + +class ConfigFactory + : public Rds::ConfigFactory { +public: + std::shared_ptr + createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const { + return std::make_shared(rc); + } + std::shared_ptr createConfig() const { return std::make_shared(); } +}; + +using RouteConfigUpdatePtr = std::unique_ptr< + Rds::RouteConfigUpdateReceiver>; +using RouteConfigUpdateReceiverImpl = + Rds::RouteConfigUpdateReceiverImpl; + +class RdsImplTest : public RdsTestBase { +public: + ~RdsImplTest() override { server_factory_context_.thread_local_.shutdownThread(); } + + void setup() { + config_update_ = + std::make_unique(server_factory_context_, config_factory_); + } + + const std::string* route(const std::string& path) { + return config_update_->parsedConfiguration()->route(path); + } + + ConfigFactory config_factory_; + RouteConfigUpdatePtr config_update_; +}; + +TEST_F(RdsImplTest, Basic) { + setup(); + + EXPECT_FALSE(config_update_->parsedConfiguration()); + EXPECT_FALSE(config_update_->configInfo().has_value()); + + const std::string response1_json = R"EOF( +{ + "name": "foo_route_config", + "virtual_hosts": null +} +)EOF"; + auto response1 = + TestUtility::parseYaml(response1_json); + + SystemTime time1(std::chrono::milliseconds(1234567891234)); + timeSystem().setSystemTime(time1); + + EXPECT_TRUE(config_update_->onRdsUpdate(response1, "1")); + EXPECT_EQ(nullptr, route("foo")); + EXPECT_EQ("1", config_update_->configVersion()); + EXPECT_EQ(time1, config_update_->lastUpdated()); + EXPECT_TRUE(config_update_->configInfo().has_value()); + EXPECT_EQ(config_update_->configVersion(), config_update_->configInfo().value().version_); + + EXPECT_FALSE(config_update_->onRdsUpdate(response1, "2")); + EXPECT_EQ(nullptr, route("foo")); + EXPECT_EQ("1", config_update_->configVersion()); + + std::shared_ptr config = config_update_->parsedConfiguration(); + EXPECT_EQ(2, config.use_count()); + + const std::string response2_json = R"EOF( +{ + "name": "foo_route_config", + "virtual_hosts": [ + { + "name": "foo", + "domains": [ + "*" + ], + } + ] +} + )EOF"; + + auto response2 = + TestUtility::parseYaml(response2_json); + + SystemTime time2(std::chrono::milliseconds(1234567891235)); + timeSystem().setSystemTime(time2); + + EXPECT_TRUE(config_update_->onRdsUpdate(response2, "2")); + EXPECT_EQ("foo", *route("foo")); + EXPECT_EQ("2", config_update_->configVersion()); + EXPECT_EQ(time2, config_update_->lastUpdated()); + EXPECT_TRUE(config_update_->configInfo().has_value()); + EXPECT_EQ(config_update_->configVersion(), config_update_->configInfo().value().version_); + + EXPECT_EQ(1, config.use_count()); +} + +} // namespace +} // namespace Router +} // namespace Envoy diff --git a/test/common/router/vhds_test.cc b/test/common/router/vhds_test.cc index 28e933675b189..e23a6cdb4caec 100644 --- a/test/common/router/vhds_test.cc +++ b/test/common/router/vhds_test.cc @@ -10,6 +10,7 @@ #include "source/common/config/utility.h" #include "source/common/protobuf/protobuf.h" #include "source/common/router/rds_impl.h" +#include "source/common/router/route_config_update_receiver_impl.h" #include "source/server/admin/admin.h" #include "test/mocks/config/mocks.h" @@ -96,7 +97,8 @@ TEST_F(VhdsTest, VhdsInstantiationShouldSucceedWithDELTA_GRPC) { TestUtility::parseYaml(default_vhds_config_); RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config); - EXPECT_NO_THROW(VhdsSubscription(config_update_info, factory_context_, context_, provider_)); + EXPECT_NO_THROW( + VhdsSubscription(config_update_info.get(), factory_context_, context_, provider_)); } // verify that api_type: GRPC fails validation @@ -114,7 +116,7 @@ name: my_route )EOF"); RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config); - EXPECT_THROW(VhdsSubscription(config_update_info, factory_context_, context_, provider_), + EXPECT_THROW(VhdsSubscription(config_update_info.get(), factory_context_, context_, provider_), EnvoyException); } @@ -124,7 +126,7 @@ TEST_F(VhdsTest, VhdsAddsVirtualHosts) { TestUtility::parseYaml(default_vhds_config_); RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config); - VhdsSubscription subscription(config_update_info, factory_context_, context_, provider_); + VhdsSubscription subscription(config_update_info.get(), factory_context_, context_, provider_); EXPECT_EQ(0UL, config_update_info->protobufConfiguration().virtual_hosts_size()); auto vhost = buildVirtualHost("vhost1", "vhost.first"); @@ -183,7 +185,7 @@ name: my_route )EOF"); RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config); - VhdsSubscription subscription(config_update_info, factory_context_, context_, provider_); + VhdsSubscription subscription(config_update_info.get(), factory_context_, context_, provider_); EXPECT_EQ(1UL, config_update_info->protobufConfiguration().virtual_hosts_size()); EXPECT_EQ("vhost_rds1", config_update_info->protobufConfiguration().virtual_hosts(0).name()); diff --git a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc index cf6090b2151ab..ca9a505cea125 100644 --- a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc +++ b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc @@ -11,6 +11,7 @@ #include "source/common/config/utility.h" #include "source/common/json/json_loader.h" +#include "source/common/router/rds/rds_route_config_provider_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" #include "test/mocks/init/mocks.h" @@ -42,13 +43,6 @@ namespace { using ::Envoy::Matchers::MockStringMatcher; using ::Envoy::Matchers::UniversalStringMatcher; -envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy -parseThriftProxyFromYaml(const std::string& yaml_string) { - envoy::extensions::filters::network::thrift_proxy::v3::ThriftProxy thrift_proxy; - TestUtility::loadFromYaml(yaml_string, thrift_proxy); - return thrift_proxy; -} - class RdsTestBase : public testing::Test { public: RdsTestBase() { @@ -80,177 +74,8 @@ class RdsTestBase : public testing::Test { NiceMock scope_; }; -class RdsImplTest : public RdsTestBase { -public: - RdsImplTest() { - EXPECT_CALL(server_factory_context_.admin_.config_tracker_, add_("routes", _)); - route_config_provider_manager_ = - std::make_unique(server_factory_context_.admin_); - } - ~RdsImplTest() override { server_factory_context_.thread_local_.shutdownThread(); } - - void setup() { - std::string config_yaml = R"EOF( -rds: - config_source: - api_config_source: - api_type: REST - cluster_names: - - foo_cluster - refresh_delay: 1s - route_config_name: foo_route_config - )EOF"; - - EXPECT_CALL(outer_init_manager_, add(_)); - rds_ = route_config_provider_manager_->createRdsRouteConfigProvider( - parseThriftProxyFromYaml(config_yaml).rds(), server_factory_context_, "foo.", - outer_init_manager_); - rds_callbacks_ = server_factory_context_.cluster_manager_.subscription_factory_.callbacks_; - EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, - start(_)); - outer_init_manager_.initialize(init_watcher_); - } - - RouteConstSharedPtr route(const MessageMetadata& metadata) { - return rds_->config()->route(metadata, 12345); - } - - RouteConfigProviderManagerImplPtr route_config_provider_manager_; - RouteConfigProviderSharedPtr rds_; -}; - -TEST_F(RdsImplTest, DestroyDuringInitialize) { - InSequence s; - setup(); - EXPECT_CALL(init_watcher_, ready()); - rds_.reset(); -} - -TEST_F(RdsImplTest, Basic) { - InSequence s; - Buffer::OwnedImpl empty; - Buffer::OwnedImpl data; - - setup(); - - // Make sure the initial empty route table works. - MessageMetadata md; - md.setMethodName("foo"); - EXPECT_EQ(nullptr, route(md)); - - // Initial request. - const std::string response1_json = R"EOF( -{ - "version_info": "1", - "resources": [ - { - "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", - "name": "foo_route_config", - "routes": null - } - ] -} -)EOF"; - auto response1 = - TestUtility::parseYaml(response1_json); - const auto decoded_resources = TestUtility::decodeResources< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response1); - - EXPECT_CALL(init_watcher_, ready()); - rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()); - md.setMethodName("bar"); - EXPECT_EQ(nullptr, route(md)); - - // 2nd request with same response. Based on hash should not reload config. - rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()); - EXPECT_EQ(nullptr, route(md)); - - // Load the config and verified shared count. - // ConfigConstSharedPtr is shared between: RouteConfigUpdateReceiverImpl, rds_ (via tls_), and - // config local var below. - ConfigConstSharedPtr config = rds_->config(); - EXPECT_EQ(3, config.use_count()); - - // Third request. - const std::string response2_json = R"EOF( -{ - "version_info": "2", - "resources": [ - { - "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", - "name": "foo_route_config", - "routes": [ - { - "match": - { - "method_name": "bar" - }, - "route": - { - "cluster": "foo" - } - } - ] - } - ] -} - )EOF"; - auto response2 = - TestUtility::parseYaml(response2_json); - const auto decoded_resources_2 = TestUtility::decodeResources< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response2); - - // Make sure we don't lookup/verify clusters. - EXPECT_CALL(server_factory_context_.cluster_manager_, getThreadLocalCluster(Eq("bar"))).Times(0); - rds_callbacks_->onConfigUpdate(decoded_resources_2.refvec_, response2.version_info()); - EXPECT_EQ("foo", route(md)->routeEntry()->clusterName()); - - // Old config use count should be 1 now. - EXPECT_EQ(1, config.use_count()); - EXPECT_EQ(2UL, scope_.counter("foo.rds.foo_route_config.config_reload").value()); - EXPECT_TRUE(scope_.findGaugeByString("foo.rds.foo_route_config.config_reload_time_ms")); -} - -// Validate behavior when the config is delivered but it fails PGV validation. -TEST_F(RdsImplTest, FailureInvalidConfig) { - InSequence s; - - setup(); - - const std::string response1_json = R"EOF( -{ - "version_info": "1", - "resources": [ - { - "@type": "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration", - "name": "INVALID_NAME_FOR_route_config", - "routes": null - } - ] -} -)EOF"; - auto response1 = - TestUtility::parseYaml(response1_json); - const auto decoded_resources = TestUtility::decodeResources< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(response1); - - EXPECT_CALL(init_watcher_, ready()); - EXPECT_THROW_WITH_MESSAGE( - rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()), - EnvoyException, - "Unexpected RDS configuration (expecting foo_route_config): INVALID_NAME_FOR_route_config"); -} - -// Validate behavior when the config fails delivery at the subscription level. -TEST_F(RdsImplTest, FailureSubscription) { - InSequence s; - - setup(); - - EXPECT_CALL(init_watcher_, ready()); - // onConfigUpdateFailed() should not be called for gRPC stream connection failure - rds_callbacks_->onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason::FetchTimedout, {}); -} +using RdsRouteConfigProviderImpl = Envoy::Router::Rds::RdsRouteConfigProviderImpl< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; class RouteConfigProviderManagerImplTest : public RdsTestBase { public: @@ -551,29 +376,6 @@ name: foo_route_config } } -TEST_F(RouteConfigProviderManagerImplTest, OnConfigUpdateEmpty) { - setup(); - EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, - start(_)); - outer_init_manager_.initialize(init_watcher_); - EXPECT_CALL(init_watcher_, ready()); - server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate({}, ""); -} - -TEST_F(RouteConfigProviderManagerImplTest, OnConfigUpdateWrongSize) { - setup(); - EXPECT_CALL(*server_factory_context_.cluster_manager_.subscription_factory_.subscription_, - start(_)); - outer_init_manager_.initialize(init_watcher_); - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration route_config; - const auto decoded_resources = TestUtility::decodeResources({route_config, route_config}); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_THROW_WITH_MESSAGE( - server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( - decoded_resources.refvec_, ""), - EnvoyException, "Unexpected RDS resource length: 2"); -} - } // namespace } // namespace Router } // namespace ThriftProxy From aeb9476b872b81bff965f6782f4c787030b2f6bb Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 30 Sep 2021 00:39:57 +0800 Subject: [PATCH 11/31] Fix RouteConfigUpdateReceiverImpl::onVhdsUpdate Even if the config was invalid it was stored. This confused delta updates. Signed-off-by: Tamas Kovacs --- source/common/router/rds/route_config_update_receiver_impl.h | 2 +- source/common/router/route_config_update_receiver_impl.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/common/router/rds/route_config_update_receiver_impl.h b/source/common/router/rds/route_config_update_receiver_impl.h index 56e7903632652..6a47da1e7287c 100644 --- a/source/common/router/rds/route_config_update_receiver_impl.h +++ b/source/common/router/rds/route_config_update_receiver_impl.h @@ -30,8 +30,8 @@ class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver&& route_config_proto) { + config_ = config_factory_.createConfig(*route_config_proto); route_config_proto_ = std::move(route_config_proto); - config_ = config_factory_.createConfig(*route_config_proto_); } void onUpdateCommon(const std::string& version_info) { diff --git a/source/common/router/route_config_update_receiver_impl.cc b/source/common/router/route_config_update_receiver_impl.cc index 58b7f116f90dc..f55c5c4b352ca 100644 --- a/source/common/router/route_config_update_receiver_impl.cc +++ b/source/common/router/route_config_update_receiver_impl.cc @@ -49,9 +49,9 @@ bool RouteConfigUpdateReceiverImpl::onVhdsUpdate( rebuildRouteConfig(rds_virtual_hosts_, *vhosts_after_this_update, *route_config_after_this_update); + base_.updateConfig(std::move(route_config_after_this_update)); // No exception, route_config_after_this_update is valid, can update the state. vhds_virtual_hosts_ = std::move(vhosts_after_this_update); - base_.updateConfig(std::move(route_config_after_this_update)); resource_ids_in_last_update_ = added_resource_ids; base_.onUpdateCommon(version_info); From 7811138bd75379a598a4f8791b77067eb34ad7cd Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sun, 3 Oct 2021 00:28:46 +0800 Subject: [PATCH 12/31] Fix clang-tidy errors Signed-off-by: Tamas Kovacs --- envoy/router/rds/route_config_provider.h | 2 ++ source/common/router/rds/config_factory.h | 2 ++ .../router/rds/rds_route_config_provider_impl.h | 2 +- test/common/router/rds_template_test.cc | 12 +++++------- .../filters/network/thrift_proxy/rds_impl_test.cc | 2 -- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/envoy/router/rds/route_config_provider.h b/envoy/router/rds/route_config_provider.h index b2808e1386b67..f7680627acd1d 100644 --- a/envoy/router/rds/route_config_provider.h +++ b/envoy/router/rds/route_config_provider.h @@ -4,6 +4,8 @@ #include "envoy/common/time.h" +#include "absl/types/optional.h" + namespace Envoy { namespace Router { namespace Rds { diff --git a/source/common/router/rds/config_factory.h b/source/common/router/rds/config_factory.h index 56ecea8f10da4..8bf93e8b8d0fb 100644 --- a/source/common/router/rds/config_factory.h +++ b/source/common/router/rds/config_factory.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "envoy/common/pure.h" namespace Envoy { diff --git a/source/common/router/rds/rds_route_config_provider_impl.h b/source/common/router/rds/rds_route_config_provider_impl.h index 2da071a569402..9115478fcbb97 100644 --- a/source/common/router/rds/rds_route_config_provider_impl.h +++ b/source/common/router/rds/rds_route_config_provider_impl.h @@ -35,7 +35,7 @@ class RdsRouteConfigProviderImpl : public RouteConfigProvider initial_config; if (config_update_info_->configInfo().has_value()) { initial_config = - config_factory.createConfig(subscription->routeConfigUpdate()->protobufConfiguration()); + config_factory.createConfig(subscription_->routeConfigUpdate()->protobufConfiguration()); } else { initial_config = config_factory.createConfig(); } diff --git a/test/common/router/rds_template_test.cc b/test/common/router/rds_template_test.cc index 28fb127c87554..6e65bc0f8671a 100644 --- a/test/common/router/rds_template_test.cc +++ b/test/common/router/rds_template_test.cc @@ -15,10 +15,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using testing::_; -using testing::Eq; -using testing::InSequence; -using testing::Invoke; using testing::ReturnRef; namespace Envoy { @@ -43,7 +39,7 @@ class RdsTestBase : public testing::Test { class Config { public: - Config() {} + Config() = default; Config(const envoy::config::route::v3::RouteConfiguration& rc) : rc_(rc) {} const std::string* route(const std::string& name) const { for (const auto& virtual_host_config : rc_.virtual_hosts()) { @@ -62,10 +58,12 @@ class ConfigFactory : public Rds::ConfigFactory { public: std::shared_ptr - createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const { + createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const override { return std::make_shared(rc); } - std::shared_ptr createConfig() const { return std::make_shared(); } + std::shared_ptr createConfig() const override { + return std::make_shared(); + } }; using RouteConfigUpdatePtr = std::unique_ptr< diff --git a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc index ca9a505cea125..43a9bb1ae6d0e 100644 --- a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc +++ b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc @@ -28,8 +28,6 @@ #include "gtest/gtest.h" using testing::_; -using testing::Eq; -using testing::InSequence; using testing::Invoke; using testing::ReturnRef; From 508f7112c154be029aaa7778567086ec71500009 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sun, 3 Oct 2021 13:11:32 +0800 Subject: [PATCH 13/31] Fix clang-tidy errors, missing build dependencies Signed-off-by: Tamas Kovacs --- source/common/router/BUILD | 28 +++++++++---------- .../filters/network/thrift_proxy/router/BUILD | 9 ------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 8c7ce4f820d03..2ca839126f990 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -172,20 +172,6 @@ envoy_cc_library( "//envoy/router:route_config_provider_manager_interface", "//envoy/router:route_config_update_info_interface", "//envoy/server:admin_interface", - "//envoy/singleton:instance_interface", - "//envoy/thread_local:thread_local_interface", - "//source/common/common:assert_lib", - "//source/common/common:callback_impl_lib", - "//source/common/common:cleanup_lib", - "//source/common/common:minimal_logger_lib", - "//source/common/config:api_version_lib", - "//source/common/config:subscription_base_interface", - "//source/common/config:subscription_factory_lib", - "//source/common/config:utility_lib", - "//source/common/init:manager_lib", - "//source/common/init:target_lib", - "//source/common/init:watcher_lib", - "//source/common/protobuf:utility_lib", "//source/common/router:rds_template_lib", "//source/common/router:route_config_update_impl_lib", "//source/common/router:vhds_lib", @@ -437,6 +423,20 @@ envoy_cc_library( ], deps = [ "//envoy/router:rds_template_interface", + "//envoy/singleton:instance_interface", + "//envoy/thread_local:thread_local_interface", + "//source/common/common:assert_lib", + "//source/common/common:callback_impl_lib", + "//source/common/common:cleanup_lib", + "//source/common/common:minimal_logger_lib", + "//source/common/config:api_version_lib", + "//source/common/config:subscription_base_interface", + "//source/common/config:subscription_factory_lib", + "//source/common/config:utility_lib", + "//source/common/init:manager_lib", + "//source/common/init:target_lib", + "//source/common/init:watcher_lib", + "//source/common/protobuf:utility_lib", "@envoy_api//envoy/admin/v3:pkg_cc_proto", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], diff --git a/source/extensions/filters/network/thrift_proxy/router/BUILD b/source/extensions/filters/network/thrift_proxy/router/BUILD index ffd03a1278ca4..570983c018afe 100644 --- a/source/extensions/filters/network/thrift_proxy/router/BUILD +++ b/source/extensions/filters/network/thrift_proxy/router/BUILD @@ -149,16 +149,7 @@ envoy_cc_library( deps = [ ":config", ":rds_interface", - "//envoy/common:time_interface", - "//envoy/config:subscription_interface", - "//envoy/local_info:local_info_interface", "//envoy/router:rds_template_interface", - "//source/common/config:api_version_lib", - "//source/common/config:subscription_base_interface", - "//source/common/config:utility_lib", - "//source/common/init:manager_lib", - "//source/common/init:target_lib", - "//source/common/protobuf:utility_lib", "//source/common/router:rds_template_lib", "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", ], From 8ca0a4f40633337f742235c4fe8d4a3ad31e0020 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Mon, 4 Oct 2021 23:33:39 +0800 Subject: [PATCH 14/31] Debug strange lua filter coverage issue Signed-off-by: Tamas Kovacs --- source/common/router/rds/rds_route_config_provider_impl.h | 8 ++++++-- source/common/router/rds/rds_route_config_subscription.h | 4 ++++ source/extensions/filters/http/lua/lua_filter.h | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/source/common/router/rds/rds_route_config_provider_impl.h b/source/common/router/rds/rds_route_config_provider_impl.h index 9115478fcbb97..b50a62b1d5b3b 100644 --- a/source/common/router/rds/rds_route_config_provider_impl.h +++ b/source/common/router/rds/rds_route_config_provider_impl.h @@ -64,8 +64,12 @@ class RdsRouteConfigProviderImpl : public RouteConfigProviderlastUpdated(); } void onConfigUpdate() override { - tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( - OptRef tls) { tls->config_ = new_config; }); + tls_.runOnAllThreads( + [new_config = config_update_info_->parsedConfiguration()](OptRef tls) { + printf("XXXX %ld tls\n", syscall(SYS_gettid)); + tls->config_ = new_config; + printf("XXXX tls end\n"); + }); } void validateConfig(const RouteConfiguration&) const override {} diff --git a/source/common/router/rds/rds_route_config_subscription.h b/source/common/router/rds/rds_route_config_subscription.h index 8c2b98b88453f..998a1829ac3c2 100644 --- a/source/common/router/rds/rds_route_config_subscription.h +++ b/source/common/router/rds/rds_route_config_subscription.h @@ -114,9 +114,13 @@ class RdsRouteConfigSubscription : Envoy::Config::SubscriptionBasevalidateConfig(route_config); + printf("XXXX validateConfig end\n"); } + printf("XXXX onRdsUpdate\n"); if (config_update_info_->onRdsUpdate(route_config, version_info)) { + printf("XXXX onRdsUpdate end\n"); stats_.config_reload_.inc(); stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index 17c9338627965..0c38940057f1b 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -384,6 +384,9 @@ class FilterConfigPerRoute : public Router::RouteSpecificFilterConfig { // ensure thread safety, ownership of per_lua_code_setup_ptr_ must be transferred to the main // thread and destroyed when the FilterConfigPerRoute object is not destructed in the main // thread. + printf("XXXX %p pointer %d thread safe %d\n", this, + static_cast(per_lua_code_setup_ptr_ != nullptr), + static_cast(main_thread_dispatcher_.isThreadSafe())); if (per_lua_code_setup_ptr_ && !main_thread_dispatcher_.isThreadSafe()) { auto shared_ptr_wrapper = std::make_shared(std::move(per_lua_code_setup_ptr_)); From 639148d4037683b666bc663fc294b6913e398b77 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Mon, 4 Oct 2021 23:33:39 +0800 Subject: [PATCH 15/31] Revert: Debug strange lua filter coverage issue Signed-off-by: Tamas Kovacs --- source/common/router/rds/rds_route_config_provider_impl.h | 8 ++------ source/common/router/rds/rds_route_config_subscription.h | 4 ---- source/extensions/filters/http/lua/lua_filter.h | 3 --- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/source/common/router/rds/rds_route_config_provider_impl.h b/source/common/router/rds/rds_route_config_provider_impl.h index b50a62b1d5b3b..9115478fcbb97 100644 --- a/source/common/router/rds/rds_route_config_provider_impl.h +++ b/source/common/router/rds/rds_route_config_provider_impl.h @@ -64,12 +64,8 @@ class RdsRouteConfigProviderImpl : public RouteConfigProviderlastUpdated(); } void onConfigUpdate() override { - tls_.runOnAllThreads( - [new_config = config_update_info_->parsedConfiguration()](OptRef tls) { - printf("XXXX %ld tls\n", syscall(SYS_gettid)); - tls->config_ = new_config; - printf("XXXX tls end\n"); - }); + tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( + OptRef tls) { tls->config_ = new_config; }); } void validateConfig(const RouteConfiguration&) const override {} diff --git a/source/common/router/rds/rds_route_config_subscription.h b/source/common/router/rds/rds_route_config_subscription.h index 998a1829ac3c2..8c2b98b88453f 100644 --- a/source/common/router/rds/rds_route_config_subscription.h +++ b/source/common/router/rds/rds_route_config_subscription.h @@ -114,13 +114,9 @@ class RdsRouteConfigSubscription : Envoy::Config::SubscriptionBasevalidateConfig(route_config); - printf("XXXX validateConfig end\n"); } - printf("XXXX onRdsUpdate\n"); if (config_update_info_->onRdsUpdate(route_config, version_info)) { - printf("XXXX onRdsUpdate end\n"); stats_.config_reload_.inc(); stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index 0c38940057f1b..17c9338627965 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -384,9 +384,6 @@ class FilterConfigPerRoute : public Router::RouteSpecificFilterConfig { // ensure thread safety, ownership of per_lua_code_setup_ptr_ must be transferred to the main // thread and destroyed when the FilterConfigPerRoute object is not destructed in the main // thread. - printf("XXXX %p pointer %d thread safe %d\n", this, - static_cast(per_lua_code_setup_ptr_ != nullptr), - static_cast(main_thread_dispatcher_.isThreadSafe())); if (per_lua_code_setup_ptr_ && !main_thread_dispatcher_.isThreadSafe()) { auto shared_ptr_wrapper = std::make_shared(std::move(per_lua_code_setup_ptr_)); From 054460eb7d8114d3a5efdfa7da9300bf4d03f364 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 6 Oct 2021 01:29:53 +0800 Subject: [PATCH 16/31] Separate service endpoint to Thrift rds Signed-off-by: Tamas Kovacs --- api/envoy/annotations/resource.proto | 4 -- .../filters/network/thrift_proxy/v3/BUILD | 2 + .../filters/network/thrift_proxy/v3/rds.proto | 48 +++++++++++++++++++ .../network/thrift_proxy/v3/route.proto | 2 - .../thrift_proxy/v3/thrift_proxy.proto | 10 ++-- source/common/config/type_to_endpoint.cc | 30 ++---------- .../filters/network/thrift_proxy/config.cc | 3 +- test/common/config/type_to_endpoint_test.cc | 8 ++-- 8 files changed, 66 insertions(+), 41 deletions(-) create mode 100644 api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto diff --git a/api/envoy/annotations/resource.proto b/api/envoy/annotations/resource.proto index f57b262bbee63..bd794c68dd7a6 100644 --- a/api/envoy/annotations/resource.proto +++ b/api/envoy/annotations/resource.proto @@ -11,10 +11,6 @@ extend google.protobuf.ServiceOptions { ResourceAnnotation resource = 265073217; } -extend google.protobuf.MessageOptions { - ResourceAnnotation resource_alias = 265073217; -} - message ResourceAnnotation { // Annotation for xDS services that indicates the fully-qualified Protobuf type for the resource // type. diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD b/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD index cdb143507f644..15d0dd94511a8 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD @@ -5,11 +5,13 @@ load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") licenses(["notice"]) # Apache 2 api_proto_package( + has_services = True, deps = [ "//envoy/annotations:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/filter/network/thrift_proxy/v2alpha1:pkg", "//envoy/config/route/v3:pkg", + "//envoy/service/discovery/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", ], ) diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto new file mode 100644 index 0000000000000..e753c7355188c --- /dev/null +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; + +package envoy.extensions.filters.network.thrift_proxy.v3; + +import "envoy/service/discovery/v3/discovery.proto"; + +import "google/api/annotations.proto"; + +import "envoy/annotations/resource.proto"; +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.network.thrift_proxy.v3"; +option java_outer_classname = "RdsProto"; +option java_multiple_files = true; +option java_generic_services = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: RDS] + +// The resource_names field in DiscoveryRequest specifies a route configuration. +// This allows an Envoy configuration with multiple Thrift listeners (and +// associated Thrift proxy filters) to use different route +// configurations. Each listener will bind its Thrift proxy filter to +// a route table via this identifier. +service RouteDiscoveryService { + option (envoy.annotations.resource).type = + "envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration"; + + rpc StreamRoutes(stream service.discovery.v3.DiscoveryRequest) + returns (stream service.discovery.v3.DiscoveryResponse) { + } + + rpc DeltaRoutes(stream service.discovery.v3.DeltaDiscoveryRequest) + returns (stream service.discovery.v3.DeltaDiscoveryResponse) { + } + + rpc FetchRoutes(service.discovery.v3.DiscoveryRequest) + returns (service.discovery.v3.DiscoveryResponse) { + option (google.api.http).post = "/v3/discovery:thrift_routes"; + option (google.api.http).body = "*"; + } +} + +// [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing +// services: https://github.com/google/protobuf/issues/4221 and protoxform to upgrade the file. +message RdsDummy { +} diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto index 82a03812352e8..b79c9bc9619ea 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/route.proto @@ -7,7 +7,6 @@ import "envoy/config/route/v3/route_components.proto"; import "google/protobuf/wrappers.proto"; -import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -23,7 +22,6 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; message RouteConfiguration { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.thrift_proxy.v2alpha1.RouteConfiguration"; - option (envoy.annotations.resource_alias).type = "envoy.config.route.v3.RouteConfiguration"; // The name of the route configuration. Reserved for future use in asynchronous route discovery. string name = 1; diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index 5336ed1ade1b4..35b0e86e1d2af 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -76,7 +76,12 @@ message ThriftProxy { string stat_prefix = 1 [(validate.rules).string = {min_len: 1}]; // The route table for the connection manager is static and is specified in this property. - RouteConfiguration route_config = 4; + oneof route_specifier { + RouteConfiguration route_config = 4; + + // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. + Rds rds = 8; + } // A list of individual Thrift filters that make up the filter chain for requests made to the // Thrift proxy. Order matters as the filters are processed sequentially. For backwards @@ -93,9 +98,6 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; - - // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. - Rds rds = 8; } // ThriftFilter configures a Thrift filter. diff --git a/source/common/config/type_to_endpoint.cc b/source/common/config/type_to_endpoint.cc index 924f659c03c3c..f072162d776ed 100644 --- a/source/common/config/type_to_endpoint.cc +++ b/source/common/config/type_to_endpoint.cc @@ -59,6 +59,7 @@ TypeUrlToV3ServiceMap* buildTypeUrlToServiceMap() { "envoy.service.listener.v3.ListenerDiscoveryService", "envoy.service.runtime.v3.RuntimeDiscoveryService", "envoy.service.extension.v3.ExtensionConfigDiscoveryService", + "envoy.extensions.filters.network.thrift_proxy.v3.RouteDiscoveryService", }) { const TypeUrl resource_type_url = getResourceTypeUrl(name); V3Service& service = (*type_url_to_versioned_service_map)[resource_type_url]; @@ -91,45 +92,22 @@ TypeUrlToV3ServiceMap& typeUrlToV3ServiceMap() { return *type_url_to_versioned_service_map; } -TypeUrlToV3ServiceMap::iterator findV3Service(const std::string& type_url) { - const auto it = typeUrlToV3ServiceMap().find(type_url); - if (it != typeUrlToV3ServiceMap().cend()) { - return it; - } - std::string message_name = type_url; - const std::string& typeUrlPrefix = Grpc::Common::typeUrlPrefix(); - if (message_name.compare(0, typeUrlPrefix.length(), typeUrlPrefix) == 0) { - if (message_name[typeUrlPrefix.length()] == '/') { - message_name.erase(0, typeUrlPrefix.length() + 1); - } - } - const auto* message_desc = - Protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(message_name); - if (message_desc != nullptr && - message_desc->options().HasExtension(envoy::annotations::resource_alias)) { - const std::string& resource = - message_desc->options().GetExtension(envoy::annotations::resource_alias).type(); - return typeUrlToV3ServiceMap().find(Grpc::Common::typeUrl(resource)); - } - return typeUrlToV3ServiceMap().end(); -} - } // namespace const Protobuf::MethodDescriptor& deltaGrpcMethod(absl::string_view type_url) { - const auto it = findV3Service(static_cast(type_url)); + const auto it = typeUrlToV3ServiceMap().find(static_cast(type_url)); ASSERT(it != typeUrlToV3ServiceMap().cend()); return *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(it->second.delta_grpc_); } const Protobuf::MethodDescriptor& sotwGrpcMethod(absl::string_view type_url) { - const auto it = findV3Service(static_cast(type_url)); + const auto it = typeUrlToV3ServiceMap().find(static_cast(type_url)); ASSERT(it != typeUrlToV3ServiceMap().cend()); return *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(it->second.sotw_grpc_); } const Protobuf::MethodDescriptor& restMethod(absl::string_view type_url) { - const auto it = findV3Service(static_cast(type_url)); + const auto it = typeUrlToV3ServiceMap().find(static_cast(type_url)); ASSERT(it != typeUrlToV3ServiceMap().cend()); return *Protobuf::DescriptorPool::generated_pool()->FindMethodByName(it->second.rest_); } diff --git a/source/extensions/filters/network/thrift_proxy/config.cc b/source/extensions/filters/network/thrift_proxy/config.cc index a5bdc0376e8d0..53f2eb12860fd 100644 --- a/source/extensions/filters/network/thrift_proxy/config.cc +++ b/source/extensions/filters/network/thrift_proxy/config.cc @@ -147,7 +147,8 @@ ConfigImpl::ConfigImpl( } } - if (config.has_rds()) { + if (config.route_specifier_case() == envoy::extensions::filters::network::thrift_proxy::v3:: + ThriftProxy::RouteSpecifierCase::kRds) { route_config_provider_ = route_config_provider_manager.createRdsRouteConfigProvider( config.rds(), context_.getServerFactoryContext(), stats_prefix_, context_.initManager()); } else { diff --git a/test/common/config/type_to_endpoint_test.cc b/test/common/config/type_to_endpoint_test.cc index fbceb32a7c269..66bf37a9179c0 100644 --- a/test/common/config/type_to_endpoint_test.cc +++ b/test/common/config/type_to_endpoint_test.cc @@ -1,5 +1,5 @@ #include "envoy/api/v2/rds.pb.h" -#include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" +#include "envoy/extensions/filters/network/thrift_proxy/v3/rds.pb.h" #include "envoy/service/route/v3/rds.pb.h" #include "source/common/config/type_to_endpoint.h" @@ -43,12 +43,12 @@ TEST(TypeToEndpoint, All) { restMethod("type.googleapis.com/envoy.config.route.v3.RouteConfiguration").full_name()); } -TEST(TypeToEndpoint, Alias) { +TEST(TypeToEndpoint, Thrift) { // The dummy messages are included for link purposes only. - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration _route_config_dummy; + envoy::extensions::filters::network::thrift_proxy::v3::RdsDummy _v3_rds_dummy; EXPECT_EQ( - "envoy.service.route.v3.RouteDiscoveryService.StreamRoutes", + "envoy.extensions.filters.network.thrift_proxy.v3.RouteDiscoveryService.StreamRoutes", sotwGrpcMethod( "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration") .full_name()); From 0695c52a6db44a35ef7c6219b74b9662fac90f39 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 7 Oct 2021 13:33:24 +0800 Subject: [PATCH 17/31] Move service to thrift rds into api/envoy/services Signed-off-by: Tamas Kovacs --- api/BUILD | 1 + .../filters/network/thrift_proxy/v3/BUILD | 3 --- .../network/thrift_proxy/v3/thrift_proxy.proto | 12 ++++++------ api/envoy/service/thrift_route/v3/BUILD | 14 ++++++++++++++ .../thrift_route}/v3/rds.proto | 17 ++++++++--------- api/versioning/BUILD | 1 + source/common/config/BUILD | 1 + source/common/config/protobuf_link_hacks.h | 2 ++ source/common/config/type_to_endpoint.cc | 2 +- .../filters/network/thrift_proxy/config.cc | 3 +-- test/common/config/BUILD | 2 +- test/common/config/type_to_endpoint_test.cc | 6 +++--- 12 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 api/envoy/service/thrift_route/v3/BUILD rename api/envoy/{extensions/filters/network/thrift_proxy => service/thrift_route}/v3/rds.proto (69%) diff --git a/api/BUILD b/api/BUILD index 341cc48a22149..e9f0211854689 100644 --- a/api/BUILD +++ b/api/BUILD @@ -244,6 +244,7 @@ proto_library( "//envoy/service/secret/v3:pkg", "//envoy/service/status/v3:pkg", "//envoy/service/tap/v3:pkg", + "//envoy/service/thrift_route/v3:pkg", "//envoy/service/trace/v3:pkg", "//envoy/type/http/v3:pkg", "//envoy/type/matcher/v3:pkg", diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD b/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD index 15d0dd94511a8..ccacc55735afa 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/BUILD @@ -5,13 +5,10 @@ load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") licenses(["notice"]) # Apache 2 api_proto_package( - has_services = True, deps = [ - "//envoy/annotations:pkg", "//envoy/config/core/v3:pkg", "//envoy/config/filter/network/thrift_proxy/v2alpha1:pkg", "//envoy/config/route/v3:pkg", - "//envoy/service/discovery/v3:pkg", "@com_github_cncf_udpa//udpa/annotations:pkg", ], ) diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index 35b0e86e1d2af..0cb417190cb50 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -8,6 +8,7 @@ import "envoy/extensions/filters/network/thrift_proxy/v3/route.proto"; import "google/protobuf/any.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -76,12 +77,8 @@ message ThriftProxy { string stat_prefix = 1 [(validate.rules).string = {min_len: 1}]; // The route table for the connection manager is static and is specified in this property. - oneof route_specifier { - RouteConfiguration route_config = 4; - - // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. - Rds rds = 8; - } + RouteConfiguration route_config = 4 + [(udpa.annotations.field_migrate).oneof_promotion = "route_specifier"]; // A list of individual Thrift filters that make up the filter chain for requests made to the // Thrift proxy. Order matters as the filters are processed sequentially. For backwards @@ -98,6 +95,9 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; + + // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. + Rds rds = 8 [(udpa.annotations.field_migrate).oneof_promotion = "route_specifier"]; } // ThriftFilter configures a Thrift filter. diff --git a/api/envoy/service/thrift_route/v3/BUILD b/api/envoy/service/thrift_route/v3/BUILD new file mode 100644 index 0000000000000..9f2ae1e747c54 --- /dev/null +++ b/api/envoy/service/thrift_route/v3/BUILD @@ -0,0 +1,14 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + has_services = True, + deps = [ + "//envoy/annotations:pkg", + "//envoy/service/discovery/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto b/api/envoy/service/thrift_route/v3/rds.proto similarity index 69% rename from api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto rename to api/envoy/service/thrift_route/v3/rds.proto index e753c7355188c..b18b1181de978 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/rds.proto +++ b/api/envoy/service/thrift_route/v3/rds.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package envoy.extensions.filters.network.thrift_proxy.v3; +package envoy.service.thrift_route.v3; import "envoy/service/discovery/v3/discovery.proto"; @@ -10,13 +10,13 @@ import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; -option java_package = "io.envoyproxy.envoy.extensions.filters.network.thrift_proxy.v3"; +option java_package = "io.envoyproxy.envoy.service.thrift_route.v3"; option java_outer_classname = "RdsProto"; option java_multiple_files = true; option java_generic_services = true; option (udpa.annotations.file_status).package_version_status = ACTIVE; -// [#protodoc-title: RDS] +// [#protodoc-title: THRIFT_RDS] // The resource_names field in DiscoveryRequest specifies a route configuration. // This allows an Envoy configuration with multiple Thrift listeners (and @@ -27,16 +27,15 @@ service RouteDiscoveryService { option (envoy.annotations.resource).type = "envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration"; - rpc StreamRoutes(stream service.discovery.v3.DiscoveryRequest) - returns (stream service.discovery.v3.DiscoveryResponse) { + rpc StreamRoutes(stream discovery.v3.DiscoveryRequest) + returns (stream discovery.v3.DiscoveryResponse) { } - rpc DeltaRoutes(stream service.discovery.v3.DeltaDiscoveryRequest) - returns (stream service.discovery.v3.DeltaDiscoveryResponse) { + rpc DeltaRoutes(stream discovery.v3.DeltaDiscoveryRequest) + returns (stream discovery.v3.DeltaDiscoveryResponse) { } - rpc FetchRoutes(service.discovery.v3.DiscoveryRequest) - returns (service.discovery.v3.DiscoveryResponse) { + rpc FetchRoutes(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) { option (google.api.http).post = "/v3/discovery:thrift_routes"; option (google.api.http).body = "*"; } diff --git a/api/versioning/BUILD b/api/versioning/BUILD index bf34f6f1eb431..8abd9f782f1dd 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -196,6 +196,7 @@ proto_library( "//envoy/service/secret/v3:pkg", "//envoy/service/status/v3:pkg", "//envoy/service/tap/v3:pkg", + "//envoy/service/thrift_route/v3:pkg", "//envoy/service/trace/v3:pkg", "//envoy/type/http/v3:pkg", "//envoy/type/matcher/v3:pkg", diff --git a/source/common/config/BUILD b/source/common/config/BUILD index 2fd7a8c75748b..b23802ab3ab4b 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -271,6 +271,7 @@ envoy_cc_library( "@envoy_api//envoy/service/route/v3:pkg_cc_proto", "@envoy_api//envoy/service/runtime/v3:pkg_cc_proto", "@envoy_api//envoy/service/secret/v3:pkg_cc_proto", + "@envoy_api//envoy/service/thrift_route/v3:pkg_cc_proto", ], ) diff --git a/source/common/config/protobuf_link_hacks.h b/source/common/config/protobuf_link_hacks.h index c5eff8e5fb8dd..692b17048bba1 100644 --- a/source/common/config/protobuf_link_hacks.h +++ b/source/common/config/protobuf_link_hacks.h @@ -12,6 +12,7 @@ #include "envoy/service/route/v3/srds.pb.h" #include "envoy/service/runtime/v3/rtds.pb.h" #include "envoy/service/secret/v3/sds.pb.h" +#include "envoy/service/thrift_route/v3/rds.pb.h" // API_NO_BOOST_FILE @@ -30,5 +31,6 @@ const envoy::service::route::v3::SrdsDummy _srds_dummy_v3; const envoy::service::extension::v3::EcdsDummy _ecds_dummy_v3; const envoy::service::runtime::v3::RtdsDummy _rtds_dummy_v3; const envoy::service::health::v3::HdsDummy _hds_dummy_v3; +const envoy::service::thrift_route::v3::RdsDummy _thrift_rds_dummy_v3; } // namespace Envoy diff --git a/source/common/config/type_to_endpoint.cc b/source/common/config/type_to_endpoint.cc index f072162d776ed..92e231b9c5b28 100644 --- a/source/common/config/type_to_endpoint.cc +++ b/source/common/config/type_to_endpoint.cc @@ -59,7 +59,7 @@ TypeUrlToV3ServiceMap* buildTypeUrlToServiceMap() { "envoy.service.listener.v3.ListenerDiscoveryService", "envoy.service.runtime.v3.RuntimeDiscoveryService", "envoy.service.extension.v3.ExtensionConfigDiscoveryService", - "envoy.extensions.filters.network.thrift_proxy.v3.RouteDiscoveryService", + "envoy.service.thrift_route.v3.RouteDiscoveryService", }) { const TypeUrl resource_type_url = getResourceTypeUrl(name); V3Service& service = (*type_url_to_versioned_service_map)[resource_type_url]; diff --git a/source/extensions/filters/network/thrift_proxy/config.cc b/source/extensions/filters/network/thrift_proxy/config.cc index 53f2eb12860fd..a5bdc0376e8d0 100644 --- a/source/extensions/filters/network/thrift_proxy/config.cc +++ b/source/extensions/filters/network/thrift_proxy/config.cc @@ -147,8 +147,7 @@ ConfigImpl::ConfigImpl( } } - if (config.route_specifier_case() == envoy::extensions::filters::network::thrift_proxy::v3:: - ThriftProxy::RouteSpecifierCase::kRds) { + if (config.has_rds()) { route_config_provider_ = route_config_provider_manager.createRdsRouteConfigProvider( config.rds(), context_.getServerFactoryContext(), stats_prefix_, context_.initManager()); } else { diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 19c49496ddfff..514e29c11696e 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -367,8 +367,8 @@ envoy_cc_test( "//source/common/config:type_to_endpoint_lib", "//test/config:v2_link_hacks", "@envoy_api//envoy/api/v2:pkg_cc_proto", - "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", "@envoy_api//envoy/service/route/v3:pkg_cc_proto", + "@envoy_api//envoy/service/thrift_route/v3:pkg_cc_proto", ], ) diff --git a/test/common/config/type_to_endpoint_test.cc b/test/common/config/type_to_endpoint_test.cc index 66bf37a9179c0..71d5aeefceb1a 100644 --- a/test/common/config/type_to_endpoint_test.cc +++ b/test/common/config/type_to_endpoint_test.cc @@ -1,6 +1,6 @@ #include "envoy/api/v2/rds.pb.h" -#include "envoy/extensions/filters/network/thrift_proxy/v3/rds.pb.h" #include "envoy/service/route/v3/rds.pb.h" +#include "envoy/service/thrift_route/v3/rds.pb.h" #include "source/common/config/type_to_endpoint.h" @@ -45,10 +45,10 @@ TEST(TypeToEndpoint, All) { TEST(TypeToEndpoint, Thrift) { // The dummy messages are included for link purposes only. - envoy::extensions::filters::network::thrift_proxy::v3::RdsDummy _v3_rds_dummy; + envoy::service::thrift_route::v3::RdsDummy _v3_rds_dummy; EXPECT_EQ( - "envoy.extensions.filters.network.thrift_proxy.v3.RouteDiscoveryService.StreamRoutes", + "envoy.service.thrift_route.v3.RouteDiscoveryService.StreamRoutes", sotwGrpcMethod( "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration") .full_name()); From 15e1747c6f823fdb7fe5fd1eaf96b52bf090c061 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 7 Oct 2021 21:19:05 +0800 Subject: [PATCH 18/31] Kick CI Signed-off-by: Tamas Kovacs From f6f111c4aa6b7587cc098f6da2d534704daf7399 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sun, 10 Oct 2021 13:38:55 +0800 Subject: [PATCH 19/31] Simplifications Remove reference to Rds::ConfigFactory form Rds::RdsRouteConfigProviderImpl and RdsRouteConfigProviderImpl. Move init_manager.add() call into Rds::RouteConfigProviderManagerImpl::insertDynamicProvider, in this way no need to take care of it in each provider manager. Signed-off-by: Tamas Kovacs --- source/common/router/rds/config_factory.h | 8 +++++ .../rds/rds_route_config_provider_impl.h | 14 ++------ .../rds/route_config_provider_manager_impl.h | 3 +- .../rds/route_config_update_receiver_impl.h | 2 +- source/common/router/rds_impl.cc | 20 +++++++---- source/common/router/rds_impl.h | 12 +++---- .../route_config_update_receiver_impl.cc | 4 +-- .../route_config_update_receiver_impl.h | 35 ++++++++++++------- .../network/thrift_proxy/router/rds_impl.cc | 6 ++-- test/common/router/rds_template_test.cc | 3 +- 10 files changed, 61 insertions(+), 46 deletions(-) diff --git a/source/common/router/rds/config_factory.h b/source/common/router/rds/config_factory.h index 8bf93e8b8d0fb..2d6cb8c38fb8b 100644 --- a/source/common/router/rds/config_factory.h +++ b/source/common/router/rds/config_factory.h @@ -12,7 +12,15 @@ template class ConfigFactory { public: virtual ~ConfigFactory() = default; + /** + * Create a config object based on a route configuration. + */ virtual std::shared_ptr createConfig(const RouteConfiguration& rc) const PURE; + + /** + * Create a dummy config object without actual route configuration. + * This object will be used before the first valid route configuration is fetched. + */ virtual std::shared_ptr createConfig() const PURE; }; diff --git a/source/common/router/rds/rds_route_config_provider_impl.h b/source/common/router/rds/rds_route_config_provider_impl.h index 9115478fcbb97..770d532ee0d7e 100644 --- a/source/common/router/rds/rds_route_config_provider_impl.h +++ b/source/common/router/rds/rds_route_config_provider_impl.h @@ -9,7 +9,6 @@ #include "envoy/thread_local/thread_local.h" #include "source/common/common/logger.h" -#include "source/common/router/rds/config_factory.h" #include "source/common/router/rds/rds_route_config_subscription.h" namespace Envoy { @@ -26,20 +25,13 @@ class RdsRouteConfigProviderImpl : public RouteConfigProvider&& subscription, - Server::Configuration::ServerFactoryContext& factory_context, - ConfigFactory& config_factory) + Server::Configuration::ServerFactoryContext& factory_context) : subscription_(std::move(subscription)), config_update_info_(subscription_->routeConfigUpdate()), tls_(factory_context.threadLocal()) { - std::shared_ptr initial_config; - if (config_update_info_->configInfo().has_value()) { - initial_config = - config_factory.createConfig(subscription_->routeConfigUpdate()->protobufConfiguration()); - } else { - initial_config = config_factory.createConfig(); - } - + auto initial_config = config_update_info_->parsedConfiguration(); + ASSERT(initial_config); tls_.set([initial_config](Event::Dispatcher&) { return std::make_shared(initial_config); }); diff --git a/source/common/router/rds/route_config_provider_manager_impl.h b/source/common/router/rds/route_config_provider_manager_impl.h index bb51f5dadd0ae..72d3cf987ecc9 100644 --- a/source/common/router/rds/route_config_provider_manager_impl.h +++ b/source/common/router/rds/route_config_provider_manager_impl.h @@ -85,7 +85,8 @@ class RouteConfigProviderManagerImpl void insertDynamicProvider(int64_t manager_identifier, RouteConfigProviderSharedPtr provider, - const Init::Target* init_target) { + const Init::Target* init_target, Init::Manager& init_manager) { + init_manager.add(*init_target); dynamic_route_config_providers_.insert( {manager_identifier, std::make_pair(std::weak_ptr>(provider), diff --git a/source/common/router/rds/route_config_update_receiver_impl.h b/source/common/router/rds/route_config_update_receiver_impl.h index 6a47da1e7287c..1caa432f0ee94 100644 --- a/source/common/router/rds/route_config_update_receiver_impl.h +++ b/source/common/router/rds/route_config_update_receiver_impl.h @@ -18,7 +18,7 @@ class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver& config_factory) : time_source_(factory_context.timeSource()), route_config_proto_(std::make_unique()), last_config_hash_(0ull), - config_factory_(config_factory) {} + config_(config_factory.createConfig()), config_factory_(config_factory) {} bool updateHash(const RouteConfiguration& rc) { const uint64_t new_hash = MessageUtil::hash(rc); diff --git a/source/common/router/rds_impl.cc b/source/common/router/rds_impl.cc index 26d4ed3020046..1db6d739d135f 100644 --- a/source/common/router/rds_impl.cc +++ b/source/common/router/rds_impl.cc @@ -132,10 +132,17 @@ void RdsRouteConfigSubscription::updateOnDemand(const std::string& aliases) { RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( RdsRouteConfigSubscription* subscription, - Server::Configuration::ServerFactoryContext& factory_context, ConfigFactory& config_factory) - : base_(RdsRouteConfigSubscriptionSharedPtr(subscription), factory_context, config_factory), + Server::Configuration::ServerFactoryContext& factory_context, + const RouteConfigProviderManager::OptionalHttpFilters& optional_http_filters) + : base_(RdsRouteConfigSubscriptionSharedPtr(subscription), factory_context), subscription_(subscription), config_update_info_(subscription->routeConfigUpdate()), - config_factory_(config_factory), factory_context_(factory_context) { + factory_context_(factory_context), + validator_(factory_context.messageValidationContext().dynamicValidationVisitor()), + optional_http_filters_(optional_http_filters) { + // The subscription referenced by the 'base_' and by 'this' is the same. + // But the subscription contains two references back to the provider. + // One is in Rds::RdsRouteConfigSubscription other in RdsRouteConfigSubscription part. + // The first is already initialized by the 'base_' so need to set back to 'this'. base_.subscription().routeConfigProvider().emplace(this); subscription_->routeConfigProvider().emplace(this); } @@ -182,7 +189,7 @@ void RdsRouteConfigProviderImpl::onConfigUpdate() { void RdsRouteConfigProviderImpl::validateConfig( const envoy::config::route::v3::RouteConfiguration& config) const { // TODO(lizan): consider cache the config here until onConfigUpdate. - config_factory_.createConfig(config); + ConfigImpl validation_config(config, optional_http_filters_, factory_context_, validator_, false); } // Schedules a VHDS request on the main thread and queues up the callback to use when the VHDS @@ -227,11 +234,10 @@ Router::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRo new RouteConfigUpdateReceiverImpl(factory_context, optional_http_filters)); RdsRouteConfigSubscription* subscription(new RdsRouteConfigSubscription( config_update, rds, manager_identifier, factory_context, stat_prefix, *this)); - init_manager.add(subscription->initTarget()); RdsRouteConfigProviderImplSharedPtr new_provider{ - new RdsRouteConfigProviderImpl(subscription, factory_context, *config_update)}; + new RdsRouteConfigProviderImpl(subscription, factory_context, optional_http_filters)}; insertDynamicProvider(manager_identifier, new_provider, - &new_provider->subscription().initTarget()); + &new_provider->subscription().initTarget(), init_manager); return new_provider; } else { RouteConfigProviderSharedPtr existing_provider_downcasted = diff --git a/source/common/router/rds_impl.h b/source/common/router/rds_impl.h index 596859ecc1c9f..967044051b09f 100644 --- a/source/common/router/rds_impl.h +++ b/source/common/router/rds_impl.h @@ -152,9 +152,10 @@ struct UpdateOnDemandCallback { class RdsRouteConfigProviderImpl : public RouteConfigProvider, Logger::Loggable { public: - RdsRouteConfigProviderImpl(RdsRouteConfigSubscription* subscription, - Server::Configuration::ServerFactoryContext& factory_context, - ConfigFactory& config_factory); + RdsRouteConfigProviderImpl( + RdsRouteConfigSubscription* subscription, + Server::Configuration::ServerFactoryContext& factory_context, + const RouteConfigProviderManager::OptionalHttpFilters& optional_http_filters); ~RdsRouteConfigProviderImpl() override; @@ -176,15 +177,14 @@ class RdsRouteConfigProviderImpl : public RouteConfigProvider, // The pointer is owned by base_, here it is just stored as raw pointer to avoid downcasting. RdsRouteConfigSubscription* subscription_; - RouteConfigUpdateReceiver* config_update_info_; - ConfigFactory& config_factory_; - Server::Configuration::ServerFactoryContext& factory_context_; + ProtobufMessage::ValidationVisitor& validator_; std::list config_update_callbacks_; // A flag used to determine if this instance of RdsRouteConfigProviderImpl hasn't been // deallocated. Please also see a comment in requestVirtualHostsUpdate() method implementation. std::shared_ptr still_alive_{std::make_shared(true)}; + const RouteConfigProviderManager::OptionalHttpFilters optional_http_filters_; }; using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; diff --git a/source/common/router/route_config_update_receiver_impl.cc b/source/common/router/route_config_update_receiver_impl.cc index f55c5c4b352ca..e64c427e27750 100644 --- a/source/common/router/route_config_update_receiver_impl.cc +++ b/source/common/router/route_config_update_receiver_impl.cc @@ -108,14 +108,14 @@ void RouteConfigUpdateReceiverImpl::rebuildRouteConfig( } } -ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::createConfig( +ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::ConfigFactoryImpl::createConfig( const envoy::config::route::v3::RouteConfiguration& rc) const { return std::make_shared( rc, optional_http_filters_, factory_context_, factory_context_.messageValidationContext().dynamicValidationVisitor(), false); } -ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::createConfig() const { +ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::ConfigFactoryImpl::createConfig() const { return std::make_shared(); } diff --git a/source/common/router/route_config_update_receiver_impl.h b/source/common/router/route_config_update_receiver_impl.h index e7eb4c14d1184..2b0553ec3224c 100644 --- a/source/common/router/route_config_update_receiver_impl.h +++ b/source/common/router/route_config_update_receiver_impl.h @@ -18,17 +18,15 @@ namespace Envoy { namespace Router { -class RouteConfigUpdateReceiverImpl - : public RouteConfigUpdateReceiver, - public Rds::ConfigFactory { +class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { public: RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context, const OptionalHttpFilters& optional_http_filters) - : base_(factory_context, *this), factory_context_(factory_context), - last_vhds_config_hash_(0ul), + : config_factory_(factory_context, optional_http_filters), + base_(factory_context, config_factory_), last_vhds_config_hash_(0ul), vhds_virtual_hosts_( std::make_unique>()), - vhds_configuration_changed_(true), optional_http_filters_(optional_http_filters) {} + vhds_configuration_changed_(true) {} void initializeRdsVhosts(const envoy::config::route::v3::RouteConfiguration& route_configuration); bool removeVhosts(std::map& vhosts, @@ -64,21 +62,32 @@ class RouteConfigUpdateReceiverImpl return resource_ids_in_last_update_; } - // Rds::ConfigFactory - ConfigConstSharedPtr - createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const override; - ConfigConstSharedPtr createConfig() const override; - private: + class ConfigFactoryImpl + : public Rds::ConfigFactory { + public: + ConfigFactoryImpl(Server::Configuration::ServerFactoryContext& factory_context, + const OptionalHttpFilters& optional_http_filters) + : factory_context_(factory_context), optional_http_filters_(optional_http_filters) {} + + // Rds::ConfigFactory + ConfigConstSharedPtr + createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const override; + ConfigConstSharedPtr createConfig() const override; + + private: + Server::Configuration::ServerFactoryContext& factory_context_; + const OptionalHttpFilters optional_http_filters_; + }; + ConfigFactoryImpl config_factory_; + Rds::RouteConfigUpdateReceiverImpl base_; - Server::Configuration::ServerFactoryContext& factory_context_; uint64_t last_vhds_config_hash_; std::map rds_virtual_hosts_; std::unique_ptr> vhds_virtual_hosts_; std::set resource_ids_in_last_update_; bool vhds_configuration_changed_; - const OptionalHttpFilters optional_http_filters_; }; } // namespace Router diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc index afa2033727712..a0b81e701e853 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc @@ -58,12 +58,10 @@ RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfi RdsRouteConfigSubscriptionSharedPtr subscription(new RdsRouteConfigSubscription( std::move(config_update), rds.config_source(), rds.route_config_name(), manager_identifier, factory_context, stat_prefix, *this)); - init_manager.add(subscription->initTarget()); - RdsRouteConfigProviderImplSharedPtr new_provider{ - new RdsRouteConfigProviderImpl(std::move(subscription), factory_context, *this)}; + new RdsRouteConfigProviderImpl(std::move(subscription), factory_context)}; insertDynamicProvider(manager_identifier, new_provider, - &new_provider->subscription().initTarget()); + &new_provider->subscription().initTarget(), init_manager); return new_provider; } else { return existing_provider; diff --git a/test/common/router/rds_template_test.cc b/test/common/router/rds_template_test.cc index 6e65bc0f8671a..de9d62ac027e3 100644 --- a/test/common/router/rds_template_test.cc +++ b/test/common/router/rds_template_test.cc @@ -91,7 +91,8 @@ class RdsImplTest : public RdsTestBase { TEST_F(RdsImplTest, Basic) { setup(); - EXPECT_FALSE(config_update_->parsedConfiguration()); + EXPECT_TRUE(config_update_->parsedConfiguration()); + EXPECT_EQ(nullptr, config_update_->parsedConfiguration()->route("foo")); EXPECT_FALSE(config_update_->configInfo().has_value()); const std::string response1_json = R"EOF( From b9ab26fbac04510e4f9bf775dea73cc28109e7e4 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Tue, 12 Oct 2021 23:17:32 +0800 Subject: [PATCH 20/31] Add prefix to Thrift rds related proto names in the api. Signed-off-by: Tamas Kovacs --- .../network/thrift_proxy/v3/thrift_proxy.proto | 7 ++++--- api/envoy/service/{thrift_route => thrift}/v3/BUILD | 0 .../v3/rds.proto => thrift/v3/trds.proto} | 12 ++++++------ api/versioning/BUILD | 2 +- source/common/config/BUILD | 2 +- source/common/config/protobuf_link_hacks.h | 4 ++-- source/common/config/type_to_endpoint.cc | 2 +- .../filters/network/thrift_proxy/config.cc | 4 ++-- .../filters/network/thrift_proxy/router/rds.h | 2 +- .../filters/network/thrift_proxy/router/rds_impl.cc | 10 +++++----- .../filters/network/thrift_proxy/router/rds_impl.h | 2 +- test/common/config/BUILD | 2 +- test/common/config/type_to_endpoint_test.cc | 6 +++--- .../filters/network/thrift_proxy/rds_impl_test.cc | 4 ++-- tools/spelling/spelling_dictionary.txt | 1 + 15 files changed, 31 insertions(+), 29 deletions(-) rename api/envoy/service/{thrift_route => thrift}/v3/BUILD (100%) rename api/envoy/service/{thrift_route/v3/rds.proto => thrift/v3/trds.proto} (86%) diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index 0cb417190cb50..4ca2d4fdfd55c 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -77,6 +77,7 @@ message ThriftProxy { string stat_prefix = 1 [(validate.rules).string = {min_len: 1}]; // The route table for the connection manager is static and is specified in this property. + // If trds is also defined this field is ignored. RouteConfiguration route_config = 4 [(udpa.annotations.field_migrate).oneof_promotion = "route_specifier"]; @@ -96,8 +97,8 @@ message ThriftProxy { // Optional maximum requests for a single downstream connection. If not specified, there is no limit. google.protobuf.UInt32Value max_requests_per_connection = 7; - // Use xDS to fetch the route configuration. If both route_config and rds defined, rds has priority. - Rds rds = 8 [(udpa.annotations.field_migrate).oneof_promotion = "route_specifier"]; + // Use xDS to fetch the route configuration. If both route_config and trds defined, trds has priority. + Trds trds = 8 [(udpa.annotations.field_migrate).oneof_promotion = "route_specifier"]; } // ThriftFilter configures a Thrift filter. @@ -145,7 +146,7 @@ message ThriftProtocolOptions { ProtocolType protocol = 2 [(validate.rules).enum = {defined_only: true}]; } -message Rds { +message Trds { config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; string route_config_name = 2; diff --git a/api/envoy/service/thrift_route/v3/BUILD b/api/envoy/service/thrift/v3/BUILD similarity index 100% rename from api/envoy/service/thrift_route/v3/BUILD rename to api/envoy/service/thrift/v3/BUILD diff --git a/api/envoy/service/thrift_route/v3/rds.proto b/api/envoy/service/thrift/v3/trds.proto similarity index 86% rename from api/envoy/service/thrift_route/v3/rds.proto rename to api/envoy/service/thrift/v3/trds.proto index b18b1181de978..27507fb492c69 100644 --- a/api/envoy/service/thrift_route/v3/rds.proto +++ b/api/envoy/service/thrift/v3/trds.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package envoy.service.thrift_route.v3; +package envoy.service.thrift.v3; import "envoy/service/discovery/v3/discovery.proto"; @@ -10,20 +10,20 @@ import "envoy/annotations/resource.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; -option java_package = "io.envoyproxy.envoy.service.thrift_route.v3"; -option java_outer_classname = "RdsProto"; +option java_package = "io.envoyproxy.envoy.service.thrift.v3"; +option java_outer_classname = "TrdsProto"; option java_multiple_files = true; option java_generic_services = true; option (udpa.annotations.file_status).package_version_status = ACTIVE; -// [#protodoc-title: THRIFT_RDS] +// [#protodoc-title: TRDS] // The resource_names field in DiscoveryRequest specifies a route configuration. // This allows an Envoy configuration with multiple Thrift listeners (and // associated Thrift proxy filters) to use different route // configurations. Each listener will bind its Thrift proxy filter to // a route table via this identifier. -service RouteDiscoveryService { +service ThriftRouteDiscoveryService { option (envoy.annotations.resource).type = "envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration"; @@ -43,5 +43,5 @@ service RouteDiscoveryService { // [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing // services: https://github.com/google/protobuf/issues/4221 and protoxform to upgrade the file. -message RdsDummy { +message TrdsDummy { } diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 40f42cc8802b7..54f37f4e65b3b 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -196,7 +196,7 @@ proto_library( "//envoy/service/secret/v3:pkg", "//envoy/service/status/v3:pkg", "//envoy/service/tap/v3:pkg", - "//envoy/service/thrift_route/v3:pkg", + "//envoy/service/thrift/v3:pkg", "//envoy/service/trace/v3:pkg", "//envoy/type/http/v3:pkg", "//envoy/type/matcher/v3:pkg", diff --git a/source/common/config/BUILD b/source/common/config/BUILD index b23802ab3ab4b..91949464465ac 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -271,7 +271,7 @@ envoy_cc_library( "@envoy_api//envoy/service/route/v3:pkg_cc_proto", "@envoy_api//envoy/service/runtime/v3:pkg_cc_proto", "@envoy_api//envoy/service/secret/v3:pkg_cc_proto", - "@envoy_api//envoy/service/thrift_route/v3:pkg_cc_proto", + "@envoy_api//envoy/service/thrift/v3:pkg_cc_proto", ], ) diff --git a/source/common/config/protobuf_link_hacks.h b/source/common/config/protobuf_link_hacks.h index 692b17048bba1..5c54400e7c393 100644 --- a/source/common/config/protobuf_link_hacks.h +++ b/source/common/config/protobuf_link_hacks.h @@ -12,7 +12,7 @@ #include "envoy/service/route/v3/srds.pb.h" #include "envoy/service/runtime/v3/rtds.pb.h" #include "envoy/service/secret/v3/sds.pb.h" -#include "envoy/service/thrift_route/v3/rds.pb.h" +#include "envoy/service/thrift/v3/trds.pb.h" // API_NO_BOOST_FILE @@ -31,6 +31,6 @@ const envoy::service::route::v3::SrdsDummy _srds_dummy_v3; const envoy::service::extension::v3::EcdsDummy _ecds_dummy_v3; const envoy::service::runtime::v3::RtdsDummy _rtds_dummy_v3; const envoy::service::health::v3::HdsDummy _hds_dummy_v3; -const envoy::service::thrift_route::v3::RdsDummy _thrift_rds_dummy_v3; +const envoy::service::thrift::v3::TrdsDummy _trds_dummy_v3; } // namespace Envoy diff --git a/source/common/config/type_to_endpoint.cc b/source/common/config/type_to_endpoint.cc index 92e231b9c5b28..e709098c62e4c 100644 --- a/source/common/config/type_to_endpoint.cc +++ b/source/common/config/type_to_endpoint.cc @@ -59,7 +59,7 @@ TypeUrlToV3ServiceMap* buildTypeUrlToServiceMap() { "envoy.service.listener.v3.ListenerDiscoveryService", "envoy.service.runtime.v3.RuntimeDiscoveryService", "envoy.service.extension.v3.ExtensionConfigDiscoveryService", - "envoy.service.thrift_route.v3.RouteDiscoveryService", + "envoy.service.thrift.v3.ThriftRouteDiscoveryService", }) { const TypeUrl resource_type_url = getResourceTypeUrl(name); V3Service& service = (*type_url_to_versioned_service_map)[resource_type_url]; diff --git a/source/extensions/filters/network/thrift_proxy/config.cc b/source/extensions/filters/network/thrift_proxy/config.cc index a5bdc0376e8d0..1430f4db4630b 100644 --- a/source/extensions/filters/network/thrift_proxy/config.cc +++ b/source/extensions/filters/network/thrift_proxy/config.cc @@ -147,9 +147,9 @@ ConfigImpl::ConfigImpl( } } - if (config.has_rds()) { + if (config.has_trds()) { route_config_provider_ = route_config_provider_manager.createRdsRouteConfigProvider( - config.rds(), context_.getServerFactoryContext(), stats_prefix_, context_.initManager()); + config.trds(), context_.getServerFactoryContext(), stats_prefix_, context_.initManager()); } else { route_config_provider_ = route_config_provider_manager.createStaticRouteConfigProvider( config.route_config(), context_.getServerFactoryContext()); diff --git a/source/extensions/filters/network/thrift_proxy/router/rds.h b/source/extensions/filters/network/thrift_proxy/router/rds.h index ec368fc29a4ad..f0b27137dd4af 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds.h +++ b/source/extensions/filters/network/thrift_proxy/router/rds.h @@ -45,7 +45,7 @@ class RouteConfigProviderManager { * subscription. */ virtual RouteConfigProviderSharedPtr createRdsRouteConfigProvider( - const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + const envoy::extensions::filters::network::thrift_proxy::v3::Trds& trds, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, Init::Manager& init_manager) PURE; diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc index a0b81e701e853..f096c3dd6bade 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc @@ -40,14 +40,14 @@ RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& ad admin) {} RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( - const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + const envoy::extensions::filters::network::thrift_proxy::v3::Trds& trds, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, Init::Manager& init_manager) { // RdsRouteConfigSubscriptions are unique based on their serialized RDS config. - const uint64_t manager_identifier = MessageUtil::hash(rds); + const uint64_t manager_identifier = MessageUtil::hash(trds); auto existing_provider = - reuseDynamicProvider(manager_identifier, init_manager, rds.route_config_name()); + reuseDynamicProvider(manager_identifier, init_manager, trds.route_config_name()); if (!existing_provider) { // std::make_shared does not work for classes with private constructors. There are ways @@ -56,8 +56,8 @@ RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfi RouteConfigUpdatePtr config_update(new RouteConfigUpdateReceiverImpl(factory_context, *this)); RdsRouteConfigSubscriptionSharedPtr subscription(new RdsRouteConfigSubscription( - std::move(config_update), rds.config_source(), rds.route_config_name(), manager_identifier, - factory_context, stat_prefix, *this)); + std::move(config_update), trds.config_source(), trds.route_config_name(), + manager_identifier, factory_context, stat_prefix, *this)); RdsRouteConfigProviderImplSharedPtr new_provider{ new RdsRouteConfigProviderImpl(std::move(subscription), factory_context)}; insertDynamicProvider(manager_identifier, new_provider, diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h index 9673b325e7942..623a9c108a5c4 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h @@ -29,7 +29,7 @@ class RouteConfigProviderManagerImpl // RouteConfigProviderManager RouteConfigProviderSharedPtr createRdsRouteConfigProvider( - const envoy::extensions::filters::network::thrift_proxy::v3::Rds& rds, + const envoy::extensions::filters::network::thrift_proxy::v3::Trds& trds, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, Init::Manager& init_manager) override; diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 514e29c11696e..49ec5febeb148 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -368,7 +368,7 @@ envoy_cc_test( "//test/config:v2_link_hacks", "@envoy_api//envoy/api/v2:pkg_cc_proto", "@envoy_api//envoy/service/route/v3:pkg_cc_proto", - "@envoy_api//envoy/service/thrift_route/v3:pkg_cc_proto", + "@envoy_api//envoy/service/thrift/v3:pkg_cc_proto", ], ) diff --git a/test/common/config/type_to_endpoint_test.cc b/test/common/config/type_to_endpoint_test.cc index 71d5aeefceb1a..8da2f4bac3d06 100644 --- a/test/common/config/type_to_endpoint_test.cc +++ b/test/common/config/type_to_endpoint_test.cc @@ -1,6 +1,6 @@ #include "envoy/api/v2/rds.pb.h" #include "envoy/service/route/v3/rds.pb.h" -#include "envoy/service/thrift_route/v3/rds.pb.h" +#include "envoy/service/thrift/v3/trds.pb.h" #include "source/common/config/type_to_endpoint.h" @@ -45,10 +45,10 @@ TEST(TypeToEndpoint, All) { TEST(TypeToEndpoint, Thrift) { // The dummy messages are included for link purposes only. - envoy::service::thrift_route::v3::RdsDummy _v3_rds_dummy; + envoy::service::thrift::v3::TrdsDummy _v3_trds_dummy; EXPECT_EQ( - "envoy.service.thrift_route.v3.RouteDiscoveryService.StreamRoutes", + "envoy.service.thrift.v3.ThriftRouteDiscoveryService.StreamRoutes", sotwGrpcMethod( "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration") .full_name()); diff --git a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc index 43a9bb1ae6d0e..051f071af73b5 100644 --- a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc +++ b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc @@ -96,7 +96,7 @@ class RouteConfigProviderManagerImplTest : public RdsTestBase { server_factory_context_.thread_local_.shutdownThread(); } - envoy::extensions::filters::network::thrift_proxy::v3::Rds rds_; + envoy::extensions::filters::network::thrift_proxy::v3::Trds rds_; RouteConfigProviderManagerImplPtr route_config_provider_manager_; RouteConfigProviderSharedPtr provider_; }; @@ -298,7 +298,7 @@ name: foo_route_config &dynamic_cast(*provider2).subscription()); EXPECT_EQ(&provider_->configInfo().value().config_, &provider2->configInfo().value().config_); - envoy::extensions::filters::network::thrift_proxy::v3::Rds rds2; + envoy::extensions::filters::network::thrift_proxy::v3::Trds rds2; rds2.set_route_config_name("foo_route_config"); rds2.mutable_config_source()->set_path("bar_path"); RouteConfigProviderSharedPtr provider3 = diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 09c571bd35d8f..bd0891fb1c5a4 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -1210,6 +1210,7 @@ transcoded transcoder transcoding transferral +trds triaged trie tuple From 44f9ea8e593ce615eb648ae74a8a7d968cf1d216 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Tue, 12 Oct 2021 23:40:41 +0800 Subject: [PATCH 21/31] Fix missed file Signed-off-by: Tamas Kovacs --- api/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/BUILD b/api/BUILD index 29651053d38c5..9bd47dd06ab11 100644 --- a/api/BUILD +++ b/api/BUILD @@ -244,7 +244,7 @@ proto_library( "//envoy/service/secret/v3:pkg", "//envoy/service/status/v3:pkg", "//envoy/service/tap/v3:pkg", - "//envoy/service/thrift_route/v3:pkg", + "//envoy/service/thrift/v3:pkg", "//envoy/service/trace/v3:pkg", "//envoy/type/http/v3:pkg", "//envoy/type/matcher/v3:pkg", From 4ae0e46051b787e2d369ea1e2df1bc4014092e55 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 14 Oct 2021 00:07:33 +0800 Subject: [PATCH 22/31] Kick CI Signed-off-by: Tamas Kovacs From ab9e419c6d606036b47ec93c00518bc6b7683e19 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 14 Oct 2021 13:47:34 +0800 Subject: [PATCH 23/31] Kick CI Signed-off-by: Tamas Kovacs From bbc830bceaf32c90b4a5e19281252824c2d28483 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sun, 17 Oct 2021 00:56:25 +0800 Subject: [PATCH 24/31] Change TRDS method names similar to other DS method names Signed-off-by: Tamas Kovacs --- api/envoy/service/thrift/v3/trds.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/envoy/service/thrift/v3/trds.proto b/api/envoy/service/thrift/v3/trds.proto index 27507fb492c69..28215d57c7748 100644 --- a/api/envoy/service/thrift/v3/trds.proto +++ b/api/envoy/service/thrift/v3/trds.proto @@ -27,15 +27,15 @@ service ThriftRouteDiscoveryService { option (envoy.annotations.resource).type = "envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration"; - rpc StreamRoutes(stream discovery.v3.DiscoveryRequest) + rpc StreamThriftRoutes(stream discovery.v3.DiscoveryRequest) returns (stream discovery.v3.DiscoveryResponse) { } - rpc DeltaRoutes(stream discovery.v3.DeltaDiscoveryRequest) + rpc DeltaThriftRoutes(stream discovery.v3.DeltaDiscoveryRequest) returns (stream discovery.v3.DeltaDiscoveryResponse) { } - rpc FetchRoutes(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) { + rpc FetchThriftRoutes(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) { option (google.api.http).post = "/v3/discovery:thrift_routes"; option (google.api.http).body = "*"; } From cd7c2d78ada79d921d67e0c519b41b4793b095db Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sun, 17 Oct 2021 20:44:39 +0800 Subject: [PATCH 25/31] Fix ut Signed-off-by: Tamas Kovacs --- test/common/config/type_to_endpoint_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/config/type_to_endpoint_test.cc b/test/common/config/type_to_endpoint_test.cc index 8da2f4bac3d06..1c62918cf0746 100644 --- a/test/common/config/type_to_endpoint_test.cc +++ b/test/common/config/type_to_endpoint_test.cc @@ -48,7 +48,7 @@ TEST(TypeToEndpoint, Thrift) { envoy::service::thrift::v3::TrdsDummy _v3_trds_dummy; EXPECT_EQ( - "envoy.service.thrift.v3.ThriftRouteDiscoveryService.StreamRoutes", + "envoy.service.thrift.v3.ThriftRouteDiscoveryService.StreamThriftRoutes", sotwGrpcMethod( "type.googleapis.com/envoy.extensions.filters.network.thrift_proxy.v3.RouteConfiguration") .full_name()); From 7d93eb66426def4baa56b5a83584df5b2464e4c4 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 28 Oct 2021 19:44:59 +0800 Subject: [PATCH 26/31] Eliminate templates from generic rds base classes. Signed-off-by: Tamas Kovacs --- .../thrift_proxy/v3/thrift_proxy.proto | 16 +- envoy/rds/BUILD | 19 ++ envoy/rds/config.h | 19 ++ envoy/rds/config_traits.h | 45 ++++ .../{router => }/rds/route_config_provider.h | 27 +-- .../rds/route_config_update_receiver.h | 23 +- envoy/router/BUILD | 11 +- envoy/router/rds.h | 12 +- envoy/router/route_config_update_receiver.h | 14 +- envoy/router/router.h | 3 +- source/common/http/conn_manager_impl.cc | 6 +- source/common/rds/BUILD | 47 ++++ .../rds/rds_route_config_provider_impl.cc | 37 ++++ .../rds/rds_route_config_provider_impl.h | 51 +++++ .../rds/rds_route_config_subscription.cc | 124 +++++++++++ .../rds/rds_route_config_subscription.h | 107 +++++++++ .../rds/route_config_provider_manager.h | 21 ++ .../rds/route_config_provider_manager_impl.cc | 95 ++++++++ .../rds/route_config_provider_manager_impl.h | 52 +++++ .../rds/route_config_update_receiver_impl.cc | 54 +++++ .../rds/route_config_update_receiver_impl.h | 44 ++++ .../rds/static_route_config_provider_impl.cc | 25 +++ .../rds/static_route_config_provider_impl.h | 39 ++++ source/common/router/BUILD | 36 +-- source/common/router/rds/config_factory.h | 29 --- .../rds/rds_route_config_provider_impl.h | 78 ------- .../rds/rds_route_config_subscription.h | 208 ------------------ .../rds/route_config_provider_manager.h | 24 -- .../rds/route_config_provider_manager_impl.h | 128 ----------- .../rds/route_config_update_receiver_impl.h | 78 ------- .../rds/static_route_config_provider_impl.h | 50 ----- source/common/router/rds_impl.cc | 81 ++++--- source/common/router/rds_impl.h | 54 ++--- .../route_config_update_receiver_impl.cc | 64 ++++-- .../route_config_update_receiver_impl.h | 78 ++++--- source/common/router/scoped_rds.cc | 6 +- source/common/router/scoped_rds.h | 2 +- source/common/router/vhds.cc | 4 +- .../filters/network/thrift_proxy/config.h | 5 +- .../filters/network/thrift_proxy/router/BUILD | 7 +- .../filters/network/thrift_proxy/router/rds.h | 12 +- .../network/thrift_proxy/router/rds_impl.cc | 116 +++++----- .../network/thrift_proxy/router/rds_impl.h | 39 ++-- .../network/thrift_proxy/router/router.h | 3 +- source/server/admin/admin.h | 4 +- test/common/router/rds_impl_test.cc | 9 +- .../network/thrift_proxy/rds_impl_test.cc | 19 +- test/mocks/router/mocks.h | 4 +- 48 files changed, 1123 insertions(+), 906 deletions(-) create mode 100644 envoy/rds/BUILD create mode 100644 envoy/rds/config.h create mode 100644 envoy/rds/config_traits.h rename envoy/{router => }/rds/route_config_provider.h (64%) rename envoy/{router => }/rds/route_config_update_receiver.h (67%) create mode 100644 source/common/rds/BUILD create mode 100644 source/common/rds/rds_route_config_provider_impl.cc create mode 100644 source/common/rds/rds_route_config_provider_impl.h create mode 100644 source/common/rds/rds_route_config_subscription.cc create mode 100644 source/common/rds/rds_route_config_subscription.h create mode 100644 source/common/rds/route_config_provider_manager.h create mode 100644 source/common/rds/route_config_provider_manager_impl.cc create mode 100644 source/common/rds/route_config_provider_manager_impl.h create mode 100644 source/common/rds/route_config_update_receiver_impl.cc create mode 100644 source/common/rds/route_config_update_receiver_impl.h create mode 100644 source/common/rds/static_route_config_provider_impl.cc create mode 100644 source/common/rds/static_route_config_provider_impl.h delete mode 100644 source/common/router/rds/config_factory.h delete mode 100644 source/common/router/rds/rds_route_config_provider_impl.h delete mode 100644 source/common/router/rds/rds_route_config_subscription.h delete mode 100644 source/common/router/rds/route_config_provider_manager.h delete mode 100644 source/common/router/rds/route_config_provider_manager_impl.h delete mode 100644 source/common/router/rds/route_config_update_receiver_impl.h delete mode 100644 source/common/router/rds/static_route_config_provider_impl.h diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index 4ca2d4fdfd55c..c044766886e81 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -60,6 +60,16 @@ enum ProtocolType { TWITTER = 4; } +message Trds { + // Configuration source specifier. + config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + + // The name of the route configuration. This allows to use different route + // configurations. Tells which route config should be fetched + // from the configuration source. + string route_config_name = 2; +} + // [#next-free-field: 9] message ThriftProxy { option (udpa.annotations.versioning).previous_message_type = @@ -145,9 +155,3 @@ message ThriftProtocolOptions { // which is the default, causes the proxy to use the same protocol as the downstream connection. ProtocolType protocol = 2 [(validate.rules).enum = {defined_only: true}]; } - -message Trds { - config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; - - string route_config_name = 2; -} diff --git a/envoy/rds/BUILD b/envoy/rds/BUILD new file mode 100644 index 0000000000000..9f20ca9bdff57 --- /dev/null +++ b/envoy/rds/BUILD @@ -0,0 +1,19 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "rds_interface", + hdrs = [ + "config.h", + "config_traits.h", + "route_config_provider.h", + "route_config_update_receiver.h", + ], +) diff --git a/envoy/rds/config.h b/envoy/rds/config.h new file mode 100644 index 0000000000000..8a230a9763c83 --- /dev/null +++ b/envoy/rds/config.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace Envoy { +namespace Rds { + +/** + * Base class for router configuration classes used with Rds. + */ +class Config { +public: + virtual ~Config() = default; +}; + +using ConfigConstSharedPtr = std::shared_ptr; + +} // namespace Rds +} // namespace Envoy diff --git a/envoy/rds/config_traits.h b/envoy/rds/config_traits.h new file mode 100644 index 0000000000000..0c91eb8c60ee0 --- /dev/null +++ b/envoy/rds/config_traits.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include "envoy/common/pure.h" +#include "envoy/config/subscription.h" +#include "envoy/rds/config.h" + +#include "source/common/protobuf/protobuf.h" + +namespace Envoy { +namespace Rds { + +/** + * Traits of route configuration and proto. + */ +class ConfigTraits { +public: + virtual ~ConfigTraits() = default; + + virtual std::string resourceType() const PURE; + + /** + * Create a dummy config object without actual route configuration. + * This object will be used before the first valid route configuration is fetched. + */ + virtual ConfigConstSharedPtr createConfig() const PURE; + + virtual ProtobufTypes::MessagePtr createProto() const PURE; + + virtual const Protobuf::Message& validateResourceType(const Protobuf::Message& rc) const PURE; + virtual const Protobuf::Message& validateConfig(const Protobuf::Message& rc) const PURE; + + virtual const std::string& resourceName(const Protobuf::Message& rc) const PURE; + + /** + * Create a config object based on a route configuration. + */ + virtual ConfigConstSharedPtr createConfig(const Protobuf::Message& rc) const PURE; + + virtual ProtobufTypes::MessagePtr cloneProto(const Protobuf::Message& rc) const PURE; +}; + +} // namespace Rds +} // namespace Envoy diff --git a/envoy/router/rds/route_config_provider.h b/envoy/rds/route_config_provider.h similarity index 64% rename from envoy/router/rds/route_config_provider.h rename to envoy/rds/route_config_provider.h index f7680627acd1d..3df38c8ba2e12 100644 --- a/envoy/router/rds/route_config_provider.h +++ b/envoy/rds/route_config_provider.h @@ -3,22 +3,26 @@ #include #include "envoy/common/time.h" +#include "envoy/rds/config.h" + +#include "source/common/protobuf/protobuf.h" #include "absl/types/optional.h" namespace Envoy { -namespace Router { namespace Rds { /** * A provider for constant route configurations. */ -template class RouteConfigProvider { +class RouteConfigProvider { public: struct ConfigInfo { // A reference to the currently loaded route configuration. Do not hold this reference beyond // the caller of configInfo()'s scope. - const RouteConfiguration& config_; + const Protobuf::Message& config_; + + const std::string& name_; // The discovery version that supplied this route. This will be set to "" in the case of // static clusters. @@ -28,11 +32,11 @@ template class RouteConfigProvider { virtual ~RouteConfigProvider() = default; /** - * @return Router::ConfigConstSharedPtr a route configuration for use during a single request. The + * @return ConfigConstSharedPtr a route configuration for use during a single request. The * returned config may be different on a subsequent call, so a new config should be acquired for * each request flow. */ - virtual std::shared_ptr config() PURE; + virtual ConfigConstSharedPtr config() PURE; /** * @return the configuration information for the currently loaded route configuration. Note that @@ -50,19 +54,10 @@ template class RouteConfigProvider { * Callback used to notify RouteConfigProvider about configuration changes. */ virtual void onConfigUpdate() PURE; - - /** - * Validate if the route configuration can be applied to the context of the route config provider. - */ - virtual void validateConfig(const RouteConfiguration& config) const PURE; }; -template -using RouteConfigProviderPtr = std::unique_ptr>; -template -using RouteConfigProviderSharedPtr = - std::shared_ptr>; +using RouteConfigProviderPtr = std::unique_ptr; +using RouteConfigProviderSharedPtr = std::shared_ptr; } // namespace Rds -} // namespace Router } // namespace Envoy diff --git a/envoy/router/rds/route_config_update_receiver.h b/envoy/rds/route_config_update_receiver.h similarity index 67% rename from envoy/router/rds/route_config_update_receiver.h rename to envoy/rds/route_config_update_receiver.h index cd780605faba4..45eb258c18f23 100644 --- a/envoy/router/rds/route_config_update_receiver.h +++ b/envoy/rds/route_config_update_receiver.h @@ -4,18 +4,18 @@ #include "envoy/common/pure.h" #include "envoy/common/time.h" -#include "envoy/router/rds/route_config_provider.h" +#include "envoy/rds/config_traits.h" +#include "envoy/rds/route_config_provider.h" #include "absl/types/optional.h" namespace Envoy { -namespace Router { namespace Rds { /** * A primitive that keeps track of updates to a RouteConfiguration. */ -template class RouteConfigUpdateReceiver { +class RouteConfigUpdateReceiver { public: virtual ~RouteConfigUpdateReceiver() = default; @@ -25,7 +25,7 @@ template class RouteConfigUpdateReceive * @param version_info supplies RouteConfiguration version. * @return bool whether RouteConfiguration has been updated. */ - virtual bool onRdsUpdate(const RouteConfiguration& rc, const std::string& version_info) PURE; + virtual bool onRdsUpdate(const Protobuf::Message& rc, const std::string& version_info) PURE; /** * @return std::string& the name of RouteConfiguration. @@ -47,29 +47,28 @@ template class RouteConfigUpdateReceive * RouteConfigProvider::ConfigInfo if RouteConfiguration has been updated at least once. Otherwise * returns an empty absl::optional. */ - virtual absl::optional::ConfigInfo> - configInfo() const PURE; + virtual absl::optional configInfo() const PURE; /** * @return envoy::config::route::v3::RouteConfiguration& current RouteConfiguration. */ - virtual const RouteConfiguration& protobufConfiguration() PURE; + virtual const Protobuf::Message& protobufConfiguration() PURE; /** - * @return Router::ConfigConstSharedPtr a parsed and validated copy of current RouteConfiguration. + * @return ConfigConstSharedPtr a parsed and validated copy of current RouteConfiguration. * @see protobufConfiguration() */ - virtual std::shared_ptr parsedConfiguration() const PURE; + virtual ConfigConstSharedPtr parsedConfiguration() const PURE; /** * @return SystemTime the time of the last update. */ virtual SystemTime lastUpdated() const PURE; + + virtual const ConfigTraits& configTraits() const PURE; }; -template -using RouteConfigUpdatePtr = std::unique_ptr>; +using RouteConfigUpdatePtr = std::unique_ptr; } // namespace Rds -} // namespace Router } // namespace Envoy diff --git a/envoy/router/BUILD b/envoy/router/BUILD index 5725ff4484e72..31ae02a84d81c 100644 --- a/envoy/router/BUILD +++ b/envoy/router/BUILD @@ -19,7 +19,7 @@ envoy_cc_library( deps = [ ":router_interface", "//envoy/http:filter_interface", - "//envoy/router:rds_template_interface", + "//envoy/rds:rds_interface", "@envoy_api//envoy/config/route/v3:pkg_cc_proto", ], ) @@ -71,6 +71,7 @@ envoy_cc_library( "//envoy/http:conn_pool_interface", "//envoy/http:hash_policy_interface", "//envoy/http:header_map_interface", + "//envoy/rds:rds_interface", "//envoy/tcp:conn_pool_interface", "//envoy/tracing:http_tracer_interface", "//envoy/upstream:resource_manager_interface", @@ -130,11 +131,3 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", ], ) - -envoy_cc_library( - name = "rds_template_interface", - hdrs = [ - "rds/route_config_provider.h", - "rds/route_config_update_receiver.h", - ], -) diff --git a/envoy/router/rds.h b/envoy/router/rds.h index b1d3696492f9a..b2e1415ae3f55 100644 --- a/envoy/router/rds.h +++ b/envoy/router/rds.h @@ -4,7 +4,7 @@ #include "envoy/config/route/v3/route.pb.h" #include "envoy/http/filter.h" -#include "envoy/router/rds/route_config_provider.h" +#include "envoy/rds/route_config_provider.h" #include "envoy/router/router.h" namespace Envoy { @@ -13,9 +13,15 @@ namespace Router { /** * A provider for constant route configurations. */ -class RouteConfigProvider - : public Rds::RouteConfigProvider { +class RouteConfigProvider : public Rds::RouteConfigProvider { public: + /** + * Same purpose as Rds::RouteConfigProvider::config() + * but the return is downcasted to proper type. + * @return dowcasted ConfigConstSharedPtr from Rds::ConfigConstSharedPtr + */ + virtual ConfigConstSharedPtr configCast() PURE; + /** * Callback used to request an update to the route configuration from the management server. * @param for_domain supplies the domain name that virtual hosts must match on diff --git a/envoy/router/route_config_update_receiver.h b/envoy/router/route_config_update_receiver.h index 94859d6e3463e..6c0ce5586065e 100644 --- a/envoy/router/route_config_update_receiver.h +++ b/envoy/router/route_config_update_receiver.h @@ -5,8 +5,7 @@ #include "envoy/common/pure.h" #include "envoy/common/time.h" #include "envoy/config/route/v3/route.pb.h" -#include "envoy/router/rds.h" -#include "envoy/router/rds/route_config_update_receiver.h" +#include "envoy/rds/route_config_update_receiver.h" #include "envoy/service/discovery/v3/discovery.pb.h" #include "source/common/protobuf/protobuf.h" @@ -19,9 +18,15 @@ namespace Router { /** * A primitive that keeps track of updates to a RouteConfiguration. */ -class RouteConfigUpdateReceiver - : public Rds::RouteConfigUpdateReceiver { +class RouteConfigUpdateReceiver : public Rds::RouteConfigUpdateReceiver { public: + /** + * Same purpose as Rds::RouteConfigUpdateReceiver::protobufConfigurationCast() + * but the return is downcasted to proper type. + * @return current RouteConfiguration downcasted from Protobuf::Message& + */ + virtual const envoy::config::route::v3::RouteConfiguration& protobufConfigurationCast() PURE; + using VirtualHostRefVector = std::vector>; @@ -54,5 +59,6 @@ class RouteConfigUpdateReceiver }; using RouteConfigUpdatePtr = std::unique_ptr; + } // namespace Router } // namespace Envoy diff --git a/envoy/router/router.h b/envoy/router/router.h index c829262d1403e..4cb4d56ebaff9 100644 --- a/envoy/router/router.h +++ b/envoy/router/router.h @@ -18,6 +18,7 @@ #include "envoy/http/codes.h" #include "envoy/http/conn_pool.h" #include "envoy/http/hash_policy.h" +#include "envoy/rds/config.h" #include "envoy/router/internal_redirect.h" #include "envoy/tcp/conn_pool.h" #include "envoy/tracing/http_tracer.h" @@ -1093,7 +1094,7 @@ using RouteCallback = std::functionconfig(); + snapped_route_config_ = connection_manager_.config_.routeConfigProvider()->configCast(); } else if (connection_manager_.config_.scopedRouteConfigProvider() != nullptr) { snapped_scoped_routes_config_ = connection_manager_.config_.scopedRouteConfigProvider()->config(); snapScopedRouteConfig(); } } else { - snapped_route_config_ = connection_manager_.config_.routeConfigProvider()->config(); + snapped_route_config_ = connection_manager_.config_.routeConfigProvider()->configCast(); } ENVOY_STREAM_LOG(debug, "request headers complete (end_stream={}):\n{}", *this, end_stream, @@ -1319,7 +1319,7 @@ void ConnectionManagerImpl::ActiveStream::requestRouteConfigUpdate( absl::optional ConnectionManagerImpl::ActiveStream::routeConfig() { if (connection_manager_.config_.routeConfigProvider() != nullptr) { return absl::optional( - connection_manager_.config_.routeConfigProvider()->config()); + connection_manager_.config_.routeConfigProvider()->configCast()); } return {}; } diff --git a/source/common/rds/BUILD b/source/common/rds/BUILD new file mode 100644 index 0000000000000..4efc083e4b6bf --- /dev/null +++ b/source/common/rds/BUILD @@ -0,0 +1,47 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "rds_lib", + srcs = [ + "rds_route_config_provider_impl.cc", + "rds_route_config_subscription.cc", + "route_config_provider_manager_impl.cc", + "route_config_update_receiver_impl.cc", + "static_route_config_provider_impl.cc", + ], + hdrs = [ + "rds_route_config_provider_impl.h", + "rds_route_config_subscription.h", + "route_config_provider_manager.h", + "route_config_provider_manager_impl.h", + "route_config_update_receiver_impl.h", + "static_route_config_provider_impl.h", + ], + deps = [ + "//envoy/rds:rds_interface", + "//envoy/singleton:instance_interface", + "//envoy/thread_local:thread_local_interface", + "//source/common/common:assert_lib", + "//source/common/common:callback_impl_lib", + "//source/common/common:cleanup_lib", + "//source/common/common:minimal_logger_lib", + "//source/common/config:api_version_lib", + "//source/common/config:subscription_base_interface", + "//source/common/config:subscription_factory_lib", + "//source/common/config:utility_lib", + "//source/common/init:manager_lib", + "//source/common/init:target_lib", + "//source/common/init:watcher_lib", + "//source/common/protobuf:utility_lib", + "@envoy_api//envoy/admin/v3:pkg_cc_proto", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) diff --git a/source/common/rds/rds_route_config_provider_impl.cc b/source/common/rds/rds_route_config_provider_impl.cc new file mode 100644 index 0000000000000..c8f2b1e446b06 --- /dev/null +++ b/source/common/rds/rds_route_config_provider_impl.cc @@ -0,0 +1,37 @@ +#include "source/common/rds/rds_route_config_provider_impl.h" + +namespace Envoy { +namespace Rds { + +RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( + RdsRouteConfigSubscriptionSharedPtr&& subscription, + Server::Configuration::ServerFactoryContext& factory_context) + : subscription_(std::move(subscription)), + config_update_info_(subscription_->routeConfigUpdate()), tls_(factory_context.threadLocal()) { + + auto initial_config = config_update_info_->parsedConfiguration(); + ASSERT(initial_config); + tls_.set([initial_config](Event::Dispatcher&) { + return std::make_shared(initial_config); + }); + // It should be 1:1 mapping due to shared rds config. + ASSERT(!subscription_->routeConfigProvider().has_value()); + subscription_->routeConfigProvider().emplace(this); +} + +RdsRouteConfigProviderImpl::~RdsRouteConfigProviderImpl() { + ASSERT(subscription_->routeConfigProvider().has_value()); + subscription_->routeConfigProvider().reset(); +} + +absl::optional RdsRouteConfigProviderImpl::configInfo() const { + return config_update_info_->configInfo(); +} + +void RdsRouteConfigProviderImpl::onConfigUpdate() { + tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( + OptRef tls) { tls->config_ = new_config; }); +} + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/rds_route_config_provider_impl.h b/source/common/rds/rds_route_config_provider_impl.h new file mode 100644 index 0000000000000..c6ce171edd6fa --- /dev/null +++ b/source/common/rds/rds_route_config_provider_impl.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#include "envoy/rds/route_config_provider.h" +#include "envoy/rds/route_config_update_receiver.h" +#include "envoy/server/factory_context.h" +#include "envoy/thread_local/thread_local.h" + +#include "source/common/common/logger.h" +#include "source/common/rds/rds_route_config_subscription.h" + +namespace Envoy { +namespace Rds { + +/** + * Implementation of RouteConfigProvider that fetches the route configuration dynamically using + * the subscription. + */ +class RdsRouteConfigProviderImpl : public RouteConfigProvider, + Logger::Loggable { +public: + RdsRouteConfigProviderImpl(RdsRouteConfigSubscriptionSharedPtr&& subscription, + Server::Configuration::ServerFactoryContext& factory_context); + + ~RdsRouteConfigProviderImpl() override; + + RdsRouteConfigSubscription& subscription() { return *subscription_; } + + // RouteConfigProvider + ConfigConstSharedPtr config() override { return tls_->config_; } + + absl::optional configInfo() const override; + SystemTime lastUpdated() const override { return config_update_info_->lastUpdated(); } + void onConfigUpdate() override; + +private: + struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { + ThreadLocalConfig(std::shared_ptr initial_config) + : config_(std::move(initial_config)) {} + ConfigConstSharedPtr config_; + }; + + RdsRouteConfigSubscriptionSharedPtr subscription_; + RouteConfigUpdatePtr& config_update_info_; + ThreadLocal::TypedSlot tls_; +}; + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/rds_route_config_subscription.cc b/source/common/rds/rds_route_config_subscription.cc new file mode 100644 index 0000000000000..95a731e839b4d --- /dev/null +++ b/source/common/rds/rds_route_config_subscription.cc @@ -0,0 +1,124 @@ +#include "source/common/rds/rds_route_config_subscription.h" + +namespace Envoy { +namespace Rds { + +RdsRouteConfigSubscription::RdsRouteConfigSubscription( + RouteConfigUpdatePtr&& config_update, + std::unique_ptr&& resource_decoder, + const envoy::config::core::v3::ConfigSource& config_source, + const std::string& route_config_name, const uint64_t manager_identifier, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + RouteConfigProviderManager& route_config_provider_manager) + : route_config_name_(route_config_name), + scope_(factory_context.scope().createScope(stat_prefix + "rds." + route_config_name_ + ".")), + factory_context_(factory_context), + parent_init_target_(fmt::format("RdsRouteConfigSubscription init {}", route_config_name_), + [this]() { local_init_manager_.initialize(local_init_watcher_); }), + local_init_watcher_(fmt::format("RDS local-init-watcher {}", route_config_name_), + [this]() { parent_init_target_.ready(); }), + local_init_target_( + fmt::format("RdsRouteConfigSubscription local-init-target {}", route_config_name_), + [this]() { subscription_->start({route_config_name_}); }), + local_init_manager_(fmt::format("RDS local-init-manager {}", route_config_name_)), + stat_prefix_(stat_prefix), + stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}), + route_config_provider_manager_(route_config_provider_manager), + manager_identifier_(manager_identifier), config_update_info_(std::move(config_update)), + resource_decoder_(std::move(resource_decoder)) { + const auto resource_type = config_update_info_->configTraits().resourceType(); + subscription_ = + factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( + config_source, Envoy::Grpc::Common::typeUrl(resource_type), *scope_, *this, + *resource_decoder_, {}); + local_init_manager_.add(local_init_target_); +} + +RdsRouteConfigSubscription::~RdsRouteConfigSubscription() { + // If we get destroyed during initialization, make sure we signal that we "initialized". + local_init_target_.ready(); + + // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that + // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the + // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get + // cleaned by the RdsRouteConfigProvider's destructor. + route_config_provider_manager_.eraseDynamicProvider(manager_identifier_); +} + +absl::optional& RdsRouteConfigSubscription::routeConfigProvider() { + return route_config_provider_opt_; +} + +void RdsRouteConfigSubscription::onConfigUpdate( + const std::vector& resources, + const std::string& version_info) { + if (!validateUpdateSize(resources.size())) { + return; + } + const auto& route_config = resources[0].get().resource(); + config_update_info_->configTraits().validateResourceType(route_config); + if (config_update_info_->configTraits().resourceName(route_config) != route_config_name_) { + throw EnvoyException( + fmt::format("Unexpected RDS configuration (expecting {}): {}", route_config_name_, + config_update_info_->configTraits().resourceName(route_config))); + } + config_update_info_->configTraits().validateConfig(route_config); + if (config_update_info_->onRdsUpdate(route_config, version_info)) { + stats_.config_reload_.inc(); + stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); + + beforeProviderUpdate(); + + ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_, + config_update_info_->configHash()); + + if (route_config_provider_opt_.has_value()) { + route_config_provider_opt_.value()->onConfigUpdate(); + } + + afterProviderUpdate(); + } + + local_init_target_.ready(); +} + +void RdsRouteConfigSubscription::onConfigUpdate( + const std::vector& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, const std::string&) { + if (!removed_resources.empty()) { + // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense + // (see discussion in #6879), and so we should do something other than ignoring here. + ENVOY_LOG( + error, + "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", + removed_resources[0]); + } + if (!added_resources.empty()) { + onConfigUpdate(added_resources, added_resources[0].get().version()); + } +} + +void RdsRouteConfigSubscription::onConfigUpdateFailed( + Envoy::Config::ConfigUpdateFailureReason reason, const EnvoyException*) { + ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason); + // We need to allow server startup to continue, even if we have a bad + // config. + local_init_target_.ready(); +} + +bool RdsRouteConfigSubscription::validateUpdateSize(int num_resources) { + if (num_resources == 0) { + ENVOY_LOG(debug, "Missing RouteConfiguration for {} in onConfigUpdate()", route_config_name_); + stats_.update_empty_.inc(); + local_init_target_.ready(); + return false; + } + if (num_resources != 1) { + throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", num_resources)); + // (would be a return false here) + } + return true; +} + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/rds_route_config_subscription.h b/source/common/rds/rds_route_config_subscription.h new file mode 100644 index 0000000000000..98b6d287b7aeb --- /dev/null +++ b/source/common/rds/rds_route_config_subscription.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +#include "envoy/config/core/v3/config_source.pb.h" +#include "envoy/config/subscription.h" +#include "envoy/rds/route_config_provider.h" +#include "envoy/rds/route_config_update_receiver.h" +#include "envoy/server/factory_context.h" +#include "envoy/stats/scope.h" + +#include "source/common/common/logger.h" +#include "source/common/grpc/common.h" +#include "source/common/init/manager_impl.h" +#include "source/common/init/target_impl.h" +#include "source/common/init/watcher_impl.h" +#include "source/common/rds/route_config_provider_manager.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Rds { + +/** + * All RDS stats. @see stats_macros.h + */ +#define ALL_RDS_STATS(COUNTER, GAUGE) \ + COUNTER(config_reload) \ + COUNTER(update_empty) \ + GAUGE(config_reload_time_ms, NeverImport) + +/** + * Struct definition for all RDS stats. @see stats_macros.h + */ +struct RdsStats { + ALL_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) +}; + +/** + * A class that fetches the route configuration dynamically using the RDS API and updates them to + * RDS config providers. + */ +class RdsRouteConfigSubscription : Envoy::Config::SubscriptionCallbacks, + protected Logger::Loggable { +public: + RdsRouteConfigSubscription( + RouteConfigUpdatePtr&& config_update, + std::unique_ptr&& resource_decoder, + const envoy::config::core::v3::ConfigSource& config_source, + const std::string& route_config_name, const uint64_t manager_identifier, + Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, + RouteConfigProviderManager& route_config_provider_manager); + + ~RdsRouteConfigSubscription() override; + + absl::optional& routeConfigProvider(); + + RouteConfigUpdatePtr& routeConfigUpdate() { return config_update_info_; } + + const Init::Target& initTarget() { return parent_init_target_; } + +private: + // Config::SubscriptionCallbacks + void onConfigUpdate(const std::vector& resources, + const std::string& version_info) override; + + void onConfigUpdate(const std::vector& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string&) override; + + void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, + const EnvoyException*) override; + + bool validateUpdateSize(int num_resources); + + virtual void beforeProviderUpdate() {} + virtual void afterProviderUpdate() {} + +protected: + const std::string route_config_name_; + // This scope must outlive the subscription_ below as the subscription has derived stats. + Stats::ScopePtr scope_; + Envoy::Config::SubscriptionPtr subscription_; + Server::Configuration::ServerFactoryContext& factory_context_; + + // Init target used to notify the parent init manager that the subscription [and its sub resource] + // is ready. + Init::SharedTargetImpl parent_init_target_; + // Init watcher on RDS and VHDS ready event. This watcher marks parent_init_target_ ready. + Init::WatcherImpl local_init_watcher_; + // Target which starts the RDS subscription. + Init::TargetImpl local_init_target_; + Init::ManagerImpl local_init_manager_; + std::string stat_prefix_; + RdsStats stats_; + RouteConfigProviderManager& route_config_provider_manager_; + const uint64_t manager_identifier_; + absl::optional route_config_provider_opt_; + RouteConfigUpdatePtr config_update_info_; + std::unique_ptr resource_decoder_; +}; + +using RdsRouteConfigSubscriptionSharedPtr = std::shared_ptr; + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/route_config_provider_manager.h b/source/common/rds/route_config_provider_manager.h new file mode 100644 index 0000000000000..063e7cb4064c4 --- /dev/null +++ b/source/common/rds/route_config_provider_manager.h @@ -0,0 +1,21 @@ +#pragma once + +#include "envoy/rds/route_config_provider.h" + +namespace Envoy { +namespace Rds { + +/** + * The RouteConfigProviderManager interface exposes helper functions for + * RouteConfigProvider implementations + */ +class RouteConfigProviderManager { +public: + virtual ~RouteConfigProviderManager() = default; + + virtual void eraseStaticProvider(RouteConfigProvider* provider) PURE; + virtual void eraseDynamicProvider(int64_t manager_identifier) PURE; +}; + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/route_config_provider_manager_impl.cc b/source/common/rds/route_config_provider_manager_impl.cc new file mode 100644 index 0000000000000..655316a029edf --- /dev/null +++ b/source/common/rds/route_config_provider_manager_impl.cc @@ -0,0 +1,95 @@ +#include "source/common/rds/route_config_provider_manager_impl.h" + +namespace Envoy { +namespace Rds { + +RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) { + config_tracker_entry_ = + admin.getConfigTracker().add("routes", [this](const Matchers::StringMatcher& matcher) { + return dumpRouteConfigs(matcher); + }); + // ConfigTracker keys must be unique. We are asserting that no one has stolen the "routes" key + // from us, since the returned entry will be nullptr if the key already exists. + RELEASE_ASSERT(config_tracker_entry_, ""); +} + +void RouteConfigProviderManagerImpl::eraseStaticProvider(RouteConfigProvider* provider) { + static_route_config_providers_.erase(provider); +} + +void RouteConfigProviderManagerImpl::eraseDynamicProvider(int64_t manager_identifier) { + dynamic_route_config_providers_.erase(manager_identifier); +} + +std::unique_ptr +RouteConfigProviderManagerImpl::dumpRouteConfigs( + const Matchers::StringMatcher& name_matcher) const { + auto config_dump = std::make_unique(); + + for (const auto& element : dynamic_route_config_providers_) { + const auto provider = element.second.first.lock(); + // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up + // in the RdsRouteConfigSubscription destructor, and the single threaded nature + // of this code, locking the weak_ptr will not fail. + ASSERT(provider); + + if (provider->configInfo()) { + if (!name_matcher.match(provider->configInfo().value().name_)) { + continue; + } + auto* dynamic_config = config_dump->mutable_dynamic_route_configs()->Add(); + dynamic_config->set_version_info(provider->configInfo().value().version_); + dynamic_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); + TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), + *dynamic_config->mutable_last_updated()); + } + } + + for (const auto& provider : static_route_config_providers_) { + ASSERT(provider->configInfo()); + if (!name_matcher.match(provider->configInfo().value().name_)) { + continue; + } + auto* static_config = config_dump->mutable_static_route_configs()->Add(); + static_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); + TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), + *static_config->mutable_last_updated()); + } + + return config_dump; +} + +void RouteConfigProviderManagerImpl::insertStaticProvider(RouteConfigProvider* provider) { + static_route_config_providers_.insert(provider); +} + +void RouteConfigProviderManagerImpl::insertDynamicProvider(int64_t manager_identifier, + RouteConfigProviderSharedPtr provider, + const Init::Target* init_target, + Init::Manager& init_manager) { + init_manager.add(*init_target); + dynamic_route_config_providers_.insert( + {manager_identifier, + std::make_pair(std::weak_ptr(provider), init_target)}); +} + +RouteConfigProviderSharedPtr +RouteConfigProviderManagerImpl::reuseDynamicProvider(uint64_t manager_identifier, + Init::Manager& init_manager, + const std::string& route_config_name) { + auto it = dynamic_route_config_providers_.find(manager_identifier); + if (it == dynamic_route_config_providers_.end()) { + return RouteConfigProviderSharedPtr(); + } + // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up + // in the RdsRouteConfigSubscription destructor, and the single threaded nature + // of this code, locking the weak_ptr will not fail. + auto existing_provider = it->second.first.lock(); + RELEASE_ASSERT(existing_provider != nullptr, + absl::StrCat("cannot find subscribed rds resource ", route_config_name)); + init_manager.add(*it->second.second); + return existing_provider; +} + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/route_config_provider_manager_impl.h b/source/common/rds/route_config_provider_manager_impl.h new file mode 100644 index 0000000000000..966a1bf69c7f7 --- /dev/null +++ b/source/common/rds/route_config_provider_manager_impl.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include "envoy/admin/v3/config_dump.pb.h" +#include "envoy/init/manager.h" +#include "envoy/init/target.h" +#include "envoy/server/admin.h" + +#include "source/common/common/matchers.h" +#include "source/common/protobuf/utility.h" +#include "source/common/rds/route_config_provider_manager.h" + +#include "absl/container/node_hash_map.h" +#include "absl/container/node_hash_set.h" + +namespace Envoy { +namespace Rds { + +class RouteConfigProviderManagerImpl : public RouteConfigProviderManager { +public: + RouteConfigProviderManagerImpl(Server::Admin& admin); + + void eraseStaticProvider(RouteConfigProvider* provider) override; + + void eraseDynamicProvider(int64_t manager_identifier) override; + + std::unique_ptr + dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const; + +protected: + void insertStaticProvider(RouteConfigProvider* provider); + void insertDynamicProvider(int64_t manager_identifier, RouteConfigProviderSharedPtr provider, + const Init::Target* init_target, Init::Manager& init_manager); + + RouteConfigProviderSharedPtr reuseDynamicProvider(uint64_t manager_identifier, + Init::Manager& init_manager, + const std::string& route_config_name); + +private: + // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map + // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists + // Then the lifetime management stuff is centralized and opaque. + absl::node_hash_map, const Init::Target*>> + dynamic_route_config_providers_; + absl::node_hash_set static_route_config_providers_; + Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; +}; + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/route_config_update_receiver_impl.cc b/source/common/rds/route_config_update_receiver_impl.cc new file mode 100644 index 0000000000000..13137dc86a217 --- /dev/null +++ b/source/common/rds/route_config_update_receiver_impl.cc @@ -0,0 +1,54 @@ +#include "source/common/rds/route_config_update_receiver_impl.h" + +namespace Envoy { +namespace Rds { + +RouteConfigUpdateReceiverImpl::RouteConfigUpdateReceiverImpl( + ConfigTraits& config_traits, Server::Configuration::ServerFactoryContext& factory_context) + : config_traits_(config_traits), time_source_(factory_context.timeSource()), + route_config_proto_(config_traits_.createProto()), last_config_hash_(0ull), + config_(config_traits_.createConfig()) {} + +bool RouteConfigUpdateReceiverImpl::updateHash(const Protobuf::Message& rc) { + const uint64_t new_hash = MessageUtil::hash(rc); + if (new_hash == last_config_hash_) { + return false; + } + last_config_hash_ = new_hash; + return true; +} + +void RouteConfigUpdateReceiverImpl::updateConfig( + std::unique_ptr&& route_config_proto) { + config_ = config_traits_.createConfig(*route_config_proto); + route_config_proto_ = std::move(route_config_proto); +} + +void RouteConfigUpdateReceiverImpl::onUpdateCommon(const std::string& version_info) { + last_config_version_ = version_info; + last_updated_ = time_source_.systemTime(); + config_info_.emplace(RouteConfigProvider::ConfigInfo{*route_config_proto_, routeConfigName(), + last_config_version_}); +} + +// Rds::RouteConfigUpdateReceiver +bool RouteConfigUpdateReceiverImpl::onRdsUpdate(const Protobuf::Message& rc, + const std::string& version_info) { + if (!updateHash(rc)) { + return false; + } + updateConfig(config_traits_.cloneProto(rc)); + onUpdateCommon(version_info); + return true; +} + +const std::string& RouteConfigUpdateReceiverImpl::routeConfigName() const { + return config_traits_.resourceName(*route_config_proto_); +} + +absl::optional RouteConfigUpdateReceiverImpl::configInfo() const { + return config_info_; +} + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/route_config_update_receiver_impl.h b/source/common/rds/route_config_update_receiver_impl.h new file mode 100644 index 0000000000000..12a68872e960c --- /dev/null +++ b/source/common/rds/route_config_update_receiver_impl.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include "envoy/rds/route_config_update_receiver.h" +#include "envoy/server/factory_context.h" + +namespace Envoy { +namespace Rds { + +class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { +public: + RouteConfigUpdateReceiverImpl(ConfigTraits& config_traits, + Server::Configuration::ServerFactoryContext& factory_context); + + bool updateHash(const Protobuf::Message& rc); + void updateConfig(std::unique_ptr&& route_config_proto); + void onUpdateCommon(const std::string& version_info); + + // RouteConfigUpdateReceiver + bool onRdsUpdate(const Protobuf::Message& rc, const std::string& version_info) override; + + const std::string& routeConfigName() const override; + const std::string& configVersion() const override { return last_config_version_; } + uint64_t configHash() const override { return last_config_hash_; } + absl::optional configInfo() const override; + const Protobuf::Message& protobufConfiguration() override { return *route_config_proto_; } + ConfigConstSharedPtr parsedConfiguration() const override { return config_; } + SystemTime lastUpdated() const override { return last_updated_; } + const ConfigTraits& configTraits() const override { return config_traits_; } + +private: + ConfigTraits& config_traits_; + TimeSource& time_source_; + ProtobufTypes::MessagePtr route_config_proto_; + uint64_t last_config_hash_; + std::string last_config_version_; + SystemTime last_updated_; + absl::optional config_info_; + ConfigConstSharedPtr config_; +}; + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/static_route_config_provider_impl.cc b/source/common/rds/static_route_config_provider_impl.cc new file mode 100644 index 0000000000000..26b1a591deb1a --- /dev/null +++ b/source/common/rds/static_route_config_provider_impl.cc @@ -0,0 +1,25 @@ +#include "source/common/rds/static_route_config_provider_impl.h" + +namespace Envoy { +namespace Rds { + +StaticRouteConfigProviderImpl::StaticRouteConfigProviderImpl( + const Protobuf::Message& route_config_proto, ConfigTraits& config_traits, + Server::Configuration::ServerFactoryContext& factory_context, + RouteConfigProviderManager& route_config_provider_manager) + : config_(config_traits.createConfig(route_config_proto)), + route_config_proto_(config_traits.cloneProto(route_config_proto)), + route_config_name_(config_traits.resourceName(*route_config_proto_)), + last_updated_(factory_context.timeSource().systemTime()), + route_config_provider_manager_(route_config_provider_manager) {} + +StaticRouteConfigProviderImpl::~StaticRouteConfigProviderImpl() { + route_config_provider_manager_.eraseStaticProvider(this); +} + +absl::optional StaticRouteConfigProviderImpl::configInfo() const { + return RouteConfigProvider::ConfigInfo{*route_config_proto_, route_config_name_, ""}; +} + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/rds/static_route_config_provider_impl.h b/source/common/rds/static_route_config_provider_impl.h new file mode 100644 index 0000000000000..abafa26c6f713 --- /dev/null +++ b/source/common/rds/static_route_config_provider_impl.h @@ -0,0 +1,39 @@ +#pragma once + +#include "envoy/rds/config_traits.h" +#include "envoy/rds/route_config_provider.h" +#include "envoy/server/factory_context.h" + +#include "source/common/rds/route_config_provider_manager.h" + +namespace Envoy { +namespace Rds { + +/** + * Implementation of RouteConfigProvider that holds a static route configuration. + */ +class StaticRouteConfigProviderImpl : public RouteConfigProvider { +public: + StaticRouteConfigProviderImpl(const Protobuf::Message& route_config_proto, + ConfigTraits& config_traits, + Server::Configuration::ServerFactoryContext& factory_context, + RouteConfigProviderManager& route_config_provider_manager); + + ~StaticRouteConfigProviderImpl() override; + + // Router::RouteConfigProvider + ConfigConstSharedPtr config() override { return config_; } + absl::optional configInfo() const override; + SystemTime lastUpdated() const override { return last_updated_; } + void onConfigUpdate() override {} + +private: + ConfigConstSharedPtr config_; + ProtobufTypes::MessagePtr route_config_proto_; + const std::string& route_config_name_; + SystemTime last_updated_; + RouteConfigProviderManager& route_config_provider_manager_; +}; + +} // namespace Rds +} // namespace Envoy diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 2fa79631e1d2f..4c1cd46d09772 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -128,7 +128,7 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", "//source/common/protobuf:utility_lib", - "//source/common/router:rds_template_lib", + "//source/common/rds:rds_lib", "@envoy_api//envoy/config/route/v3:pkg_cc_proto", "@envoy_api//envoy/service/discovery/v3:pkg_cc_proto", ], @@ -175,7 +175,7 @@ envoy_cc_library( "//envoy/router:route_config_provider_manager_interface", "//envoy/router:route_config_update_info_interface", "//envoy/server:admin_interface", - "//source/common/router:rds_template_lib", + "//source/common/rds:rds_lib", "//source/common/router:route_config_update_impl_lib", "//source/common/router:vhds_lib", "@envoy_api//envoy/admin/v3:pkg_cc_proto", @@ -413,35 +413,3 @@ envoy_cc_library( "//envoy/router:router_interface", ], ) - -envoy_cc_library( - name = "rds_template_lib", - hdrs = [ - "rds/config_factory.h", - "rds/rds_route_config_provider_impl.h", - "rds/rds_route_config_subscription.h", - "rds/route_config_provider_manager.h", - "rds/route_config_provider_manager_impl.h", - "rds/route_config_update_receiver_impl.h", - "rds/static_route_config_provider_impl.h", - ], - deps = [ - "//envoy/router:rds_template_interface", - "//envoy/singleton:instance_interface", - "//envoy/thread_local:thread_local_interface", - "//source/common/common:assert_lib", - "//source/common/common:callback_impl_lib", - "//source/common/common:cleanup_lib", - "//source/common/common:minimal_logger_lib", - "//source/common/config:api_version_lib", - "//source/common/config:subscription_base_interface", - "//source/common/config:subscription_factory_lib", - "//source/common/config:utility_lib", - "//source/common/init:manager_lib", - "//source/common/init:target_lib", - "//source/common/init:watcher_lib", - "//source/common/protobuf:utility_lib", - "@envoy_api//envoy/admin/v3:pkg_cc_proto", - "@envoy_api//envoy/config/core/v3:pkg_cc_proto", - ], -) diff --git a/source/common/router/rds/config_factory.h b/source/common/router/rds/config_factory.h deleted file mode 100644 index 2d6cb8c38fb8b..0000000000000 --- a/source/common/router/rds/config_factory.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "envoy/common/pure.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -template class ConfigFactory { -public: - virtual ~ConfigFactory() = default; - - /** - * Create a config object based on a route configuration. - */ - virtual std::shared_ptr createConfig(const RouteConfiguration& rc) const PURE; - - /** - * Create a dummy config object without actual route configuration. - * This object will be used before the first valid route configuration is fetched. - */ - virtual std::shared_ptr createConfig() const PURE; -}; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds/rds_route_config_provider_impl.h b/source/common/router/rds/rds_route_config_provider_impl.h deleted file mode 100644 index 770d532ee0d7e..0000000000000 --- a/source/common/router/rds/rds_route_config_provider_impl.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include -#include - -#include "envoy/router/rds/route_config_provider.h" -#include "envoy/router/rds/route_config_update_receiver.h" -#include "envoy/server/factory_context.h" -#include "envoy/thread_local/thread_local.h" - -#include "source/common/common/logger.h" -#include "source/common/router/rds/rds_route_config_subscription.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -/** - * Implementation of RouteConfigProvider that fetches the route configuration dynamically using - * the subscription. - */ -template -class RdsRouteConfigProviderImpl : public RouteConfigProvider, - Logger::Loggable { -public: - RdsRouteConfigProviderImpl( - RdsRouteConfigSubscriptionSharedPtr&& subscription, - Server::Configuration::ServerFactoryContext& factory_context) - : subscription_(std::move(subscription)), - config_update_info_(subscription_->routeConfigUpdate()), - tls_(factory_context.threadLocal()) { - - auto initial_config = config_update_info_->parsedConfiguration(); - ASSERT(initial_config); - tls_.set([initial_config](Event::Dispatcher&) { - return std::make_shared(initial_config); - }); - // It should be 1:1 mapping due to shared rds config. - ASSERT(!subscription_->routeConfigProvider().has_value()); - subscription_->routeConfigProvider().emplace(this); - } - - ~RdsRouteConfigProviderImpl() override { - ASSERT(subscription_->routeConfigProvider().has_value()); - subscription_->routeConfigProvider().reset(); - } - - RdsRouteConfigSubscription& subscription() { return *subscription_; } - - // Rds::RouteConfigProvider - std::shared_ptr config() override { return tls_->config_; } - - absl::optional::ConfigInfo> - configInfo() const override { - return config_update_info_->configInfo(); - } - SystemTime lastUpdated() const override { return config_update_info_->lastUpdated(); } - void onConfigUpdate() override { - tls_.runOnAllThreads([new_config = config_update_info_->parsedConfiguration()]( - OptRef tls) { tls->config_ = new_config; }); - } - void validateConfig(const RouteConfiguration&) const override {} - -private: - struct ThreadLocalConfig : public ThreadLocal::ThreadLocalObject { - ThreadLocalConfig(std::shared_ptr initial_config) - : config_(std::move(initial_config)) {} - std::shared_ptr config_; - }; - - RdsRouteConfigSubscriptionSharedPtr subscription_; - RouteConfigUpdatePtr& config_update_info_; - ThreadLocal::TypedSlot tls_; -}; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds/rds_route_config_subscription.h b/source/common/router/rds/rds_route_config_subscription.h deleted file mode 100644 index 8c2b98b88453f..0000000000000 --- a/source/common/router/rds/rds_route_config_subscription.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once - -#include -#include - -#include "envoy/config/core/v3/config_source.pb.h" -#include "envoy/router/rds/route_config_provider.h" -#include "envoy/router/rds/route_config_update_receiver.h" -#include "envoy/server/factory_context.h" -#include "envoy/stats/scope.h" - -#include "source/common/common/logger.h" -#include "source/common/config/subscription_base.h" -#include "source/common/grpc/common.h" -#include "source/common/init/manager_impl.h" -#include "source/common/init/target_impl.h" -#include "source/common/init/watcher_impl.h" -#include "source/common/router/rds/route_config_provider_manager.h" - -#include "absl/types/optional.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -/** - * All RDS stats. @see stats_macros.h - */ -#define ALL_RDS_STATS(COUNTER, GAUGE) \ - COUNTER(config_reload) \ - COUNTER(update_empty) \ - GAUGE(config_reload_time_ms, NeverImport) - -/** - * Struct definition for all RDS stats. @see stats_macros.h - */ -struct RdsStats { - ALL_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) -}; - -/** - * A class that fetches the route configuration dynamically using the RDS API and updates them to - * RDS config providers. - */ -template -class RdsRouteConfigSubscription : Envoy::Config::SubscriptionBase, - protected Logger::Loggable { -public: - RdsRouteConfigSubscription( - RouteConfigUpdatePtr&& config_update, - const envoy::config::core::v3::ConfigSource& config_source, - const std::string& route_config_name, const uint64_t manager_identifier, - Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, - RouteConfigProviderManager& route_config_provider_manager) - : Envoy::Config::SubscriptionBase( - factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), - route_config_name_(route_config_name), - scope_( - factory_context.scope().createScope(stat_prefix + "rds." + route_config_name_ + ".")), - factory_context_(factory_context), - parent_init_target_(fmt::format("RdsRouteConfigSubscription init {}", route_config_name_), - [this]() { local_init_manager_.initialize(local_init_watcher_); }), - local_init_watcher_(fmt::format("RDS local-init-watcher {}", route_config_name_), - [this]() { parent_init_target_.ready(); }), - local_init_target_( - fmt::format("RdsRouteConfigSubscription local-init-target {}", route_config_name_), - [this]() { subscription_->start({route_config_name_}); }), - local_init_manager_(fmt::format("RDS local-init-manager {}", route_config_name_)), - stat_prefix_(stat_prefix), - stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}), - route_config_provider_manager_(route_config_provider_manager), - manager_identifier_(manager_identifier), config_update_info_(std::move(config_update)) { - const auto resource_name = - Envoy::Config::SubscriptionBase::getResourceName(); - subscription_ = - factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( - config_source, Envoy::Grpc::Common::typeUrl(resource_name), *scope_, *this, - Envoy::Config::SubscriptionBase::resource_decoder_, {}); - local_init_manager_.add(local_init_target_); - } - - ~RdsRouteConfigSubscription() override { - // If we get destroyed during initialization, make sure we signal that we "initialized". - local_init_target_.ready(); - - // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that - // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the - // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get - // cleaned by the RdsRouteConfigProvider's destructor. - route_config_provider_manager_.eraseDynamicProvider(manager_identifier_); - } - - absl::optional*>& routeConfigProvider() { - return route_config_provider_opt_; - } - RouteConfigUpdatePtr& routeConfigUpdate() { - return config_update_info_; - } - - const Init::Target& initTarget() { return parent_init_target_; } - -private: - // Config::SubscriptionCallbacks - void onConfigUpdate(const std::vector& resources, - const std::string& version_info) override { - if (!validateUpdateSize(resources.size())) { - return; - } - const auto& route_config = - dynamic_cast(resources[0].get().resource()); - if (route_config.name() != route_config_name_) { - // check_format.py complains about throw, dummy comment helps to ignore - /**/ throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}", - route_config_name_, route_config.name())); - } - if (route_config_provider_opt_.has_value()) { - route_config_provider_opt_.value()->validateConfig(route_config); - } - if (config_update_info_->onRdsUpdate(route_config, version_info)) { - stats_.config_reload_.inc(); - stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource())); - - beforeProviderUpdate(); - - ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_, - config_update_info_->configHash()); - - if (route_config_provider_opt_.has_value()) { - route_config_provider_opt_.value()->onConfigUpdate(); - } - - afterProviderUpdate(); - } - - local_init_target_.ready(); - } - - void onConfigUpdate(const std::vector& added_resources, - const Protobuf::RepeatedPtrField& removed_resources, - const std::string&) override { - if (!removed_resources.empty()) { - // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense - // (see discussion in #6879), and so we should do something other than ignoring here. - ENVOY_LOG( - error, - "Server sent a delta RDS update attempting to remove a resource (name: {}). Ignoring.", - removed_resources[0]); - } - if (!added_resources.empty()) { - onConfigUpdate(added_resources, added_resources[0].get().version()); - } - } - - void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason, - const EnvoyException*) override { - ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason); - // We need to allow server startup to continue, even if we have a bad - // config. - local_init_target_.ready(); - } - - bool validateUpdateSize(int num_resources) { - if (num_resources == 0) { - ENVOY_LOG(debug, "Missing RouteConfiguration for {} in onConfigUpdate()", route_config_name_); - stats_.update_empty_.inc(); - local_init_target_.ready(); - return false; - } - if (num_resources != 1) { - /**/ throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", num_resources)); - // (would be a return false here) - } - return true; - } - - virtual void beforeProviderUpdate() {} - virtual void afterProviderUpdate() {} - -protected: - const std::string route_config_name_; - // This scope must outlive the subscription_ below as the subscription has derived stats. - Stats::ScopePtr scope_; - Envoy::Config::SubscriptionPtr subscription_; - Server::Configuration::ServerFactoryContext& factory_context_; - - // Init target used to notify the parent init manager that the subscription [and its sub resource] - // is ready. - Init::SharedTargetImpl parent_init_target_; - // Init watcher on RDS and VHDS ready event. This watcher marks parent_init_target_ ready. - Init::WatcherImpl local_init_watcher_; - // Target which starts the RDS subscription. - Init::TargetImpl local_init_target_; - Init::ManagerImpl local_init_manager_; - std::string stat_prefix_; - RdsStats stats_; - RouteConfigProviderManager& route_config_provider_manager_; - const uint64_t manager_identifier_; - absl::optional*> route_config_provider_opt_; - RouteConfigUpdatePtr config_update_info_; -}; - -template -using RdsRouteConfigSubscriptionSharedPtr = - std::shared_ptr>; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds/route_config_provider_manager.h b/source/common/router/rds/route_config_provider_manager.h deleted file mode 100644 index 81e0909d5ae87..0000000000000 --- a/source/common/router/rds/route_config_provider_manager.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "envoy/router/rds/route_config_provider.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -/** - * The RouteConfigProviderManager exposes the ability to get a RouteConfigProvider. This interface - * is exposed to the Server's FactoryContext in order to allow HttpConnectionManagers to get - * RouteConfigProviders. - */ -template class RouteConfigProviderManager { -public: - virtual ~RouteConfigProviderManager() = default; - - virtual void eraseStaticProvider(RouteConfigProvider* provider) PURE; - virtual void eraseDynamicProvider(int64_t manager_identifier) PURE; -}; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds/route_config_provider_manager_impl.h b/source/common/router/rds/route_config_provider_manager_impl.h deleted file mode 100644 index 72d3cf987ecc9..0000000000000 --- a/source/common/router/rds/route_config_provider_manager_impl.h +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -#include -#include - -#include "envoy/admin/v3/config_dump.pb.h" -#include "envoy/init/manager.h" -#include "envoy/init/target.h" -#include "envoy/server/admin.h" - -#include "source/common/common/matchers.h" -#include "source/common/protobuf/utility.h" -#include "source/common/router/rds/route_config_provider_manager.h" - -#include "absl/container/node_hash_map.h" -#include "absl/container/node_hash_set.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -template -class RouteConfigProviderManagerImpl - : public RouteConfigProviderManager { -public: - RouteConfigProviderManagerImpl(Server::Admin& admin) { - config_tracker_entry_ = - admin.getConfigTracker().add("routes", [this](const Matchers::StringMatcher& matcher) { - return dumpRouteConfigs(matcher); - }); - // ConfigTracker keys must be unique. We are asserting that no one has stolen the "routes" key - // from us, since the returned entry will be nullptr if the key already exists. - RELEASE_ASSERT(config_tracker_entry_, ""); - } - - void eraseStaticProvider(RouteConfigProvider* provider) override { - static_route_config_providers_.erase(provider); - } - - void eraseDynamicProvider(int64_t manager_identifier) override { - dynamic_route_config_providers_.erase(manager_identifier); - } - - std::unique_ptr - dumpRouteConfigs(const Matchers::StringMatcher& name_matcher) const { - auto config_dump = std::make_unique(); - - for (const auto& element : dynamic_route_config_providers_) { - const auto provider = element.second.first.lock(); - // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up - // in the RdsRouteConfigSubscription destructor, and the single threaded nature - // of this code, locking the weak_ptr will not fail. - ASSERT(provider); - - if (provider->configInfo()) { - if (!name_matcher.match(provider->configInfo().value().config_.name())) { - continue; - } - auto* dynamic_config = config_dump->mutable_dynamic_route_configs()->Add(); - dynamic_config->set_version_info(provider->configInfo().value().version_); - dynamic_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); - TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), - *dynamic_config->mutable_last_updated()); - } - } - - for (const auto& provider : static_route_config_providers_) { - ASSERT(provider->configInfo()); - if (!name_matcher.match(provider->configInfo().value().config_.name())) { - continue; - } - auto* static_config = config_dump->mutable_static_route_configs()->Add(); - static_config->mutable_route_config()->PackFrom(provider->configInfo().value().config_); - TimestampUtil::systemClockToTimestamp(provider->lastUpdated(), - *static_config->mutable_last_updated()); - } - - return config_dump; - } - -protected: - void insertStaticProvider(RouteConfigProvider* provider) { - static_route_config_providers_.insert(provider); - } - - void insertDynamicProvider(int64_t manager_identifier, - RouteConfigProviderSharedPtr provider, - const Init::Target* init_target, Init::Manager& init_manager) { - init_manager.add(*init_target); - dynamic_route_config_providers_.insert( - {manager_identifier, - std::make_pair(std::weak_ptr>(provider), - init_target)}); - } - - RouteConfigProviderSharedPtr - reuseDynamicProvider(uint64_t manager_identifier, Init::Manager& init_manager, - const std::string& route_config_name) { - auto it = dynamic_route_config_providers_.find(manager_identifier); - if (it == dynamic_route_config_providers_.end()) { - return RouteConfigProviderSharedPtr(); - } - // Because the RouteConfigProviderManager's weak_ptrs only get cleaned up - // in the RdsRouteConfigSubscription destructor, and the single threaded nature - // of this code, locking the weak_ptr will not fail. - auto existing_provider = it->second.first.lock(); - RELEASE_ASSERT(existing_provider != nullptr, - absl::StrCat("cannot find subscribed rds resource ", route_config_name)); - init_manager.add(*it->second.second); - return existing_provider; - } - -private: - // TODO(jsedgwick) These two members are prime candidates for the owned-entry list/map - // as in ConfigTracker. I.e. the ProviderImpls would have an EntryOwner for these lists - // Then the lifetime management stuff is centralized and opaque. - absl::node_hash_map>, - const Init::Target*>> - dynamic_route_config_providers_; - absl::node_hash_set*> - static_route_config_providers_; - Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; -}; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds/route_config_update_receiver_impl.h b/source/common/router/rds/route_config_update_receiver_impl.h deleted file mode 100644 index 1caa432f0ee94..0000000000000 --- a/source/common/router/rds/route_config_update_receiver_impl.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include - -#include "envoy/router/rds/route_config_update_receiver.h" -#include "envoy/server/factory_context.h" - -#include "source/common/router/rds/config_factory.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -template -class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { -public: - RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context, - ConfigFactory& config_factory) - : time_source_(factory_context.timeSource()), - route_config_proto_(std::make_unique()), last_config_hash_(0ull), - config_(config_factory.createConfig()), config_factory_(config_factory) {} - - bool updateHash(const RouteConfiguration& rc) { - const uint64_t new_hash = MessageUtil::hash(rc); - if (new_hash == last_config_hash_) { - return false; - } - last_config_hash_ = new_hash; - return true; - } - - void updateConfig(std::unique_ptr&& route_config_proto) { - config_ = config_factory_.createConfig(*route_config_proto); - route_config_proto_ = std::move(route_config_proto); - } - - void onUpdateCommon(const std::string& version_info) { - last_config_version_ = version_info; - last_updated_ = time_source_.systemTime(); - config_info_.emplace(typename RouteConfigProvider::ConfigInfo{ - *route_config_proto_, last_config_version_}); - } - - // Rds::RouteConfigUpdateReceiver - bool onRdsUpdate(const RouteConfiguration& rc, const std::string& version_info) override { - if (!updateHash(rc)) { - return false; - } - updateConfig(std::make_unique(rc)); - onUpdateCommon(version_info); - return true; - } - - const std::string& routeConfigName() const override { return route_config_proto_->name(); } - const std::string& configVersion() const override { return last_config_version_; } - uint64_t configHash() const override { return last_config_hash_; } - absl::optional::ConfigInfo> - configInfo() const override { - return config_info_; - } - const RouteConfiguration& protobufConfiguration() override { return *route_config_proto_; } - std::shared_ptr parsedConfiguration() const override { return config_; } - SystemTime lastUpdated() const override { return last_updated_; } - -private: - TimeSource& time_source_; - std::unique_ptr route_config_proto_; - uint64_t last_config_hash_; - std::string last_config_version_; - SystemTime last_updated_; - absl::optional::ConfigInfo> config_info_; - std::shared_ptr config_; - ConfigFactory& config_factory_; -}; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds/static_route_config_provider_impl.h b/source/common/router/rds/static_route_config_provider_impl.h deleted file mode 100644 index 58a0b9c8ae88f..0000000000000 --- a/source/common/router/rds/static_route_config_provider_impl.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "envoy/router/rds/route_config_provider.h" -#include "envoy/server/factory_context.h" - -#include "source/common/router/rds/route_config_provider_manager.h" - -namespace Envoy { -namespace Router { -namespace Rds { - -/** - * Implementation of RouteConfigProvider that holds a static route configuration. - */ -template -class StaticRouteConfigProviderImpl : public RouteConfigProvider { -public: - StaticRouteConfigProviderImpl( - std::shared_ptr config, const RouteConfiguration& route_config_proto, - Server::Configuration::ServerFactoryContext& factory_context, - RouteConfigProviderManager& route_config_provider_manager) - : config_(config), route_config_proto_{route_config_proto}, - last_updated_(factory_context.timeSource().systemTime()), - route_config_provider_manager_(route_config_provider_manager) {} - - ~StaticRouteConfigProviderImpl() override { - route_config_provider_manager_.eraseStaticProvider(this); - } - - // Router::RouteConfigProvider - std::shared_ptr config() override { return config_; } - absl::optional::ConfigInfo> - configInfo() const override { - return typename RouteConfigProvider::ConfigInfo{route_config_proto_, - ""}; - } - SystemTime lastUpdated() const override { return last_updated_; } - void onConfigUpdate() override {} - void validateConfig(const RouteConfiguration&) const override {} - -private: - std::shared_ptr config_; - RouteConfiguration route_config_proto_; - SystemTime last_updated_; - RouteConfigProviderManager& route_config_provider_manager_; -}; - -} // namespace Rds -} // namespace Router -} // namespace Envoy diff --git a/source/common/router/rds_impl.cc b/source/common/router/rds_impl.cc index 1db6d739d135f..82473c81cd8b3 100644 --- a/source/common/router/rds_impl.cc +++ b/source/common/router/rds_impl.cc @@ -52,33 +52,37 @@ RouteConfigProviderSharedPtr RouteConfigProviderUtil::create( } StaticRouteConfigProviderImpl::StaticRouteConfigProviderImpl( - const envoy::config::route::v3::RouteConfiguration& config, - const OptionalHttpFilters& optional_http_filters, + const envoy::config::route::v3::RouteConfiguration& config, Rds::ConfigTraits& config_traits, Server::Configuration::ServerFactoryContext& factory_context, - ProtobufMessage::ValidationVisitor& validator, - RouteConfigProviderManagerImpl& route_config_provider_manager) - : base_(std::make_shared(config, optional_http_filters, factory_context, validator, - true), - config, factory_context, route_config_provider_manager), + Rds::RouteConfigProviderManager& route_config_provider_manager) + : base_(config, config_traits, factory_context, route_config_provider_manager), route_config_provider_manager_(route_config_provider_manager) {} StaticRouteConfigProviderImpl::~StaticRouteConfigProviderImpl() { route_config_provider_manager_.eraseStaticProvider(this); } +ConfigConstSharedPtr StaticRouteConfigProviderImpl::configCast() { + ASSERT(dynamic_cast(base_.config().get())); + return std::static_pointer_cast(base_.config()); +} + // TODO(htuch): If support for multiple clusters is added per #1170 cluster_name_ RdsRouteConfigSubscription::RdsRouteConfigSubscription( RouteConfigUpdateReceiver* config_update, + Envoy::Config::OpaqueResourceDecoder* resource_decoder, const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, const uint64_t manager_identifier, Server::Configuration::ServerFactoryContext& factory_context, - const std::string& stat_prefix, RouteConfigProviderManagerImpl& route_config_provider_manager) - : Rds::RdsRouteConfigSubscription( - RouteConfigUpdatePtr(config_update), rds.config_source(), rds.route_config_name(), - manager_identifier, factory_context, stat_prefix, route_config_provider_manager), + const std::string& stat_prefix, Rds::RouteConfigProviderManager& route_config_provider_manager) + : Rds::RdsRouteConfigSubscription( + RouteConfigUpdatePtr(config_update), + std::unique_ptr(resource_decoder), + rds.config_source(), rds.route_config_name(), manager_identifier, factory_context, + stat_prefix, route_config_provider_manager), config_update_info_(config_update) {} void RdsRouteConfigSubscription::beforeProviderUpdate() { - if (config_update_info_->protobufConfiguration().has_vhds() && + if (config_update_info_->protobufConfigurationCast().has_vhds() && config_update_info_->vhdsConfigurationChanged()) { std::unique_ptr noop_init_manager; std::unique_ptr resume_rds; @@ -95,7 +99,7 @@ void RdsRouteConfigSubscription::beforeProviderUpdate() { void RdsRouteConfigSubscription::afterProviderUpdate() { // RDS update removed VHDS configuration - if (!config_update_info_->protobufConfiguration().has_vhds()) { + if (!config_update_info_->protobufConfigurationCast().has_vhds()) { vhds_subscription_.release(); } @@ -132,13 +136,10 @@ void RdsRouteConfigSubscription::updateOnDemand(const std::string& aliases) { RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl( RdsRouteConfigSubscription* subscription, - Server::Configuration::ServerFactoryContext& factory_context, - const RouteConfigProviderManager::OptionalHttpFilters& optional_http_filters) + Server::Configuration::ServerFactoryContext& factory_context) : base_(RdsRouteConfigSubscriptionSharedPtr(subscription), factory_context), subscription_(subscription), config_update_info_(subscription->routeConfigUpdate()), - factory_context_(factory_context), - validator_(factory_context.messageValidationContext().dynamicValidationVisitor()), - optional_http_filters_(optional_http_filters) { + factory_context_(factory_context) { // The subscription referenced by the 'base_' and by 'this' is the same. // But the subscription contains two references back to the provider. // One is in Rds::RdsRouteConfigSubscription other in RdsRouteConfigSubscription part. @@ -186,10 +187,9 @@ void RdsRouteConfigProviderImpl::onConfigUpdate() { } } -void RdsRouteConfigProviderImpl::validateConfig( - const envoy::config::route::v3::RouteConfiguration& config) const { - // TODO(lizan): consider cache the config here until onConfigUpdate. - ConfigImpl validation_config(config, optional_http_filters_, factory_context_, validator_, false); +ConfigConstSharedPtr RdsRouteConfigProviderImpl::configCast() { + ASSERT(dynamic_cast(base_.config().get())); + return std::static_pointer_cast(base_.config()); } // Schedules a VHDS request on the main thread and queues up the callback to use when the VHDS @@ -216,8 +216,7 @@ void RdsRouteConfigProviderImpl::requestVirtualHostsUpdate( } RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) - : Rds::RouteConfigProviderManagerImpl( - admin) {} + : Rds::RouteConfigProviderManagerImpl(admin) {} Router::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, @@ -229,22 +228,21 @@ Router::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRo auto existing_provider = reuseDynamicProvider(manager_identifier, init_manager, rds.route_config_name()); - if (!existing_provider) { - RouteConfigUpdateReceiverImpl* config_update( - new RouteConfigUpdateReceiverImpl(factory_context, optional_http_filters)); - RdsRouteConfigSubscription* subscription(new RdsRouteConfigSubscription( - config_update, rds, manager_identifier, factory_context, stat_prefix, *this)); - RdsRouteConfigProviderImplSharedPtr new_provider{ - new RdsRouteConfigProviderImpl(subscription, factory_context, optional_http_filters)}; - insertDynamicProvider(manager_identifier, new_provider, - &new_provider->subscription().initTarget(), init_manager); - return new_provider; - } else { - RouteConfigProviderSharedPtr existing_provider_downcasted = - std::dynamic_pointer_cast(existing_provider); - ASSERT(existing_provider_downcasted); - return existing_provider_downcasted; + if (existing_provider) { + ASSERT(dynamic_cast(existing_provider.get())); + return std::static_pointer_cast(existing_provider); } + auto config_update = new RouteConfigUpdateReceiverImpl(factory_context, optional_http_filters); + auto resource_decoder = + new Envoy::Config::OpaqueResourceDecoderImpl( + factory_context.messageValidationContext().dynamicValidationVisitor(), "name"); + auto subscription = + new RdsRouteConfigSubscription(config_update, resource_decoder, rds, manager_identifier, + factory_context, stat_prefix, *this); + auto new_provider = std::make_shared(subscription, factory_context); + insertDynamicProvider(manager_identifier, new_provider, + &new_provider->subscription().initTarget(), init_manager); + return new_provider; } RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigProvider( @@ -252,8 +250,9 @@ RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigPr const OptionalHttpFilters& optional_http_filters, Server::Configuration::ServerFactoryContext& factory_context, ProtobufMessage::ValidationVisitor& validator) { - auto provider = std::make_unique( - route_config, optional_http_filters, factory_context, validator, *this); + ConfigTraitsImpl config_traits(optional_http_filters, factory_context, validator, true); + auto provider = std::make_unique(route_config, config_traits, + factory_context, *this); insertStaticProvider(provider.get()); return provider; } diff --git a/source/common/router/rds_impl.h b/source/common/router/rds_impl.h index 967044051b09f..2833b38edb7de 100644 --- a/source/common/router/rds_impl.h +++ b/source/common/router/rds_impl.h @@ -31,11 +31,11 @@ #include "source/common/init/target_impl.h" #include "source/common/init/watcher_impl.h" #include "source/common/protobuf/utility.h" -#include "source/common/router/rds/rds_route_config_provider_impl.h" -#include "source/common/router/rds/rds_route_config_subscription.h" -#include "source/common/router/rds/route_config_provider_manager_impl.h" -#include "source/common/router/rds/route_config_update_receiver_impl.h" -#include "source/common/router/rds/static_route_config_provider_impl.h" +#include "source/common/rds/rds_route_config_provider_impl.h" +#include "source/common/rds/rds_route_config_subscription.h" +#include "source/common/rds/route_config_provider_manager_impl.h" +#include "source/common/rds/route_config_update_receiver_impl.h" +#include "source/common/rds/static_route_config_provider_impl.h" #include "source/common/router/vhds.h" #include "absl/container/node_hash_map.h" @@ -64,35 +64,31 @@ class RouteConfigProviderUtil { const std::string& stat_prefix, RouteConfigProviderManager& route_config_provider_manager); }; -class RouteConfigProviderManagerImpl; -using ConfigFactory = Rds::ConfigFactory; - /** * Implementation of RouteConfigProvider that holds a static route configuration. */ class StaticRouteConfigProviderImpl : public RouteConfigProvider { public: StaticRouteConfigProviderImpl(const envoy::config::route::v3::RouteConfiguration& config, - const RouteConfigProviderManager::OptionalHttpFilters& http_filters, + Rds::ConfigTraits& config_traits, Server::Configuration::ServerFactoryContext& factory_context, - ProtobufMessage::ValidationVisitor& validator, - RouteConfigProviderManagerImpl& route_config_provider_manager); + Rds::RouteConfigProviderManager& route_config_provider_manager); ~StaticRouteConfigProviderImpl() override; // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override { return base_.config(); } + Rds::ConfigConstSharedPtr config() override { return base_.config(); } absl::optional configInfo() const override { return base_.configInfo(); } SystemTime lastUpdated() const override { return base_.lastUpdated(); } void onConfigUpdate() override { base_.onConfigUpdate(); } - void validateConfig(const envoy::config::route::v3::RouteConfiguration&) const override {} + ConfigConstSharedPtr configCast() override; void requestVirtualHostsUpdate(const std::string&, Event::Dispatcher&, std::weak_ptr) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } private: - Rds::StaticRouteConfigProviderImpl base_; - RouteConfigProviderManagerImpl& route_config_provider_manager_; + Rds::StaticRouteConfigProviderImpl base_; + Rds::RouteConfigProviderManager& route_config_provider_manager_; }; /** @@ -100,15 +96,15 @@ class StaticRouteConfigProviderImpl : public RouteConfigProvider { * RDS config providers. */ -class RdsRouteConfigSubscription - : public Rds::RdsRouteConfigSubscription { +class RdsRouteConfigSubscription : public Rds::RdsRouteConfigSubscription { public: RdsRouteConfigSubscription( RouteConfigUpdateReceiver* config_update, + Envoy::Config::OpaqueResourceDecoder* resource_decoder, const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds, const uint64_t manager_identifier, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, - RouteConfigProviderManagerImpl& route_config_provider_manager); + Rds::RouteConfigProviderManager& route_config_provider_manager); absl::optional& routeConfigProvider() { return route_config_provider_opt_; } RouteConfigUpdateReceiver* routeConfigUpdate() { return config_update_info_; } @@ -152,48 +148,42 @@ struct UpdateOnDemandCallback { class RdsRouteConfigProviderImpl : public RouteConfigProvider, Logger::Loggable { public: - RdsRouteConfigProviderImpl( - RdsRouteConfigSubscription* subscription, - Server::Configuration::ServerFactoryContext& factory_context, - const RouteConfigProviderManager::OptionalHttpFilters& optional_http_filters); + RdsRouteConfigProviderImpl(RdsRouteConfigSubscription* subscription, + Server::Configuration::ServerFactoryContext& factory_context); ~RdsRouteConfigProviderImpl() override; RdsRouteConfigSubscription& subscription() { return *subscription_; } // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override { return base_.config(); } + Rds::ConfigConstSharedPtr config() override { return base_.config(); } absl::optional configInfo() const override { return base_.configInfo(); } SystemTime lastUpdated() const override { return base_.lastUpdated(); } void onConfigUpdate() override; + ConfigConstSharedPtr configCast() override; void requestVirtualHostsUpdate( const std::string& for_domain, Event::Dispatcher& thread_local_dispatcher, std::weak_ptr route_config_updated_cb) override; - void validateConfig(const envoy::config::route::v3::RouteConfiguration& config) const override; private: - Rds::RdsRouteConfigProviderImpl base_; + Rds::RdsRouteConfigProviderImpl base_; // The pointer is owned by base_, here it is just stored as raw pointer to avoid downcasting. RdsRouteConfigSubscription* subscription_; RouteConfigUpdateReceiver* config_update_info_; Server::Configuration::ServerFactoryContext& factory_context_; - ProtobufMessage::ValidationVisitor& validator_; std::list config_update_callbacks_; // A flag used to determine if this instance of RdsRouteConfigProviderImpl hasn't been // deallocated. Please also see a comment in requestVirtualHostsUpdate() method implementation. std::shared_ptr still_alive_{std::make_shared(true)}; - const RouteConfigProviderManager::OptionalHttpFilters optional_http_filters_; }; using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; -class RouteConfigProviderManagerImpl - : public RouteConfigProviderManager, - public Singleton::Instance, - public Rds::RouteConfigProviderManagerImpl { +class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, + public Singleton::Instance, + public Rds::RouteConfigProviderManagerImpl { public: RouteConfigProviderManagerImpl(Server::Admin& admin); diff --git a/source/common/router/route_config_update_receiver_impl.cc b/source/common/router/route_config_update_receiver_impl.cc index e64c427e27750..b515c39139d45 100644 --- a/source/common/router/route_config_update_receiver_impl.cc +++ b/source/common/router/route_config_update_receiver_impl.cc @@ -8,23 +8,66 @@ #include "source/common/common/assert.h" #include "source/common/common/fmt.h" #include "source/common/common/thread.h" +#include "source/common/config/resource_name.h" #include "source/common/protobuf/utility.h" #include "source/common/router/config_impl.h" namespace Envoy { namespace Router { -bool RouteConfigUpdateReceiverImpl::onRdsUpdate( - const envoy::config::route::v3::RouteConfiguration& rc, const std::string& version_info) { +std::string ConfigTraitsImpl::resourceType() const { + return Envoy::Config::getResourceName(); +} + +Rds::ConfigConstSharedPtr ConfigTraitsImpl::createConfig() const { + return std::make_shared(); +} + +ProtobufTypes::MessagePtr ConfigTraitsImpl::createProto() const { + return std::make_unique(); +} + +const Protobuf::Message& ConfigTraitsImpl::validateResourceType(const Protobuf::Message& rc) const { + return dynamic_cast(rc); +} + +const Protobuf::Message& ConfigTraitsImpl::validateConfig(const Protobuf::Message& rc) const { + // TODO(lizan): consider cache the config here until onConfigUpdate. + createConfig(rc); + return rc; +} + +const std::string& ConfigTraitsImpl::resourceName(const Protobuf::Message& rc) const { + ASSERT(dynamic_cast(&rc)); + return static_cast(rc).name(); +} + +Rds::ConfigConstSharedPtr ConfigTraitsImpl::createConfig(const Protobuf::Message& rc) const { + ASSERT(dynamic_cast(&rc)); + return std::make_shared( + static_cast(rc), optional_http_filters_, + factory_context_, validator_, validate_clusters_default_); +} + +ProtobufTypes::MessagePtr ConfigTraitsImpl::cloneProto(const Protobuf::Message& rc) const { + ASSERT(dynamic_cast(&rc)); + return std::make_unique( + static_cast(rc)); +} + +bool RouteConfigUpdateReceiverImpl::onRdsUpdate(const Protobuf::Message& rc, + const std::string& version_info) { if (!base_.updateHash(rc)) { return false; } - const uint64_t new_vhds_config_hash = rc.has_vhds() ? MessageUtil::hash(rc.vhds()) : 0ul; + auto route_config_proto = std::make_unique( + static_cast(rc)); + const uint64_t new_vhds_config_hash = + route_config_proto->has_vhds() ? MessageUtil::hash(route_config_proto->vhds()) : 0ul; vhds_configuration_changed_ = new_vhds_config_hash != last_vhds_config_hash_; last_vhds_config_hash_ = new_vhds_config_hash; - initializeRdsVhosts(rc); + initializeRdsVhosts(*route_config_proto); - auto route_config_proto = std::make_unique(rc); rebuildRouteConfig(rds_virtual_hosts_, *vhds_virtual_hosts_, *route_config_proto); base_.updateConfig(std::move(route_config_proto)); @@ -108,16 +151,5 @@ void RouteConfigUpdateReceiverImpl::rebuildRouteConfig( } } -ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::ConfigFactoryImpl::createConfig( - const envoy::config::route::v3::RouteConfiguration& rc) const { - return std::make_shared( - rc, optional_http_filters_, factory_context_, - factory_context_.messageValidationContext().dynamicValidationVisitor(), false); -} - -ConfigConstSharedPtr RouteConfigUpdateReceiverImpl::ConfigFactoryImpl::createConfig() const { - return std::make_shared(); -} - } // namespace Router } // namespace Envoy diff --git a/source/common/router/route_config_update_receiver_impl.h b/source/common/router/route_config_update_receiver_impl.h index 2b0553ec3224c..eed8daf7516b1 100644 --- a/source/common/router/route_config_update_receiver_impl.h +++ b/source/common/router/route_config_update_receiver_impl.h @@ -4,6 +4,7 @@ #include "envoy/config/route/v3/route.pb.h" #include "envoy/config/route/v3/route_components.pb.h" +#include "envoy/rds/config_traits.h" #include "envoy/router/rds.h" #include "envoy/router/route_config_update_receiver.h" #include "envoy/server/factory_context.h" @@ -11,19 +12,48 @@ #include "source/common/common/logger.h" #include "source/common/protobuf/utility.h" +#include "source/common/rds/route_config_update_receiver_impl.h" #include "source/common/router/config_impl.h" -#include "source/common/router/rds/config_factory.h" -#include "source/common/router/rds/route_config_update_receiver_impl.h" namespace Envoy { namespace Router { +class ConfigTraitsImpl : public Rds::ConfigTraits { +public: + ConfigTraitsImpl(const OptionalHttpFilters& optional_http_filters, + Server::Configuration::ServerFactoryContext& factory_context, + ProtobufMessage::ValidationVisitor& validator, bool validate_clusters_default) + : optional_http_filters_(optional_http_filters), factory_context_(factory_context), + validator_(validator), validate_clusters_default_(validate_clusters_default) {} + + std::string resourceType() const override; + + Rds::ConfigConstSharedPtr createConfig() const override; + ProtobufTypes::MessagePtr createProto() const override; + + const Protobuf::Message& validateResourceType(const Protobuf::Message& rc) const override; + const Protobuf::Message& validateConfig(const Protobuf::Message& rc) const override; + + const std::string& resourceName(const Protobuf::Message& rc) const override; + + Rds::ConfigConstSharedPtr createConfig(const Protobuf::Message& rc) const override; + ProtobufTypes::MessagePtr cloneProto(const Protobuf::Message& rc) const override; + +private: + const OptionalHttpFilters optional_http_filters_; + Server::Configuration::ServerFactoryContext& factory_context_; + ProtobufMessage::ValidationVisitor& validator_; + bool validate_clusters_default_; +}; + class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { public: RouteConfigUpdateReceiverImpl(Server::Configuration::ServerFactoryContext& factory_context, const OptionalHttpFilters& optional_http_filters) - : config_factory_(factory_context, optional_http_filters), - base_(factory_context, config_factory_), last_vhds_config_hash_(0ul), + : config_traits_(optional_http_filters, factory_context, + factory_context.messageValidationContext().dynamicValidationVisitor(), + false), + base_(config_traits_, factory_context), last_vhds_config_hash_(0ul), vhds_virtual_hosts_( std::make_unique>()), vhds_configuration_changed_(true) {} @@ -40,8 +70,7 @@ class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { bool onDemandFetchFailed(const envoy::service::discovery::v3::Resource& resource) const; // Router::RouteConfigUpdateReceiver - bool onRdsUpdate(const envoy::config::route::v3::RouteConfiguration& rc, - const std::string& version_info) override; + bool onRdsUpdate(const Protobuf::Message& rc, const std::string& version_info) override; bool onVhdsUpdate(const VirtualHostRefVector& added_vhosts, const std::set& added_resource_ids, const Protobuf::RepeatedPtrField& removed_resources, @@ -49,39 +78,32 @@ class RouteConfigUpdateReceiverImpl : public RouteConfigUpdateReceiver { const std::string& routeConfigName() const override { return base_.routeConfigName(); } const std::string& configVersion() const override { return base_.configVersion(); } uint64_t configHash() const override { return base_.configHash(); } - absl::optional configInfo() const override { + absl::optional configInfo() const override { return base_.configInfo(); } bool vhdsConfigurationChanged() const override { return vhds_configuration_changed_; } - const envoy::config::route::v3::RouteConfiguration& protobufConfiguration() override { + const Protobuf::Message& protobufConfiguration() override { return base_.protobufConfiguration(); } - ConfigConstSharedPtr parsedConfiguration() const override { return base_.parsedConfiguration(); } + Rds::ConfigConstSharedPtr parsedConfiguration() const override { + return base_.parsedConfiguration(); + } SystemTime lastUpdated() const override { return base_.lastUpdated(); } const std::set& resourceIdsInLastVhdsUpdate() override { return resource_ids_in_last_update_; } + const Rds::ConfigTraits& configTraits() const override { return config_traits_; } + const envoy::config::route::v3::RouteConfiguration& protobufConfigurationCast() override { + ASSERT(dynamic_cast( + &base_.protobufConfiguration())); + return static_cast( + base_.protobufConfiguration()); + } private: - class ConfigFactoryImpl - : public Rds::ConfigFactory { - public: - ConfigFactoryImpl(Server::Configuration::ServerFactoryContext& factory_context, - const OptionalHttpFilters& optional_http_filters) - : factory_context_(factory_context), optional_http_filters_(optional_http_filters) {} - - // Rds::ConfigFactory - ConfigConstSharedPtr - createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const override; - ConfigConstSharedPtr createConfig() const override; - - private: - Server::Configuration::ServerFactoryContext& factory_context_; - const OptionalHttpFilters optional_http_filters_; - }; - ConfigFactoryImpl config_factory_; - - Rds::RouteConfigUpdateReceiverImpl base_; + ConfigTraitsImpl config_traits_; + + Rds::RouteConfigUpdateReceiverImpl base_; uint64_t last_vhds_config_hash_; std::map rds_virtual_hosts_; diff --git a/source/common/router/scoped_rds.cc b/source/common/router/scoped_rds.cc index de3e5832130ac..c18e6ee3c258c 100644 --- a/source/common/router/scoped_rds.cc +++ b/source/common/router/scoped_rds.cc @@ -103,7 +103,7 @@ makeScopedRouteInfos(ProtobufTypes::ConstMessagePtrVector&& config_protos, scoped_route_config.route_configuration(), optional_http_filters, factory_context, factory_context.messageValidationContext().staticValidationVisitor()); scopes.push_back(std::make_shared(scoped_route_config, - route_config_provider->config())); + route_config_provider->configCast())); } return scopes; @@ -230,7 +230,7 @@ void ScopedRdsConfigSubscription::RdsRouteConfigProviderHelper::initRdsConfigPro rds_update_callback_handle_ = route_provider_->subscription().addUpdateCallback([this]() { // Subscribe to RDS update. - parent_.onRdsConfigUpdate(scope_name_, route_provider_->config()); + parent_.onRdsConfigUpdate(scope_name_, route_provider_->configCast()); }); parent_.stats_.active_scopes_.inc(); } @@ -263,7 +263,7 @@ void ScopedRdsConfigSubscription::RdsRouteConfigProviderHelper::maybeInitRdsConf return; } // If RouteConfiguration has been initialized, apply update to all the threads. - parent_.onRdsConfigUpdate(scope_name_, route_provider_->config()); + parent_.onRdsConfigUpdate(scope_name_, route_provider_->configCast()); } bool ScopedRdsConfigSubscription::addOrUpdateScopes( diff --git a/source/common/router/scoped_rds.h b/source/common/router/scoped_rds.h index eb53c8b57fe89..2b542ff403ffe 100644 --- a/source/common/router/scoped_rds.h +++ b/source/common/router/scoped_rds.h @@ -153,7 +153,7 @@ class ScopedRdsConfigSubscription parent_.stats_.on_demand_scopes_.dec(); } } - ConfigConstSharedPtr routeConfig() { return route_provider_->config(); } + ConfigConstSharedPtr routeConfig() { return route_provider_->configCast(); } void addOnDemandUpdateCallback(std::function callback); diff --git a/source/common/router/vhds.cc b/source/common/router/vhds.cc index 859674b1b6c84..5791dbd0431ee 100644 --- a/source/common/router/vhds.cc +++ b/source/common/router/vhds.cc @@ -33,7 +33,7 @@ VhdsSubscription::VhdsSubscription(RouteConfigUpdateReceiver* config_update_info init_target_(fmt::format("VhdsConfigSubscription {}", config_update_info_->routeConfigName()), [this]() { subscription_->start({config_update_info_->routeConfigName()}); }), route_config_provider_opt_(route_config_provider_opt) { - const auto& config_source = config_update_info_->protobufConfiguration() + const auto& config_source = config_update_info_->protobufConfigurationCast() .vhds() .config_source() .api_config_source() @@ -46,7 +46,7 @@ VhdsSubscription::VhdsSubscription(RouteConfigUpdateReceiver* config_update_info options.use_namespace_matching_ = true; subscription_ = factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource( - config_update_info_->protobufConfiguration().vhds().config_source(), + config_update_info_->protobufConfigurationCast().vhds().config_source(), Grpc::Common::typeUrl(resource_name), *scope_, *this, resource_decoder_, options); } diff --git a/source/extensions/filters/network/thrift_proxy/config.h b/source/extensions/filters/network/thrift_proxy/config.h index d41d26571595a..51fbebb60edec 100644 --- a/source/extensions/filters/network/thrift_proxy/config.h +++ b/source/extensions/filters/network/thrift_proxy/config.h @@ -75,7 +75,8 @@ class ConfigImpl : public Config, // Router::Config Router::RouteConstSharedPtr route(const MessageMetadata& metadata, uint64_t random_value) const override { - return route_config_provider_->config()->route(metadata, random_value); + auto config = std::static_pointer_cast(route_config_provider_->config()); + return config->route(metadata, random_value); } // Config @@ -96,7 +97,7 @@ class ConfigImpl : public Config, ThriftFilterStats stats_; const TransportType transport_; const ProtocolType proto_; - Router::RouteConfigProviderSharedPtr route_config_provider_; + Rds::RouteConfigProviderSharedPtr route_config_provider_; std::list filter_factories_; const bool payload_passthrough_; diff --git a/source/extensions/filters/network/thrift_proxy/router/BUILD b/source/extensions/filters/network/thrift_proxy/router/BUILD index 570983c018afe..5f53da78bd371 100644 --- a/source/extensions/filters/network/thrift_proxy/router/BUILD +++ b/source/extensions/filters/network/thrift_proxy/router/BUILD @@ -27,6 +27,7 @@ envoy_cc_library( hdrs = ["router.h"], external_deps = ["abseil_optional"], deps = [ + "//envoy/rds:rds_interface", "//envoy/router:router_interface", "//envoy/tcp:conn_pool_interface", "//source/common/buffer:buffer_lib", @@ -133,7 +134,7 @@ envoy_cc_library( hdrs = ["rds.h"], deps = [ ":router_interface", - "//envoy/router:rds_template_interface", + "//envoy/rds:rds_interface", "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", ], ) @@ -149,8 +150,8 @@ envoy_cc_library( deps = [ ":config", ":rds_interface", - "//envoy/router:rds_template_interface", - "//source/common/router:rds_template_lib", + "//envoy/rds:rds_interface", + "//source/common/rds:rds_lib", "@envoy_api//envoy/extensions/filters/network/thrift_proxy/v3:pkg_cc_proto", ], ) diff --git a/source/extensions/filters/network/thrift_proxy/router/rds.h b/source/extensions/filters/network/thrift_proxy/router/rds.h index f0b27137dd4af..a34d23b4216ee 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds.h +++ b/source/extensions/filters/network/thrift_proxy/router/rds.h @@ -5,7 +5,7 @@ #include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" #include "envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.pb.h" #include "envoy/init/manager.h" -#include "envoy/router/rds/route_config_provider.h" +#include "envoy/rds/route_config_provider.h" #include "envoy/server/factory_context.h" #include "source/extensions/filters/network/thrift_proxy/router/router.h" @@ -16,12 +16,6 @@ namespace NetworkFilters { namespace ThriftProxy { namespace Router { -using RouteConfigProvider = Envoy::Router::Rds::RouteConfigProvider< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; - -using RouteConfigProviderPtr = std::unique_ptr; -using RouteConfigProviderSharedPtr = std::shared_ptr; - /** * The RouteConfigProviderManager exposes the ability to get a RouteConfigProvider. This interface * is exposed to the Server's FactoryContext in order to allow HttpConnectionManagers to get @@ -44,7 +38,7 @@ class RouteConfigProviderManager { * @param init_manager the Init::Manager used to coordinate initialization of a the underlying RDS * subscription. */ - virtual RouteConfigProviderSharedPtr createRdsRouteConfigProvider( + virtual Rds::RouteConfigProviderSharedPtr createRdsRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::Trds& trds, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, Init::Manager& init_manager) PURE; @@ -57,7 +51,7 @@ class RouteConfigProviderManager { * @param factory_context is the context to use for the route config provider. * @param validator is the message validator for route config. */ - virtual RouteConfigProviderPtr createStaticRouteConfigProvider( + virtual Rds::RouteConfigProviderPtr createStaticRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, Server::Configuration::ServerFactoryContext& factory_context) PURE; }; diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc index f096c3dd6bade..ba59031ab1b46 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc @@ -5,12 +5,14 @@ #include #include -#include "envoy/router/rds/route_config_update_receiver.h" - -#include "source/common/router/rds/rds_route_config_provider_impl.h" -#include "source/common/router/rds/rds_route_config_subscription.h" -#include "source/common/router/rds/route_config_update_receiver_impl.h" -#include "source/common/router/rds/static_route_config_provider_impl.h" +#include "envoy/rds/route_config_update_receiver.h" + +#include "source/common/config/opaque_resource_decoder_impl.h" +#include "source/common/config/resource_name.h" +#include "source/common/rds/rds_route_config_provider_impl.h" +#include "source/common/rds/rds_route_config_subscription.h" +#include "source/common/rds/route_config_update_receiver_impl.h" +#include "source/common/rds/static_route_config_provider_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/config.h" namespace Envoy { @@ -19,27 +21,52 @@ namespace NetworkFilters { namespace ThriftProxy { namespace Router { -using RouteConfigUpdatePtr = std::unique_ptr>; -using RouteConfigUpdateReceiverImpl = Envoy::Router::Rds::RouteConfigUpdateReceiverImpl< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; +std::string ConfigTraitsImpl::resourceType() const { + return Envoy::Config::getResourceName< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(); +} + +Rds::ConfigConstSharedPtr ConfigTraitsImpl::createConfig() const { + return std::make_shared(); +} + +ProtobufTypes::MessagePtr ConfigTraitsImpl::createProto() const { + return std::make_unique< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>(); +} + +const Protobuf::Message& ConfigTraitsImpl::validateResourceType(const Protobuf::Message& rc) const { + return dynamic_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>(rc); +} + +const Protobuf::Message& ConfigTraitsImpl::validateConfig(const Protobuf::Message& rc) const { + return rc; +} -using RdsRouteConfigSubscription = Envoy::Router::Rds::RdsRouteConfigSubscription< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; -using RdsRouteConfigSubscriptionSharedPtr = std::shared_ptr; +const std::string& ConfigTraitsImpl::resourceName(const Protobuf::Message& rc) const { + return static_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>(rc) + .name(); +} -using StaticRouteConfigProviderImpl = Envoy::Router::Rds::StaticRouteConfigProviderImpl< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; -using RdsRouteConfigProviderImpl = Envoy::Router::Rds::RdsRouteConfigProviderImpl< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; -using RdsRouteConfigProviderImplSharedPtr = std::shared_ptr; +Rds::ConfigConstSharedPtr ConfigTraitsImpl::createConfig(const Protobuf::Message& rc) const { + return std::make_shared( + static_cast( + rc)); +} + +ProtobufTypes::MessagePtr ConfigTraitsImpl::cloneProto(const Protobuf::Message& rc) const { + return std::make_unique< + envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>( + static_cast( + rc)); +} RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(Server::Admin& admin) - : Envoy::Router::Rds::RouteConfigProviderManagerImpl< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>( - admin) {} + : Rds::RouteConfigProviderManagerImpl(admin) {} -RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( +Rds::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::Trds& trds, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, Init::Manager& init_manager) { @@ -49,44 +76,33 @@ RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfi auto existing_provider = reuseDynamicProvider(manager_identifier, init_manager, trds.route_config_name()); - if (!existing_provider) { - // std::make_shared does not work for classes with private constructors. There are ways - // around it. However, since this is not a performance critical path we err on the side - // of simplicity. - - RouteConfigUpdatePtr config_update(new RouteConfigUpdateReceiverImpl(factory_context, *this)); - RdsRouteConfigSubscriptionSharedPtr subscription(new RdsRouteConfigSubscription( - std::move(config_update), trds.config_source(), trds.route_config_name(), - manager_identifier, factory_context, stat_prefix, *this)); - RdsRouteConfigProviderImplSharedPtr new_provider{ - new RdsRouteConfigProviderImpl(std::move(subscription), factory_context)}; - insertDynamicProvider(manager_identifier, new_provider, - &new_provider->subscription().initTarget(), init_manager); - return new_provider; - } else { + if (existing_provider) { return existing_provider; } + auto config_update = + std::make_unique(config_traits_, factory_context); + auto resource_decoder = std::make_unique>( + factory_context.messageValidationContext().dynamicValidationVisitor(), "name"); + auto subscription = std::make_shared( + std::move(config_update), std::move(resource_decoder), trds.config_source(), + trds.route_config_name(), manager_identifier, factory_context, stat_prefix, *this); + auto new_provider = + std::make_shared(std::move(subscription), factory_context); + insertDynamicProvider(manager_identifier, new_provider, + &new_provider->subscription().initTarget(), init_manager); + return new_provider; } -RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigProvider( +Rds::RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, Server::Configuration::ServerFactoryContext& factory_context) { - auto initial_config = createConfig(route_config); - auto provider = std::make_unique(initial_config, route_config, - factory_context, *this); + auto provider = std::make_unique(route_config, config_traits_, + factory_context, *this); insertStaticProvider(provider.get()); return provider; } -std::shared_ptr RouteConfigProviderManagerImpl::createConfig( - const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc) const { - return std::make_shared(rc); -} - -std::shared_ptr RouteConfigProviderManagerImpl::createConfig() const { - return std::make_shared(); -} - } // namespace Router } // namespace ThriftProxy } // namespace NetworkFilters diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h index 623a9c108a5c4..6e41289ca7b61 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.h +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.h @@ -4,10 +4,10 @@ #include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.h" #include "envoy/extensions/filters/network/thrift_proxy/v3/route.pb.validate.h" +#include "envoy/rds/config_traits.h" #include "envoy/singleton/instance.h" -#include "source/common/router/rds/config_factory.h" -#include "source/common/router/rds/route_config_provider_manager_impl.h" +#include "source/common/rds/route_config_provider_manager_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/rds.h" #include "source/extensions/filters/network/thrift_proxy/router/router.h" @@ -17,31 +17,40 @@ namespace NetworkFilters { namespace ThriftProxy { namespace Router { -class RouteConfigProviderManagerImpl - : public RouteConfigProviderManager, - public Singleton::Instance, - public Envoy::Router::Rds::RouteConfigProviderManagerImpl< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>, - public Envoy::Router::Rds::ConfigFactory< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config> { +class ConfigTraitsImpl : public Rds::ConfigTraits { +public: + std::string resourceType() const override; + + Rds::ConfigConstSharedPtr createConfig() const override; + ProtobufTypes::MessagePtr createProto() const override; + + const Protobuf::Message& validateResourceType(const Protobuf::Message& rc) const override; + const Protobuf::Message& validateConfig(const Protobuf::Message& rc) const override; + + const std::string& resourceName(const Protobuf::Message& rc) const override; + + Rds::ConfigConstSharedPtr createConfig(const Protobuf::Message& rc) const override; + ProtobufTypes::MessagePtr cloneProto(const Protobuf::Message& rc) const override; +}; + +class RouteConfigProviderManagerImpl : public RouteConfigProviderManager, + public Singleton::Instance, + public Rds::RouteConfigProviderManagerImpl { public: RouteConfigProviderManagerImpl(Server::Admin& admin); // RouteConfigProviderManager - RouteConfigProviderSharedPtr createRdsRouteConfigProvider( + Rds::RouteConfigProviderSharedPtr createRdsRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::Trds& trds, Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix, Init::Manager& init_manager) override; - RouteConfigProviderPtr createStaticRouteConfigProvider( + Rds::RouteConfigProviderPtr createStaticRouteConfigProvider( const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& route_config, Server::Configuration::ServerFactoryContext& factory_context) override; private: - std::shared_ptr - createConfig(const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration& rc) - const override; - std::shared_ptr createConfig() const override; + ConfigTraitsImpl config_traits_; }; using RouteConfigProviderManagerImplPtr = std::unique_ptr; diff --git a/source/extensions/filters/network/thrift_proxy/router/router.h b/source/extensions/filters/network/thrift_proxy/router/router.h index e7df1eb074d52..d74e0804f28d2 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router.h +++ b/source/extensions/filters/network/thrift_proxy/router/router.h @@ -6,6 +6,7 @@ #include "envoy/buffer/buffer.h" #include "envoy/local_info/local_info.h" +#include "envoy/rds/config.h" #include "envoy/router/router.h" #include "envoy/tcp/conn_pool.h" @@ -85,7 +86,7 @@ using RouteConstSharedPtr = std::shared_ptr; /** * The router configuration. */ -class Config { +class Config : public Rds::Config { public: virtual ~Config() = default; diff --git a/source/server/admin/admin.h b/source/server/admin/admin.h index e99330c2c8fc7..67e04f7b72ab7 100644 --- a/source/server/admin/admin.h +++ b/source/server/admin/admin.h @@ -226,11 +226,11 @@ class AdminImpl : public Admin, NullRouteConfigProvider(TimeSource& time_source); // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override { return config_; } + Rds::ConfigConstSharedPtr config() override { return config_; } absl::optional configInfo() const override { return {}; } SystemTime lastUpdated() const override { return time_source_.systemTime(); } void onConfigUpdate() override {} - void validateConfig(const envoy::config::route::v3::RouteConfiguration&) const override {} + Router::ConfigConstSharedPtr configCast() override { return config_; } void requestVirtualHostsUpdate(const std::string&, Event::Dispatcher&, std::weak_ptr) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; diff --git a/test/common/router/rds_impl_test.cc b/test/common/router/rds_impl_test.cc index f34ca44aa38a0..c2da1deeafe41 100644 --- a/test/common/router/rds_impl_test.cc +++ b/test/common/router/rds_impl_test.cc @@ -122,7 +122,7 @@ stat_prefix: foo RouteConstSharedPtr route(Http::TestRequestHeaderMapImpl headers) { NiceMock stream_info; headers.addCopy("x-forwarded-proto", "http"); - return rds_->config()->route(headers, stream_info, 0); + return rds_->configCast()->route(headers, stream_info, 0); } NiceMock server_; @@ -246,7 +246,7 @@ TEST_F(RdsImplTest, Basic) { // Load the config and verified shared count. // ConfigConstSharedPtr is shared between: RouteConfigUpdateReceiverImpl, rds_ (via tls_), and // config local var below. - ConfigConstSharedPtr config = rds_->config(); + ConfigConstSharedPtr config = rds_->configCast(); EXPECT_EQ(3, config.use_count()); // Third request. @@ -612,7 +612,7 @@ TEST_F(RdsImplTest, VHDSandRDSupdateTogether) { EXPECT_CALL(init_watcher_, ready()); rds_callbacks_->onConfigUpdate(decoded_resources.refvec_, response1.version_info()); - EXPECT_TRUE(rds_->config()->usesVhds()); + EXPECT_TRUE(rds_->configCast()->usesVhds()); EXPECT_EQ("foo", route(Http::TestRequestHeaderMapImpl{{":authority", "foo"}, {":path", "/foo"}}) ->routeEntry() @@ -673,8 +673,7 @@ TEST_F(RdsImplTest, RdsRouteConfigProviderImplSubscriptionSetup) { EXPECT_CALL(init_watcher_, ready()); RdsRouteConfigSubscription& subscription = dynamic_cast(*rds_).subscription(); - Rds::RdsRouteConfigSubscription& base = - subscription; + Rds::RdsRouteConfigSubscription& base = subscription; EXPECT_NE(static_cast(&subscription.routeConfigProvider()), static_cast(&base.routeConfigProvider())); EXPECT_EQ(rds_.get(), subscription.routeConfigProvider().value()); diff --git a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc index 051f071af73b5..ad027f4b2bf36 100644 --- a/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc +++ b/test/extensions/filters/network/thrift_proxy/rds_impl_test.cc @@ -11,7 +11,7 @@ #include "source/common/config/utility.h" #include "source/common/json/json_loader.h" -#include "source/common/router/rds/rds_route_config_provider_impl.h" +#include "source/common/rds/rds_route_config_provider_impl.h" #include "source/extensions/filters/network/thrift_proxy/router/rds_impl.h" #include "test/mocks/init/mocks.h" @@ -72,9 +72,6 @@ class RdsTestBase : public testing::Test { NiceMock scope_; }; -using RdsRouteConfigProviderImpl = Envoy::Router::Rds::RdsRouteConfigProviderImpl< - envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration, Config>; - class RouteConfigProviderManagerImplTest : public RdsTestBase { public: void setup() { @@ -98,7 +95,7 @@ class RouteConfigProviderManagerImplTest : public RdsTestBase { envoy::extensions::filters::network::thrift_proxy::v3::Trds rds_; RouteConfigProviderManagerImplPtr route_config_provider_manager_; - RouteConfigProviderSharedPtr provider_; + Rds::RouteConfigProviderSharedPtr provider_; }; envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration @@ -138,7 +135,7 @@ name: foo // Only static route. server_factory_context_.cluster_manager_.initializeClusters({"baz"}, {}); - RouteConfigProviderPtr static_config = + Rds::RouteConfigProviderPtr static_config = route_config_provider_manager_->createStaticRouteConfigProvider( parseRouteConfigurationFromV3Yaml(config_yaml), server_factory_context_); message_ptr = server_factory_context_.admin_.config_tracker_.config_tracker_callbacks_["routes"]( @@ -284,7 +281,7 @@ name: foo_route_config server_factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( decoded_resources.refvec_, "1"); - RouteConfigProviderSharedPtr provider2 = + Rds::RouteConfigProviderSharedPtr provider2 = route_config_provider_manager_->createRdsRouteConfigProvider( rds_, server_factory_context_, "foo_prefix", outer_init_manager_); @@ -294,14 +291,14 @@ name: foo_route_config EXPECT_EQ(provider_, provider2) << "fail to obtain the same rds config provider object"; // So this means that both provider have same subscription. - EXPECT_EQ(&dynamic_cast(*provider_).subscription(), - &dynamic_cast(*provider2).subscription()); + EXPECT_EQ(&dynamic_cast(*provider_).subscription(), + &dynamic_cast(*provider2).subscription()); EXPECT_EQ(&provider_->configInfo().value().config_, &provider2->configInfo().value().config_); envoy::extensions::filters::network::thrift_proxy::v3::Trds rds2; rds2.set_route_config_name("foo_route_config"); rds2.mutable_config_source()->set_path("bar_path"); - RouteConfigProviderSharedPtr provider3 = + Rds::RouteConfigProviderSharedPtr provider3 = route_config_provider_manager_->createRdsRouteConfigProvider( rds2, server_factory_context_, "foo_prefix", outer_init_manager_); EXPECT_NE(provider3, provider_); @@ -344,7 +341,7 @@ TEST_F(RouteConfigProviderManagerImplTest, SameProviderOnTwoInitManager) { Init::WatcherImpl real_watcher("real", []() {}); Init::ManagerImpl real_init_manager("real"); - RouteConfigProviderSharedPtr provider2 = + Rds::RouteConfigProviderSharedPtr provider2 = route_config_provider_manager_->createRdsRouteConfigProvider(rds_, mock_factory_context2, "foo_prefix", real_init_manager); diff --git a/test/mocks/router/mocks.h b/test/mocks/router/mocks.h index e9ccd1de05a2e..8c08a46390f03 100644 --- a/test/mocks/router/mocks.h +++ b/test/mocks/router/mocks.h @@ -502,11 +502,11 @@ class MockRouteConfigProvider : public RouteConfigProvider { MockRouteConfigProvider(); ~MockRouteConfigProvider() override; - MOCK_METHOD(ConfigConstSharedPtr, config, ()); + MOCK_METHOD(Rds::ConfigConstSharedPtr, config, ()); MOCK_METHOD(absl::optional, configInfo, (), (const)); MOCK_METHOD(SystemTime, lastUpdated, (), (const)); MOCK_METHOD(void, onConfigUpdate, ()); - MOCK_METHOD(void, validateConfig, (const envoy::config::route::v3::RouteConfiguration&), (const)); + MOCK_METHOD(ConfigConstSharedPtr, configCast, ()); MOCK_METHOD(void, requestVirtualHostsUpdate, (const std::string&, Event::Dispatcher&, std::weak_ptr route_config_updated_cb)); From 22d91c77c2f4b468897649f3c67bc72c3bcde568 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 28 Oct 2021 23:23:27 +0800 Subject: [PATCH 27/31] Fix CI issues. Signed-off-by: Tamas Kovacs --- .../thrift_proxy/v3/thrift_proxy.proto | 3 +- envoy/rds/config_traits.h | 30 ++++++++- .../network/thrift_proxy/router/rds_impl.cc | 6 ++ test/common/rds/BUILD | 19 ++++++ .../rds_template_test.cc => rds/rds_test.cc} | 62 +++++++++++-------- test/common/router/BUILD | 10 --- test/common/router/vhds_test.cc | 20 +++--- 7 files changed, 102 insertions(+), 48 deletions(-) create mode 100644 test/common/rds/BUILD rename test/common/{router/rds_template_test.cc => rds/rds_test.cc} (64%) diff --git a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto index c044766886e81..c7e8161f82fb7 100644 --- a/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto +++ b/api/envoy/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto @@ -65,8 +65,7 @@ message Trds { config.core.v3.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; // The name of the route configuration. This allows to use different route - // configurations. Tells which route config should be fetched - // from the configuration source. + // configurations. Tells which route configuration should be fetched from the configuration source. string route_config_name = 2; } diff --git a/envoy/rds/config_traits.h b/envoy/rds/config_traits.h index 0c91eb8c60ee0..a703faeeb6b26 100644 --- a/envoy/rds/config_traits.h +++ b/envoy/rds/config_traits.h @@ -12,12 +12,18 @@ namespace Envoy { namespace Rds { /** - * Traits of route configuration and proto. + * Traits of the protocol specific route configuration and proto. + * The generic rds classes will call the methods of this interface + * to get information which are not visible for them directly. */ class ConfigTraits { public: virtual ~ConfigTraits() = default; + /** + * Give the full name of the route configuration proto description. + * For example 'envoy.config.route.v3.RouteConfiguration' + */ virtual std::string resourceType() const PURE; /** @@ -26,11 +32,30 @@ class ConfigTraits { */ virtual ConfigConstSharedPtr createConfig() const PURE; + /** + * Create an empty route configuration proto object. + */ virtual ProtobufTypes::MessagePtr createProto() const PURE; + /** + * Runtime check if the provided proto message object is really a route configuration instance. + * Throw an std::bad_cast exception if not. + * Every other method below this assumes the proto message is already + * validated and and doesn't do any further runtime check. + */ virtual const Protobuf::Message& validateResourceType(const Protobuf::Message& rc) const PURE; + + /** + * Check if a valid config object can be made based on the provided route configuration proto. + * Throw an exception if not. + */ virtual const Protobuf::Message& validateConfig(const Protobuf::Message& rc) const PURE; + /** + * Gives back the value of the name field Check if a valid config object can be made + * based on the provided route configuration proto. + * The object behind the returned reference has to have the same lifetime like the proto. + */ virtual const std::string& resourceName(const Protobuf::Message& rc) const PURE; /** @@ -38,6 +63,9 @@ class ConfigTraits { */ virtual ConfigConstSharedPtr createConfig(const Protobuf::Message& rc) const PURE; + /** + * Clones the route configuration proto. + */ virtual ProtobufTypes::MessagePtr cloneProto(const Protobuf::Message& rc) const PURE; }; diff --git a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc index ba59031ab1b46..e1df12b2a0f00 100644 --- a/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/rds_impl.cc @@ -45,18 +45,24 @@ const Protobuf::Message& ConfigTraitsImpl::validateConfig(const Protobuf::Messag } const std::string& ConfigTraitsImpl::resourceName(const Protobuf::Message& rc) const { + ASSERT(dynamic_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration*>(&rc)); return static_cast< const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration&>(rc) .name(); } Rds::ConfigConstSharedPtr ConfigTraitsImpl::createConfig(const Protobuf::Message& rc) const { + ASSERT(dynamic_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration*>(&rc)); return std::make_shared( static_cast( rc)); } ProtobufTypes::MessagePtr ConfigTraitsImpl::cloneProto(const Protobuf::Message& rc) const { + ASSERT(dynamic_cast< + const envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration*>(&rc)); return std::make_unique< envoy::extensions::filters::network::thrift_proxy::v3::RouteConfiguration>( static_cast( diff --git a/test/common/rds/BUILD b/test/common/rds/BUILD new file mode 100644 index 0000000000000..e12ec953362ac --- /dev/null +++ b/test/common/rds/BUILD @@ -0,0 +1,19 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_test( + name = "rds_test", + srcs = ["rds_test.cc"], + deps = [ + "//source/common/rds:rds_lib", + "//test/mocks/server:instance_mocks", + "@envoy_api//envoy/config/route/v3:pkg_cc_proto", + ], +) diff --git a/test/common/router/rds_template_test.cc b/test/common/rds/rds_test.cc similarity index 64% rename from test/common/router/rds_template_test.cc rename to test/common/rds/rds_test.cc index de9d62ac027e3..2f987aa6ee898 100644 --- a/test/common/router/rds_template_test.cc +++ b/test/common/rds/rds_test.cc @@ -6,7 +6,7 @@ #include "envoy/stats/scope.h" #include "source/common/config/utility.h" -#include "source/common/router/rds/route_config_update_receiver_impl.h" +#include "source/common/rds/route_config_update_receiver_impl.h" #include "test/mocks/protobuf/mocks.h" #include "test/mocks/server/instance.h" @@ -18,7 +18,7 @@ using testing::ReturnRef; namespace Envoy { -namespace Router { +namespace Rds { namespace { class RdsTestBase : public testing::Test { @@ -37,10 +37,10 @@ class RdsTestBase : public testing::Test { NiceMock scope_; }; -class Config { +class TestConfig : public Config { public: - Config() = default; - Config(const envoy::config::route::v3::RouteConfiguration& rc) : rc_(rc) {} + TestConfig() = default; + TestConfig(const envoy::config::route::v3::RouteConfiguration& rc) : rc_(rc) {} const std::string* route(const std::string& name) const { for (const auto& virtual_host_config : rc_.virtual_hosts()) { if (virtual_host_config.name() == name) { @@ -54,45 +54,57 @@ class Config { envoy::config::route::v3::RouteConfiguration rc_; }; -class ConfigFactory - : public Rds::ConfigFactory { +class TestConfigTraits : public ConfigTraits { public: - std::shared_ptr - createConfig(const envoy::config::route::v3::RouteConfiguration& rc) const override { - return std::make_shared(rc); + const envoy::config::route::v3::RouteConfiguration& cast(const Protobuf::Message& rc) const { + return static_cast(rc); } - std::shared_ptr createConfig() const override { - return std::make_shared(); + + std::string resourceType() const override { return "test"; } + ConfigConstSharedPtr createConfig() const override { + return std::make_shared(); + } + ProtobufTypes::MessagePtr createProto() const override { + return std::make_unique(); + } + const Protobuf::Message& validateResourceType(const Protobuf::Message& rc) const override { + return rc; + } + const Protobuf::Message& validateConfig(const Protobuf::Message& rc) const override { return rc; } + const std::string& resourceName(const Protobuf::Message& rc) const override { + return cast(rc).name(); + } + ConfigConstSharedPtr createConfig(const Protobuf::Message& rc) const override { + return std::make_shared(cast(rc)); + } + ProtobufTypes::MessagePtr cloneProto(const Protobuf::Message& rc) const override { + return std::make_unique(cast(rc)); } }; -using RouteConfigUpdatePtr = std::unique_ptr< - Rds::RouteConfigUpdateReceiver>; -using RouteConfigUpdateReceiverImpl = - Rds::RouteConfigUpdateReceiverImpl; - -class RdsImplTest : public RdsTestBase { +class RdsTest : public RdsTestBase { public: - ~RdsImplTest() override { server_factory_context_.thread_local_.shutdownThread(); } + ~RdsTest() override { server_factory_context_.thread_local_.shutdownThread(); } void setup() { config_update_ = - std::make_unique(server_factory_context_, config_factory_); + std::make_unique(config_traits_, server_factory_context_); } const std::string* route(const std::string& path) { - return config_update_->parsedConfiguration()->route(path); + return std::static_pointer_cast(config_update_->parsedConfiguration()) + ->route(path); } - ConfigFactory config_factory_; + TestConfigTraits config_traits_; RouteConfigUpdatePtr config_update_; }; -TEST_F(RdsImplTest, Basic) { +TEST_F(RdsTest, Basic) { setup(); EXPECT_TRUE(config_update_->parsedConfiguration()); - EXPECT_EQ(nullptr, config_update_->parsedConfiguration()->route("foo")); + EXPECT_EQ(nullptr, route("foo")); EXPECT_FALSE(config_update_->configInfo().has_value()); const std::string response1_json = R"EOF( @@ -152,5 +164,5 @@ TEST_F(RdsImplTest, Basic) { } } // namespace -} // namespace Router +} // namespace Rds } // namespace Envoy diff --git a/test/common/router/BUILD b/test/common/router/BUILD index c381a063e0435..596a8a86e7a3f 100644 --- a/test/common/router/BUILD +++ b/test/common/router/BUILD @@ -114,16 +114,6 @@ envoy_cc_test( ], ) -envoy_cc_test( - name = "rds_template_test", - srcs = ["rds_template_test.cc"], - deps = [ - "//source/common/router:rds_template_lib", - "//test/mocks/server:instance_mocks", - "@envoy_api//envoy/config/route/v3:pkg_cc_proto", - ], -) - envoy_cc_test( name = "scoped_config_impl_test", srcs = ["scoped_config_impl_test.cc"], diff --git a/test/common/router/vhds_test.cc b/test/common/router/vhds_test.cc index e23a6cdb4caec..078fa74602c5e 100644 --- a/test/common/router/vhds_test.cc +++ b/test/common/router/vhds_test.cc @@ -127,7 +127,7 @@ TEST_F(VhdsTest, VhdsAddsVirtualHosts) { RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config); VhdsSubscription subscription(config_update_info.get(), factory_context_, context_, provider_); - EXPECT_EQ(0UL, config_update_info->protobufConfiguration().virtual_hosts_size()); + EXPECT_EQ(0UL, config_update_info->protobufConfigurationCast().virtual_hosts_size()); auto vhost = buildVirtualHost("vhost1", "vhost.first"); const auto& added_resources = buildAddedResources({vhost}); @@ -137,9 +137,9 @@ TEST_F(VhdsTest, VhdsAddsVirtualHosts) { factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( decoded_resources.refvec_, removed_resources, "1"); - EXPECT_EQ(1UL, config_update_info->protobufConfiguration().virtual_hosts_size()); + EXPECT_EQ(1UL, config_update_info->protobufConfigurationCast().virtual_hosts_size()); EXPECT_TRUE(messageDifferencer_.Equals( - vhost, config_update_info->protobufConfiguration().virtual_hosts(0))); + vhost, config_update_info->protobufConfigurationCast().virtual_hosts(0))); } // verify that an RDS update of virtual hosts leaves VHDS virtual hosts intact @@ -186,8 +186,8 @@ name: my_route RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config); VhdsSubscription subscription(config_update_info.get(), factory_context_, context_, provider_); - EXPECT_EQ(1UL, config_update_info->protobufConfiguration().virtual_hosts_size()); - EXPECT_EQ("vhost_rds1", config_update_info->protobufConfiguration().virtual_hosts(0).name()); + EXPECT_EQ(1UL, config_update_info->protobufConfigurationCast().virtual_hosts_size()); + EXPECT_EQ("vhost_rds1", config_update_info->protobufConfigurationCast().virtual_hosts(0).name()); auto vhost = buildVirtualHost("vhost_vhds1", "vhost.first"); const auto& added_resources = buildAddedResources({vhost}); @@ -196,14 +196,14 @@ name: my_route const Protobuf::RepeatedPtrField removed_resources; factory_context_.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( decoded_resources.refvec_, removed_resources, "1"); - EXPECT_EQ(2UL, config_update_info->protobufConfiguration().virtual_hosts_size()); + EXPECT_EQ(2UL, config_update_info->protobufConfigurationCast().virtual_hosts_size()); config_update_info->onRdsUpdate(updated_route_config, "2"); - EXPECT_EQ(3UL, config_update_info->protobufConfiguration().virtual_hosts_size()); - auto actual_vhost_0 = config_update_info->protobufConfiguration().virtual_hosts(0); - auto actual_vhost_1 = config_update_info->protobufConfiguration().virtual_hosts(1); - auto actual_vhost_2 = config_update_info->protobufConfiguration().virtual_hosts(2); + EXPECT_EQ(3UL, config_update_info->protobufConfigurationCast().virtual_hosts_size()); + auto actual_vhost_0 = config_update_info->protobufConfigurationCast().virtual_hosts(0); + auto actual_vhost_1 = config_update_info->protobufConfigurationCast().virtual_hosts(1); + auto actual_vhost_2 = config_update_info->protobufConfigurationCast().virtual_hosts(2); EXPECT_TRUE("vhost_rds1" == actual_vhost_0.name() || "vhost_rds1" == actual_vhost_1.name() || "vhost_rds1" == actual_vhost_2.name()); EXPECT_TRUE("vhost_rds2" == actual_vhost_0.name() || "vhost_rds2" == actual_vhost_1.name() || From 54090b22f585745ad5c64ebd944909043a74a985 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Fri, 29 Oct 2021 22:56:50 +0800 Subject: [PATCH 28/31] Fix CI issues. Signed-off-by: Tamas Kovacs --- test/common/http/conn_manager_impl_test_base.h | 13 ------------- test/mocks/router/mocks.cc | 1 + 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/test/common/http/conn_manager_impl_test_base.h b/test/common/http/conn_manager_impl_test_base.h index 6225b61d854d2..3c50a650e1169 100644 --- a/test/common/http/conn_manager_impl_test_base.h +++ b/test/common/http/conn_manager_impl_test_base.h @@ -28,19 +28,6 @@ namespace Http { class HttpConnectionManagerImplTest : public testing::Test, public ConnectionManagerConfig { public: - struct RouteConfigProvider : public Router::RouteConfigProvider { - RouteConfigProvider(TimeSource& time_source) : time_source_(time_source) {} - - // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override { return route_config_; } - absl::optional configInfo() const override { return {}; } - SystemTime lastUpdated() const override { return time_source_.systemTime(); } - void onConfigUpdate() override {} - - TimeSource& time_source_; - std::shared_ptr route_config_{new NiceMock()}; - }; - HttpConnectionManagerImplTest(); ~HttpConnectionManagerImplTest() override; Tracing::CustomTagConstSharedPtr requestHeaderCustomTag(const std::string& header); diff --git a/test/mocks/router/mocks.cc b/test/mocks/router/mocks.cc index 8ab3d486fba10..5ae26ddc415dc 100644 --- a/test/mocks/router/mocks.cc +++ b/test/mocks/router/mocks.cc @@ -136,6 +136,7 @@ MockRoute::~MockRoute() = default; MockRouteConfigProvider::MockRouteConfigProvider() { ON_CALL(*this, config()).WillByDefault(Return(route_config_)); + ON_CALL(*this, configCast()).WillByDefault(Return(route_config_)); } MockRouteConfigProvider::~MockRouteConfigProvider() = default; From 2e94bda18b1e96af9c8cad512db1583987d24338 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sat, 30 Oct 2021 05:25:07 +0000 Subject: [PATCH 29/31] Fix CI issues. Signed-off-by: Tamas Kovacs --- test/common/http/conn_manager_impl_fuzz_test.cc | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/test/common/http/conn_manager_impl_fuzz_test.cc b/test/common/http/conn_manager_impl_fuzz_test.cc index 35aa7dd8ad977..d1d366cb7d436 100644 --- a/test/common/http/conn_manager_impl_fuzz_test.cc +++ b/test/common/http/conn_manager_impl_fuzz_test.cc @@ -49,19 +49,6 @@ namespace Http { class FuzzConfig : public ConnectionManagerConfig { public: - struct RouteConfigProvider : public Router::RouteConfigProvider { - RouteConfigProvider(TimeSource& time_source) : time_source_(time_source) {} - - // Router::RouteConfigProvider - Router::ConfigConstSharedPtr config() override { return route_config_; } - absl::optional configInfo() const override { return {}; } - SystemTime lastUpdated() const override { return time_source_.systemTime(); } - void onConfigUpdate() override {} - - TimeSource& time_source_; - std::shared_ptr route_config_{new NiceMock()}; - }; - FuzzConfig(envoy::extensions::filters::network::http_connection_manager::v3:: HttpConnectionManager::ForwardClientCertDetails forward_client_cert) : stats_({ALL_HTTP_CONN_MAN_STATS(POOL_COUNTER(fake_stats_), POOL_GAUGE(fake_stats_), From d8b377f1066c286d2fc007efb6a83dd8dda07cfb Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sat, 30 Oct 2021 14:28:06 +0000 Subject: [PATCH 30/31] Fix CI issues. Signed-off-by: Tamas Kovacs --- envoy/router/router.h | 2 -- source/extensions/filters/network/thrift_proxy/router/router.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/envoy/router/router.h b/envoy/router/router.h index 4cb4d56ebaff9..a0d30f0c37bec 100644 --- a/envoy/router/router.h +++ b/envoy/router/router.h @@ -1096,8 +1096,6 @@ using RouteCallback = std::function; */ class Config : public Rds::Config { public: - virtual ~Config() = default; - /** * Based on the incoming Thrift request transport and/or protocol data, determine the target * route for the request. From 8209da53fbcbb3784ea7f21dfa2938f364f07828 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Sun, 31 Oct 2021 06:00:45 +0000 Subject: [PATCH 31/31] Fix CI issues, clang-tidy. Signed-off-by: Tamas Kovacs --- envoy/rds/config_traits.h | 1 - source/common/rds/rds_route_config_provider_impl.h | 1 - source/common/rds/rds_route_config_subscription.cc | 2 ++ source/common/rds/rds_route_config_subscription.h | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/envoy/rds/config_traits.h b/envoy/rds/config_traits.h index a703faeeb6b26..50d10e647c0ce 100644 --- a/envoy/rds/config_traits.h +++ b/envoy/rds/config_traits.h @@ -3,7 +3,6 @@ #include #include "envoy/common/pure.h" -#include "envoy/config/subscription.h" #include "envoy/rds/config.h" #include "source/common/protobuf/protobuf.h" diff --git a/source/common/rds/rds_route_config_provider_impl.h b/source/common/rds/rds_route_config_provider_impl.h index c6ce171edd6fa..bb3c40b9a962c 100644 --- a/source/common/rds/rds_route_config_provider_impl.h +++ b/source/common/rds/rds_route_config_provider_impl.h @@ -8,7 +8,6 @@ #include "envoy/server/factory_context.h" #include "envoy/thread_local/thread_local.h" -#include "source/common/common/logger.h" #include "source/common/rds/rds_route_config_subscription.h" namespace Envoy { diff --git a/source/common/rds/rds_route_config_subscription.cc b/source/common/rds/rds_route_config_subscription.cc index 95a731e839b4d..a6b026428d151 100644 --- a/source/common/rds/rds_route_config_subscription.cc +++ b/source/common/rds/rds_route_config_subscription.cc @@ -1,5 +1,7 @@ #include "source/common/rds/rds_route_config_subscription.h" +#include "source/common/common/logger.h" + namespace Envoy { namespace Rds { diff --git a/source/common/rds/rds_route_config_subscription.h b/source/common/rds/rds_route_config_subscription.h index 98b6d287b7aeb..13f079bfbc62e 100644 --- a/source/common/rds/rds_route_config_subscription.h +++ b/source/common/rds/rds_route_config_subscription.h @@ -10,7 +10,6 @@ #include "envoy/server/factory_context.h" #include "envoy/stats/scope.h" -#include "source/common/common/logger.h" #include "source/common/grpc/common.h" #include "source/common/init/manager_impl.h" #include "source/common/init/target_impl.h"