LCOV - code coverage report
Current view: top level - source/common/router - scoped_rds.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 2 51 3.9 %
Date: 2024-01-05 06:35:25 Functions: 2 21 9.5 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <memory>
       4             : #include <string>
       5             : 
       6             : #include "envoy/common/callback.h"
       7             : #include "envoy/config/core/v3/config_source.pb.h"
       8             : #include "envoy/config/route/v3/scoped_route.pb.h"
       9             : #include "envoy/config/route/v3/scoped_route.pb.validate.h"
      10             : #include "envoy/config/subscription.h"
      11             : #include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
      12             : #include "envoy/router/route_config_provider_manager.h"
      13             : #include "envoy/router/scopes.h"
      14             : #include "envoy/service/discovery/v3/discovery.pb.h"
      15             : #include "envoy/stats/scope.h"
      16             : 
      17             : #include "source/common/config/config_provider_impl.h"
      18             : #include "source/common/config/subscription_base.h"
      19             : #include "source/common/init/manager_impl.h"
      20             : #include "source/common/router/rds_impl.h"
      21             : #include "source/common/router/scoped_config_impl.h"
      22             : 
      23             : namespace Envoy {
      24             : namespace Router {
      25             : 
      26             : // Scoped routing configuration utilities.
      27             : namespace ScopedRoutesConfigProviderUtil {
      28             : 
      29             : // If enabled in the HttpConnectionManager config, returns a ConfigProvider for scoped routing
      30             : // configuration.
      31             : Envoy::Config::ConfigProviderPtr create(
      32             :     const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
      33             :         config,
      34             :     Server::Configuration::ServerFactoryContext& factory_context, Init::Manager& init_manager,
      35             :     const std::string& stat_prefix,
      36             :     Envoy::Config::ConfigProviderManager& scoped_routes_config_provider_manager);
      37             : 
      38             : // If enabled in the HttpConnectionManager config, returns a ConfigProvider for scoped routing
      39             : // configuration.
      40             : ScopeKeyBuilderPtr createScopeKeyBuilder(
      41             :     const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
      42             :         config);
      43             : 
      44             : } // namespace ScopedRoutesConfigProviderUtil
      45             : 
      46             : class ScopedRoutesConfigProviderManager;
      47             : 
      48             : // A ConfigProvider for inline scoped routing configuration.
      49             : // InlineScopedRoutesConfigProvider is not fully implemented at this point. It doesn't load
      50             : // ScopedRouteConfigurations and propagate them to worker threads. If
      51             : // InlineScopedRoutesConfigProvider is fully implemented, when it is loading
      52             : // ScopedRouteConfiguration, the on demand field should be ignored and all scopes should be loaded
      53             : // eagerly.
      54             : class InlineScopedRoutesConfigProvider : public Envoy::Config::ImmutableConfigProviderBase {
      55             : public:
      56             :   InlineScopedRoutesConfigProvider(ProtobufTypes::ConstMessagePtrVector&& config_protos,
      57             :                                    std::string name,
      58             :                                    Server::Configuration::ServerFactoryContext& factory_context,
      59             :                                    ScopedRoutesConfigProviderManager& config_provider_manager,
      60             :                                    envoy::config::core::v3::ConfigSource rds_config_source);
      61             : 
      62           0 :   ~InlineScopedRoutesConfigProvider() override = default;
      63             : 
      64           0 :   const std::string& name() const { return name_; }
      65             : 
      66             :   // Envoy::Config::ConfigProvider
      67           0 :   Envoy::Config::ConfigProvider::ConfigProtoVector getConfigProtos() const override {
      68           0 :     Envoy::Config::ConfigProvider::ConfigProtoVector out_protos;
      69           0 :     std::for_each(scopes_.begin(), scopes_.end(),
      70           0 :                   [&out_protos](const ScopedRouteInfoConstSharedPtr& scope) {
      71           0 :                     out_protos.push_back(&scope->configProto());
      72           0 :                   });
      73           0 :     return out_protos;
      74           0 :   }
      75             : 
      76           0 :   std::string getConfigVersion() const override { return ""; }
      77           0 :   ConfigConstSharedPtr getConfig() const override { return config_; }
      78             : 
      79             : private:
      80             :   const std::string name_;
      81             :   const std::vector<ScopedRouteInfoConstSharedPtr> scopes_;
      82             :   ConfigConstSharedPtr config_;
      83             :   const envoy::config::core::v3::ConfigSource rds_config_source_;
      84             : };
      85             : 
      86             : /**
      87             :  * All SRDS stats. @see stats_macros.h
      88             :  */
      89             : // clang-format off
      90             : #define ALL_SCOPED_RDS_STATS(COUNTER, GAUGE)                                                       \
      91             :   COUNTER(config_reload)                                                                           \
      92             :   COUNTER(update_empty)                                                                            \
      93             :   GAUGE(all_scopes, Accumulate)                                                                    \
      94             :   GAUGE(config_reload_time_ms, NeverImport)                                                        \
      95             :   GAUGE(on_demand_scopes, Accumulate)                                                              \
      96             :   GAUGE(active_scopes, Accumulate)
      97             : 
      98             : // clang-format on
      99             : 
     100             : struct ScopedRdsStats {
     101             :   ALL_SCOPED_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT)
     102             : 
     103           0 :   static ScopedRdsStats generateStats(const std::string& prefix, Stats::Scope& scope) {
     104           0 :     return ScopedRdsStats{
     105           0 :         ALL_SCOPED_RDS_STATS(POOL_COUNTER_PREFIX(scope, prefix), POOL_GAUGE_PREFIX(scope, prefix))};
     106           0 :   }
     107             : };
     108             : 
     109             : // A scoped RDS subscription to be used with the dynamic scoped RDS ConfigProvider.
     110             : class ScopedRdsConfigSubscription
     111             :     : public Envoy::Config::DeltaConfigSubscriptionInstance,
     112             :       public Envoy::Config::SubscriptionBase<envoy::config::route::v3::ScopedRouteConfiguration> {
     113             : public:
     114             :   using ScopedRouteConfigurationMap =
     115             :       std::map<std::string, envoy::config::route::v3::ScopedRouteConfiguration>;
     116             : 
     117             :   ScopedRdsConfigSubscription(
     118             :       const envoy::extensions::filters::network::http_connection_manager::v3::ScopedRds& scoped_rds,
     119             :       const uint64_t manager_identifier, const std::string& name,
     120             :       Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix,
     121             :       envoy::config::core::v3::ConfigSource rds_config_source,
     122             :       RouteConfigProviderManager& route_config_provider_manager,
     123             :       ScopedRoutesConfigProviderManager& config_provider_manager);
     124             : 
     125           0 :   ~ScopedRdsConfigSubscription() override = default;
     126             : 
     127           0 :   const std::string& name() const { return name_; }
     128             : 
     129           0 :   const ScopedRouteMap& scopedRouteMap() const { return scoped_route_map_; }
     130             : 
     131             :   void
     132             :   onDemandRdsUpdate(std::shared_ptr<Router::ScopeKey> scope_key,
     133             :                     Event::Dispatcher& thread_local_dispatcher,
     134             :                     Http::RouteConfigUpdatedCallback&& route_config_updated_cb,
     135             :                     std::weak_ptr<Envoy::Config::ConfigSubscriptionCommonBase> weak_subscription);
     136             : 
     137             : private:
     138             :   // A helper class that takes care of the life cycle management of a RDS route provider and the
     139             :   // update callback handle.
     140             :   struct RdsRouteConfigProviderHelper {
     141             :     RdsRouteConfigProviderHelper(
     142             :         ScopedRdsConfigSubscription& parent, std::string scope_name,
     143             :         envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds,
     144             :         Init::Manager& init_manager);
     145             : 
     146             :     RdsRouteConfigProviderHelper(ScopedRdsConfigSubscription& parent, std::string scope_name);
     147             : 
     148           0 :     ~RdsRouteConfigProviderHelper() {
     149             :       // Only remove the rds update when the rds provider has been initialized.
     150           0 :       if (route_provider_) {
     151           0 :         parent_.stats_.active_scopes_.dec();
     152           0 :       }
     153           0 :       if (on_demand_) {
     154           0 :         parent_.stats_.on_demand_scopes_.dec();
     155           0 :       }
     156           0 :     }
     157           0 :     ConfigConstSharedPtr routeConfig() { return route_provider_->configCast(); }
     158             : 
     159             :     void addOnDemandUpdateCallback(std::function<void()> callback);
     160             : 
     161             :     // Runs all the callback from worker thread to continue filter chain.
     162             :     void runOnDemandUpdateCallback();
     163             : 
     164             :     // If route provider has not been initialized, initialize it.
     165             :     void maybeInitRdsConfigProvider();
     166             : 
     167             :     // Initialize route provider and register for rds update.
     168             :     void initRdsConfigProvider(
     169             :         envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds,
     170             :         Init::Manager& init_manager);
     171             : 
     172             :     ScopedRdsConfigSubscription& parent_;
     173             :     std::string scope_name_;
     174             :     bool on_demand_;
     175             :     RdsRouteConfigProviderImplSharedPtr route_provider_;
     176             :     // This handle_ is owned by the route config provider's RDS subscription, when the helper
     177             :     // destructs, the handle is deleted as well.
     178             :     Common::CallbackHandlePtr rds_update_callback_handle_;
     179             :     std::vector<std::function<void()>> on_demand_update_callbacks_;
     180             :   };
     181             : 
     182             :   using RdsRouteConfigProviderHelperPtr = std::unique_ptr<RdsRouteConfigProviderHelper>;
     183             : 
     184             :   // Adds or updates scopes, create a new RDS provider for each resource, if an exception is thrown
     185             :   // during updating, the exception message is collected via the exception messages vector.
     186             :   // Returns a failed status if the operation was unsuccessful. If successful,
     187             :   // returns a boolean indicating if any scopes were applied.
     188             :   absl::StatusOr<bool>
     189             :   addOrUpdateScopes(const std::vector<Envoy::Config::DecodedResourceRef>& resources,
     190             :                     Init::Manager& init_manager, const std::string& version_info);
     191             :   // Removes given scopes from the managed set of scopes.
     192             :   // Returns a list of to be removed helpers which is temporally held in the onConfigUpdate method,
     193             :   // to make sure new scopes sharing the same RDS source configs could reuse the subscriptions.
     194             :   std::list<RdsRouteConfigProviderHelperPtr>
     195             :   removeScopes(const Protobuf::RepeatedPtrField<std::string>& scope_names,
     196             :                const std::string& version_info);
     197             : 
     198             :   // Envoy::Config::DeltaConfigSubscriptionInstance
     199           0 :   void start() override { subscription_->start({}); }
     200             : 
     201             :   // Detect scope name and scope key conflict between added scopes or between added scopes and old
     202             :   // scopes. Some removed scopes may be in added resources list, instead of being removed, they
     203             :   // should be updated, so only return scope names that will disappear after update. If conflict
     204             :   // detected, fill exception_msg with information about scope conflict and return.
     205             :   Protobuf::RepeatedPtrField<std::string> detectUpdateConflictAndCleanupRemoved(
     206             :       const std::vector<Envoy::Config::DecodedResourceRef>& added_resources,
     207             :       const Protobuf::RepeatedPtrField<std::string>& removed_resources, std::string& exception_msg);
     208             : 
     209             :   // Envoy::Config::SubscriptionCallbacks
     210             : 
     211             :   // NOTE: both delta form and state-of-the-world form onConfigUpdate(resources, version_info) will
     212             :   // throw an EnvoyException or return failure on any error and essentially reject an update.
     213             :   absl::Status onConfigUpdate(const std::vector<Envoy::Config::DecodedResourceRef>& resources,
     214             :                               const std::string& version_info) override;
     215             :   absl::Status onConfigUpdate(const std::vector<Envoy::Config::DecodedResourceRef>& added_resources,
     216             :                               const Protobuf::RepeatedPtrField<std::string>& removed_resources,
     217             :                               const std::string& system_version_info) override;
     218             :   void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason,
     219           0 :                             const EnvoyException*) override {
     220           0 :     ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason);
     221           0 :     DeltaConfigSubscriptionInstance::onConfigUpdateFailed();
     222           0 :   }
     223             :   // Propagate RDS updates to ScopeConfigImpl in workers.
     224             :   void onRdsConfigUpdate(const std::string& scope_name, ConfigConstSharedPtr new_rds_config);
     225             : 
     226             :   // ScopedRouteInfo by scope name.
     227             :   ScopedRouteMap scoped_route_map_;
     228             : 
     229             :   // For creating RDS subscriptions.
     230             :   Server::Configuration::ServerFactoryContext& factory_context_;
     231             :   const std::string name_;
     232             :   // Stats must outlive subscription.
     233             :   Stats::ScopeSharedPtr scope_;
     234             :   ScopedRdsStats stats_;
     235             :   Envoy::Config::SubscriptionPtr subscription_;
     236             :   const envoy::config::core::v3::ConfigSource rds_config_source_;
     237             :   const std::string stat_prefix_;
     238             :   RouteConfigProviderManager& route_config_provider_manager_;
     239             : 
     240             :   // RdsRouteConfigProvider by scope name.
     241             :   absl::flat_hash_map<std::string, RdsRouteConfigProviderHelperPtr> route_provider_by_scope_;
     242             :   // A map of (hash, scope-name), used to detect the key conflict between scopes.
     243             :   absl::flat_hash_map<uint64_t, std::string> scope_name_by_hash_;
     244             : };
     245             : 
     246             : using ScopedRdsConfigSubscriptionSharedPtr = std::shared_ptr<ScopedRdsConfigSubscription>;
     247             : 
     248             : // A ConfigProvider for scoped RDS that dynamically fetches scoped routing configuration via a
     249             : // subscription.
     250             : class ScopedRdsConfigProvider : public Envoy::Config::MutableConfigProviderCommonBase {
     251             : public:
     252             :   ScopedRdsConfigProvider(ScopedRdsConfigSubscriptionSharedPtr&& subscription);
     253             : 
     254           0 :   ScopedRdsConfigSubscription& subscription() const {
     255           0 :     return *static_cast<ScopedRdsConfigSubscription*>(subscription_.get());
     256           0 :   }
     257             :   void onDemandRdsUpdate(std::shared_ptr<Router::ScopeKey> scope_key,
     258             :                          Event::Dispatcher& thread_local_dispatcher,
     259           0 :                          Http::RouteConfigUpdatedCallback&& route_config_updated_cb) const {
     260           0 :     subscription().onDemandRdsUpdate(
     261           0 :         std::move(scope_key), thread_local_dispatcher, std::move(route_config_updated_cb),
     262           0 :         std::weak_ptr<Envoy::Config::ConfigSubscriptionCommonBase>(subscription_));
     263           0 :   }
     264             : };
     265             : 
     266             : // A ConfigProviderManager for scoped routing configuration that creates static/inline and dynamic
     267             : // (xds) config providers.
     268             : class ScopedRoutesConfigProviderManager : public Envoy::Config::ConfigProviderManagerImplBase {
     269             : public:
     270             :   ScopedRoutesConfigProviderManager(
     271             :       OptRef<Server::Admin> admin,
     272             :       Router::RouteConfigProviderManager& route_config_provider_manager)
     273             :       : Envoy::Config::ConfigProviderManagerImplBase(admin, "route_scopes"),
     274          96 :         route_config_provider_manager_(route_config_provider_manager) {}
     275             : 
     276          96 :   ~ScopedRoutesConfigProviderManager() override = default;
     277             : 
     278             :   // Envoy::Config::ConfigProviderManagerImplBase
     279             :   ProtobufTypes::MessagePtr dumpConfigs(const Matchers::StringMatcher& name_matcher) const override;
     280             : 
     281             :   // Envoy::Config::ConfigProviderManager
     282             :   Envoy::Config::ConfigProviderPtr
     283             :   createXdsConfigProvider(const Protobuf::Message& config_source_proto,
     284             :                           Server::Configuration::ServerFactoryContext& factory_context,
     285             :                           Init::Manager& init_manager, const std::string& stat_prefix,
     286             :                           const Envoy::Config::ConfigProviderManager::OptionalArg& optarg) override;
     287             :   Envoy::Config::ConfigProviderPtr
     288             :   createStaticConfigProvider(const Protobuf::Message&, Server::Configuration::ServerFactoryContext&,
     289           0 :                              const Envoy::Config::ConfigProviderManager::OptionalArg&) override {
     290           0 :     PANIC("SRDS supports delta updates and requires the use of the createStaticConfigProvider() "
     291           0 :           "overload that accepts a config proto set as an argument.");
     292           0 :   }
     293             :   Envoy::Config::ConfigProviderPtr createStaticConfigProvider(
     294             :       std::vector<std::unique_ptr<const Protobuf::Message>>&& config_protos,
     295             :       Server::Configuration::ServerFactoryContext& factory_context,
     296             :       const Envoy::Config::ConfigProviderManager::OptionalArg& optarg) override;
     297             : 
     298           0 :   RouteConfigProviderManager& routeConfigProviderManager() {
     299           0 :     return route_config_provider_manager_;
     300           0 :   }
     301             : 
     302             : private:
     303             :   RouteConfigProviderManager& route_config_provider_manager_;
     304             : };
     305             : 
     306             : using ScopedRoutesConfigProviderManagerPtr = std::unique_ptr<ScopedRoutesConfigProviderManager>;
     307             : using ScopedRoutesConfigProviderManagerSharedPtr =
     308             :     std::shared_ptr<ScopedRoutesConfigProviderManager>;
     309             : 
     310             : // The optional argument passed to the ConfigProviderManager::create*() functions.
     311             : class ScopedRoutesConfigProviderManagerOptArg
     312             :     : public Envoy::Config::ConfigProviderManager::OptionalArg {
     313             : public:
     314             :   ScopedRoutesConfigProviderManagerOptArg(
     315             :       std::string scoped_routes_name,
     316             :       const envoy::config::core::v3::ConfigSource& rds_config_source)
     317           0 :       : scoped_routes_name_(std::move(scoped_routes_name)), rds_config_source_(rds_config_source) {}
     318             : 
     319             :   const std::string scoped_routes_name_;
     320             :   const envoy::config::core::v3::ConfigSource& rds_config_source_;
     321             : };
     322             : 
     323             : } // namespace Router
     324             : } // namespace Envoy

Generated by: LCOV version 1.15