LCOV - code coverage report
Current view: top level - source/common/router - rds_impl.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 74 151 49.0 %
Date: 2024-01-05 06:35:25 Functions: 16 24 66.7 %

          Line data    Source code
       1             : #include "source/common/router/rds_impl.h"
       2             : 
       3             : #include <chrono>
       4             : #include <cstdint>
       5             : #include <memory>
       6             : #include <string>
       7             : 
       8             : #include "envoy/admin/v3/config_dump.pb.h"
       9             : #include "envoy/config/core/v3/config_source.pb.h"
      10             : #include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
      11             : #include "envoy/service/discovery/v3/discovery.pb.h"
      12             : 
      13             : #include "source/common/common/assert.h"
      14             : #include "source/common/common/fmt.h"
      15             : #include "source/common/config/api_version.h"
      16             : #include "source/common/config/utility.h"
      17             : #include "source/common/http/header_map_impl.h"
      18             : #include "source/common/protobuf/utility.h"
      19             : #include "source/common/router/config_impl.h"
      20             : #include "source/common/router/route_config_update_receiver_impl.h"
      21             : 
      22             : namespace Envoy {
      23             : namespace Router {
      24             : 
      25             : RouteConfigProviderSharedPtr RouteConfigProviderUtil::create(
      26             :     const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
      27             :         config,
      28             :     Server::Configuration::ServerFactoryContext& factory_context,
      29             :     ProtobufMessage::ValidationVisitor& validator, Init::Manager& init_manager,
      30         140 :     const std::string& stat_prefix, RouteConfigProviderManager& route_config_provider_manager) {
      31             : 
      32         140 :   switch (config.route_specifier_case()) {
      33          74 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
      34          74 :       RouteSpecifierCase::kRouteConfig:
      35          74 :     return route_config_provider_manager.createStaticRouteConfigProvider(
      36          74 :         config.route_config(), factory_context, validator);
      37          66 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
      38          66 :       RouteSpecifierCase::kRds:
      39          66 :     return route_config_provider_manager.createRdsRouteConfigProvider(
      40             :         // At the creation of a RDS route config provider, the factory_context's initManager is
      41             :         // always valid, though the init manager may go away later when the listener goes away.
      42          66 :         config.rds(), factory_context, stat_prefix, init_manager);
      43           0 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
      44           0 :       RouteSpecifierCase::kScopedRoutes:
      45           0 :     FALLTHRU; // PANIC
      46           0 :   case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
      47           0 :       RouteSpecifierCase::ROUTE_SPECIFIER_NOT_SET:
      48           0 :     PANIC("not implemented");
      49         140 :   }
      50           0 :   PANIC_DUE_TO_CORRUPT_ENUM;
      51           0 : }
      52             : 
      53             : StaticRouteConfigProviderImpl::StaticRouteConfigProviderImpl(
      54             :     const envoy::config::route::v3::RouteConfiguration& config, Rds::ConfigTraits& config_traits,
      55             :     Server::Configuration::ServerFactoryContext& factory_context,
      56             :     Rds::RouteConfigProviderManager& route_config_provider_manager)
      57             :     : base_(config, config_traits, factory_context, route_config_provider_manager),
      58          74 :       route_config_provider_manager_(route_config_provider_manager) {}
      59             : 
      60          74 : StaticRouteConfigProviderImpl::~StaticRouteConfigProviderImpl() {
      61          74 :   route_config_provider_manager_.eraseStaticProvider(this);
      62          74 : }
      63             : 
      64         393 : ConfigConstSharedPtr StaticRouteConfigProviderImpl::configCast() const {
      65         393 :   ASSERT(dynamic_cast<const Config*>(StaticRouteConfigProviderImpl::config().get()));
      66         393 :   return std::static_pointer_cast<const Config>(StaticRouteConfigProviderImpl::config());
      67         393 : }
      68             : 
      69             : // TODO(htuch): If support for multiple clusters is added per #1170 cluster_name_
      70             : RdsRouteConfigSubscription::RdsRouteConfigSubscription(
      71             :     RouteConfigUpdatePtr&& config_update,
      72             :     Envoy::Config::OpaqueResourceDecoderSharedPtr&& resource_decoder,
      73             :     const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds,
      74             :     const uint64_t manager_identifier, Server::Configuration::ServerFactoryContext& factory_context,
      75             :     const std::string& stat_prefix, Rds::RouteConfigProviderManager& route_config_provider_manager)
      76             :     : Rds::RdsRouteConfigSubscription(std::move(config_update), std::move(resource_decoder),
      77             :                                       rds.config_source(), rds.route_config_name(),
      78             :                                       manager_identifier, factory_context, stat_prefix + "rds.",
      79             :                                       "RDS", route_config_provider_manager),
      80             :       config_update_info_(static_cast<RouteConfigUpdateReceiver*>(
      81          50 :           Rds::RdsRouteConfigSubscription::config_update_info_.get())) {}
      82             : 
      83          50 : RdsRouteConfigSubscription::~RdsRouteConfigSubscription() { config_update_info_.release(); }
      84             : 
      85             : void RdsRouteConfigSubscription::beforeProviderUpdate(
      86          36 :     std::unique_ptr<Init::ManagerImpl>& noop_init_manager, std::unique_ptr<Cleanup>& resume_rds) {
      87          36 :   if (config_update_info_->protobufConfigurationCast().has_vhds() &&
      88          36 :       config_update_info_->vhdsConfigurationChanged()) {
      89           0 :     ENVOY_LOG(debug,
      90           0 :               "rds: vhds configuration present/changed, (re)starting vhds: config_name={} hash={}",
      91           0 :               route_config_name_, routeConfigUpdate()->configHash());
      92           0 :     ASSERT(config_update_info_->configInfo().has_value());
      93           0 :     maybeCreateInitManager(routeConfigUpdate()->configInfo().value().version_, noop_init_manager,
      94           0 :                            resume_rds);
      95           0 :     vhds_subscription_ = std::make_unique<VhdsSubscription>(config_update_info_, factory_context_,
      96           0 :                                                             stat_prefix_, route_config_provider_);
      97           0 :     vhds_subscription_->registerInitTargetWithInitManager(
      98           0 :         noop_init_manager == nullptr ? local_init_manager_ : *noop_init_manager);
      99           0 :   }
     100          36 : }
     101             : 
     102          36 : void RdsRouteConfigSubscription::afterProviderUpdate() {
     103             :   // RDS update removed VHDS configuration
     104          36 :   if (!config_update_info_->protobufConfigurationCast().has_vhds()) {
     105          36 :     vhds_subscription_.release();
     106          36 :   }
     107             : 
     108          36 :   update_callback_manager_.runCallbacks();
     109          36 : }
     110             : 
     111             : // Initialize a no-op InitManager in case the one in the factory_context has completed
     112             : // initialization. This can happen if an RDS config update for an already established RDS
     113             : // subscription contains VHDS configuration.
     114             : void RdsRouteConfigSubscription::maybeCreateInitManager(
     115             :     const std::string& version_info, std::unique_ptr<Init::ManagerImpl>& init_manager,
     116           0 :     std::unique_ptr<Cleanup>& init_vhds) {
     117           0 :   if (local_init_manager_.state() == Init::Manager::State::Initialized) {
     118           0 :     init_manager = std::make_unique<Init::ManagerImpl>(
     119           0 :         fmt::format("VHDS {}:{}", route_config_name_, version_info));
     120           0 :     init_vhds = std::make_unique<Cleanup>([this, &init_manager, version_info] {
     121             :       // For new RDS subscriptions created after listener warming up, we don't wait for them to warm
     122             :       // up.
     123           0 :       Init::WatcherImpl noop_watcher(
     124             :           // Note: we just throw it away.
     125           0 :           fmt::format("VHDS ConfigUpdate watcher {}:{}", route_config_name_, version_info),
     126           0 :           []() { /*Do nothing.*/ });
     127           0 :       init_manager->initialize(noop_watcher);
     128           0 :     });
     129           0 :   }
     130           0 : }
     131             : 
     132           0 : void RdsRouteConfigSubscription::updateOnDemand(const std::string& aliases) {
     133           0 :   if (vhds_subscription_.get() == nullptr) {
     134           0 :     return;
     135           0 :   }
     136           0 :   vhds_subscription_->updateOnDemand(aliases);
     137           0 : }
     138             : 
     139             : RdsRouteConfigProviderImpl::RdsRouteConfigProviderImpl(
     140             :     RdsRouteConfigSubscriptionSharedPtr&& subscription,
     141             :     Server::Configuration::ServerFactoryContext& factory_context)
     142             :     : base_(subscription, factory_context), config_update_info_(subscription->routeConfigUpdate()),
     143          50 :       factory_context_(factory_context) {
     144             :   // The subscription referenced by the 'base_' and by 'this' is the same.
     145             :   // In it the provider is already set by the 'base_' so it points to that.
     146             :   // Need to set again to point to 'this'.
     147          50 :   base_.subscription().routeConfigProvider() = this;
     148          50 : }
     149             : 
     150          50 : RdsRouteConfigSubscription& RdsRouteConfigProviderImpl::subscription() {
     151          50 :   return static_cast<RdsRouteConfigSubscription&>(base_.subscription());
     152          50 : }
     153             : 
     154          36 : absl::Status RdsRouteConfigProviderImpl::onConfigUpdate() {
     155          36 :   auto status = base_.onConfigUpdate();
     156          36 :   if (!status.ok()) {
     157           0 :     return status;
     158           0 :   }
     159             : 
     160          36 :   const auto aliases = config_update_info_->resourceIdsInLastVhdsUpdate();
     161             :   // Regular (non-VHDS) RDS updates don't populate aliases fields in resources.
     162          36 :   if (aliases.empty()) {
     163          36 :     return absl::OkStatus();
     164          36 :   }
     165             : 
     166           0 :   const auto config =
     167           0 :       std::static_pointer_cast<const ConfigImpl>(config_update_info_->parsedConfiguration());
     168             :   // Notifies connections that RouteConfiguration update has been propagated.
     169             :   // Callbacks processing is performed in FIFO order. The callback is skipped if alias used in
     170             :   // the VHDS update request do not match the aliases in the update response
     171           0 :   for (auto it = config_update_callbacks_.begin(); it != config_update_callbacks_.end();) {
     172           0 :     auto found = aliases.find(it->alias_);
     173           0 :     if (found != aliases.end()) {
     174             :       // TODO(dmitri-d) HeaderMapImpl is expensive, need to profile this
     175           0 :       auto host_header = Http::RequestHeaderMapImpl::create();
     176           0 :       host_header->setHost(VhdsSubscription::aliasToDomainName(it->alias_));
     177           0 :       const bool host_exists = config->virtualHostExists(*host_header);
     178           0 :       std::weak_ptr<Http::RouteConfigUpdatedCallback> current_cb(it->cb_);
     179           0 :       it->thread_local_dispatcher_.post([current_cb, host_exists] {
     180           0 :         if (auto cb = current_cb.lock()) {
     181           0 :           (*cb)(host_exists);
     182           0 :         }
     183           0 :       });
     184           0 :       it = config_update_callbacks_.erase(it);
     185           0 :     } else {
     186           0 :       it++;
     187           0 :     }
     188           0 :   }
     189           0 :   return absl::OkStatus();
     190          36 : }
     191             : 
     192           0 : ConfigConstSharedPtr RdsRouteConfigProviderImpl::configCast() const {
     193           0 :   ASSERT(dynamic_cast<const Config*>(RdsRouteConfigProviderImpl::config().get()));
     194           0 :   return std::static_pointer_cast<const Config>(RdsRouteConfigProviderImpl::config());
     195           0 : }
     196             : 
     197             : // Schedules a VHDS request on the main thread and queues up the callback to use when the VHDS
     198             : // response has been propagated to the worker thread that was the request origin.
     199             : void RdsRouteConfigProviderImpl::requestVirtualHostsUpdate(
     200             :     const std::string& for_domain, Event::Dispatcher& thread_local_dispatcher,
     201           0 :     std::weak_ptr<Http::RouteConfigUpdatedCallback> route_config_updated_cb) {
     202           0 :   auto alias = VhdsSubscription::domainNameToAlias(
     203           0 :       config_update_info_->protobufConfigurationCast().name(), for_domain);
     204             :   // The RdsRouteConfigProviderImpl instance can go away before the dispatcher has a chance to
     205             :   // execute the callback. still_alive shared_ptr will be deallocated when the current instance of
     206             :   // the RdsRouteConfigProviderImpl is deallocated; we rely on a weak_ptr to still_alive flag to
     207             :   // determine if the RdsRouteConfigProviderImpl instance is still valid.
     208           0 :   factory_context_.mainThreadDispatcher().post([this,
     209           0 :                                                 maybe_still_alive =
     210           0 :                                                     std::weak_ptr<bool>(still_alive_),
     211           0 :                                                 alias, &thread_local_dispatcher,
     212           0 :                                                 route_config_updated_cb]() -> void {
     213           0 :     if (maybe_still_alive.lock()) {
     214           0 :       subscription().updateOnDemand(alias);
     215           0 :       config_update_callbacks_.push_back({alias, thread_local_dispatcher, route_config_updated_cb});
     216           0 :     }
     217           0 :   });
     218           0 : }
     219             : 
     220             : RouteConfigProviderManagerImpl::RouteConfigProviderManagerImpl(OptRef<Server::Admin> admin)
     221          96 :     : manager_(admin, "routes", proto_traits_) {}
     222             : 
     223             : Router::RouteConfigProviderSharedPtr RouteConfigProviderManagerImpl::createRdsRouteConfigProvider(
     224             :     const envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds,
     225             :     Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix,
     226          66 :     Init::Manager& init_manager) {
     227          66 :   auto provider = manager_.addDynamicProvider(
     228          66 :       rds, rds.route_config_name(), init_manager,
     229          66 :       [&factory_context, &rds, &stat_prefix, this](uint64_t manager_identifier) {
     230          50 :         auto config_update =
     231          50 :             std::make_unique<RouteConfigUpdateReceiverImpl>(proto_traits_, factory_context);
     232          50 :         auto resource_decoder = std::make_shared<
     233          50 :             Envoy::Config::OpaqueResourceDecoderImpl<envoy::config::route::v3::RouteConfiguration>>(
     234          50 :             factory_context.messageValidationContext().dynamicValidationVisitor(), "name");
     235          50 :         auto subscription = std::make_shared<RdsRouteConfigSubscription>(
     236          50 :             std::move(config_update), std::move(resource_decoder), rds, manager_identifier,
     237          50 :             factory_context, stat_prefix, manager_);
     238          50 :         auto provider =
     239          50 :             std::make_shared<RdsRouteConfigProviderImpl>(std::move(subscription), factory_context);
     240          50 :         return std::make_pair(provider, &provider->subscription().initTarget());
     241          50 :       });
     242          66 :   ASSERT(dynamic_cast<RouteConfigProvider*>(provider.get()));
     243          66 :   return std::static_pointer_cast<RouteConfigProvider>(provider);
     244          66 : }
     245             : 
     246             : RouteConfigProviderPtr RouteConfigProviderManagerImpl::createStaticRouteConfigProvider(
     247             :     const envoy::config::route::v3::RouteConfiguration& route_config,
     248             :     Server::Configuration::ServerFactoryContext& factory_context,
     249          74 :     ProtobufMessage::ValidationVisitor& validator) {
     250          74 :   auto provider = manager_.addStaticProvider([&factory_context, &validator, &route_config, this]() {
     251          74 :     ConfigTraitsImpl config_traits(validator);
     252          74 :     return std::make_unique<StaticRouteConfigProviderImpl>(route_config, config_traits,
     253          74 :                                                            factory_context, manager_);
     254          74 :   });
     255          74 :   ASSERT(dynamic_cast<RouteConfigProvider*>(provider.get()));
     256          74 :   return RouteConfigProviderPtr(static_cast<RouteConfigProvider*>(provider.release()));
     257          74 : }
     258             : 
     259             : } // namespace Router
     260             : } // namespace Envoy

Generated by: LCOV version 1.15