LCOV - code coverage report
Current view: top level - source/common/config - utility.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 112 159 70.4 %
Date: 2024-01-05 06:35:25 Functions: 89 423 21.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "envoy/api/api.h"
       4             : #include "envoy/common/random_generator.h"
       5             : #include "envoy/config/bootstrap/v3/bootstrap.pb.h"
       6             : #include "envoy/config/cluster/v3/cluster.pb.h"
       7             : #include "envoy/config/core/v3/address.pb.h"
       8             : #include "envoy/config/core/v3/config_source.pb.h"
       9             : #include "envoy/config/endpoint/v3/endpoint.pb.h"
      10             : #include "envoy/config/grpc_mux.h"
      11             : #include "envoy/config/subscription.h"
      12             : #include "envoy/local_info/local_info.h"
      13             : #include "envoy/registry/registry.h"
      14             : #include "envoy/server/filter_config.h"
      15             : #include "envoy/stats/histogram.h"
      16             : #include "envoy/stats/scope.h"
      17             : #include "envoy/stats/stats_macros.h"
      18             : #include "envoy/stats/stats_matcher.h"
      19             : #include "envoy/stats/tag_producer.h"
      20             : #include "envoy/upstream/cluster_manager.h"
      21             : 
      22             : #include "source/common/common/assert.h"
      23             : #include "source/common/common/backoff_strategy.h"
      24             : #include "source/common/common/hash.h"
      25             : #include "source/common/common/hex.h"
      26             : #include "source/common/common/utility.h"
      27             : #include "source/common/grpc/common.h"
      28             : #include "source/common/protobuf/protobuf.h"
      29             : #include "source/common/protobuf/utility.h"
      30             : #include "source/common/runtime/runtime_features.h"
      31             : #include "source/common/singleton/const_singleton.h"
      32             : #include "source/common/version/api_version.h"
      33             : #include "source/common/version/api_version_struct.h"
      34             : 
      35             : #include "absl/types/optional.h"
      36             : #include "udpa/type/v1/typed_struct.pb.h"
      37             : #include "xds/type/v3/typed_struct.pb.h"
      38             : 
      39             : namespace Envoy {
      40             : namespace Config {
      41             : 
      42             : constexpr absl::string_view Wildcard = "*";
      43             : 
      44             : /**
      45             :  * Constant Api Type Values, used by envoy::config::core::v3::ApiConfigSource.
      46             :  */
      47             : class ApiTypeValues {
      48             : public:
      49             :   const std::string UnsupportedRestLegacy{"REST_LEGACY"};
      50             :   const std::string Rest{"REST"};
      51             :   const std::string Grpc{"GRPC"};
      52             : };
      53             : 
      54             : /**
      55             :  * RateLimitSettings for discovery requests.
      56             :  */
      57             : struct RateLimitSettings {
      58             :   // Default Max Tokens.
      59             :   static const uint32_t DefaultMaxTokens = 100;
      60             :   // Default Fill Rate.
      61             :   static constexpr double DefaultFillRate = 10;
      62             : 
      63             :   uint32_t max_tokens_{DefaultMaxTokens};
      64             :   double fill_rate_{DefaultFillRate};
      65             :   bool enabled_{false};
      66             : };
      67             : 
      68             : using ApiType = ConstSingleton<ApiTypeValues>;
      69             : 
      70             : /**
      71             :  * General config API utilities.
      72             :  */
      73             : class Utility {
      74             : public:
      75             :   /**
      76             :    * Legacy APIs uses JSON and do not have an explicit version.
      77             :    * @param input the input to hash.
      78             :    * @return std::pair<std::string, uint64_t> the string is the hash converted into
      79             :    *         a hex string, pre-pended by a user friendly prefix. The uint64_t is the
      80             :    *         raw hash.
      81             :    */
      82           0 :   static std::pair<std::string, uint64_t> computeHashedVersion(const std::string& input) {
      83           0 :     uint64_t hash = HashUtil::xxHash64(input);
      84           0 :     return std::make_pair("hash_" + Hex::uint64ToHex(hash), hash);
      85           0 :   }
      86             : 
      87             :   /**
      88             :    * Extract refresh_delay as a std::chrono::milliseconds from
      89             :    * envoy::config::core::v3::ApiConfigSource.
      90             :    */
      91             :   static std::chrono::milliseconds
      92             :   apiConfigSourceRefreshDelay(const envoy::config::core::v3::ApiConfigSource& api_config_source);
      93             : 
      94             :   /**
      95             :    * Extract request_timeout as a std::chrono::milliseconds from
      96             :    * envoy::config::core::v3::ApiConfigSource. If request_timeout isn't set in the config source, a
      97             :    * default value of 1s will be returned.
      98             :    */
      99             :   static std::chrono::milliseconds
     100             :   apiConfigSourceRequestTimeout(const envoy::config::core::v3::ApiConfigSource& api_config_source);
     101             : 
     102             :   /**
     103             :    * Extract initial_fetch_timeout as a std::chrono::milliseconds from
     104             :    * envoy::config::core::v3::ApiConfigSource. If request_timeout isn't set in the config source, a
     105             :    * default value of 15s will be returned.
     106             :    */
     107             :   static std::chrono::milliseconds
     108             :   configSourceInitialFetchTimeout(const envoy::config::core::v3::ConfigSource& config_source);
     109             : 
     110             :   /**
     111             :    * Check cluster info for API config sanity. Throws on error.
     112             :    * @param error_prefix supplies the prefix to use in error messages.
     113             :    * @param cluster_name supplies the cluster name to check.
     114             :    * @param cm supplies the cluster manager.
     115             :    * @param allow_added_via_api indicates whether a cluster is allowed to be added via api
     116             :    *                            rather than be a static resource from the bootstrap config.
     117             :    * @return the main thread cluster if it exists.
     118             :    */
     119             :   static Upstream::ClusterConstOptRef checkCluster(absl::string_view error_prefix,
     120             :                                                    absl::string_view cluster_name,
     121             :                                                    Upstream::ClusterManager& cm,
     122             :                                                    bool allow_added_via_api = false);
     123             : 
     124             :   /**
     125             :    * Check cluster/local info for API config sanity. Throws on error.
     126             :    * @param error_prefix supplies the prefix to use in error messages.
     127             :    * @param cluster_name supplies the cluster name to check.
     128             :    * @param cm supplies the cluster manager.
     129             :    * @param local_info supplies the local info.
     130             :    * @return the main thread cluster if it exists.
     131             :    */
     132             :   static Upstream::ClusterConstOptRef
     133             :   checkClusterAndLocalInfo(absl::string_view error_prefix, absl::string_view cluster_name,
     134             :                            Upstream::ClusterManager& cm, const LocalInfo::LocalInfo& local_info);
     135             : 
     136             :   /**
     137             :    * Check local info for API config sanity. Throws on error.
     138             :    * @param error_prefix supplies the prefix to use in error messages.
     139             :    * @param local_info supplies the local info.
     140             :    */
     141             :   static void checkLocalInfo(absl::string_view error_prefix,
     142             :                              const LocalInfo::LocalInfo& local_info);
     143             : 
     144             :   /**
     145             :    * Check the existence of a path for a filesystem subscription. Throws on error.
     146             :    * @param path the path to validate.
     147             :    * @param api reference to the Api object
     148             :    */
     149             :   static void checkFilesystemSubscriptionBackingPath(const std::string& path, Api::Api& api);
     150             : 
     151             :   /**
     152             :    * Check the validity of a cluster backing an api config source. Throws on error.
     153             :    * @param primary_clusters the API config source eligible clusters.
     154             :    * @param cluster_name the cluster name to validate.
     155             :    * @param config_source the config source typed name.
     156             :    * @throws EnvoyException when an API config doesn't have a statically defined non-EDS cluster.
     157             :    */
     158             :   static void validateClusterName(const Upstream::ClusterManager::ClusterSet& primary_clusters,
     159             :                                   const std::string& cluster_name,
     160             :                                   const std::string& config_source);
     161             : 
     162             :   /**
     163             :    * Potentially calls Utility::validateClusterName, if a cluster name can be found.
     164             :    * @param primary_clusters the API config source eligible clusters.
     165             :    * @param api_config_source the config source to validate.
     166             :    * @throws EnvoyException when an API config doesn't have a statically defined non-EDS cluster.
     167             :    */
     168             :   static void checkApiConfigSourceSubscriptionBackingCluster(
     169             :       const Upstream::ClusterManager::ClusterSet& primary_clusters,
     170             :       const envoy::config::core::v3::ApiConfigSource& api_config_source);
     171             : 
     172             :   /**
     173             :    * Gets the gRPC control plane management server from the API config source. The result is either
     174             :    * a cluster name or a host name.
     175             :    * @param api_config_source the config source to validate.
     176             :    * @return the gRPC control plane server, or absl::nullopt if it couldn't be extracted.
     177             :    */
     178             :   static absl::optional<std::string>
     179             :   getGrpcControlPlane(const envoy::config::core::v3::ApiConfigSource& api_config_source);
     180             : 
     181             :   /**
     182             :    * Validate transport_api_version field in ApiConfigSource.
     183             :    * @param api_config_source the config source to extract transport API version from.
     184             :    * @returns a failure status when the transport version is disabled.
     185             :    */
     186          45 :   template <class Proto> static absl::Status checkTransportVersion(const Proto& api_config_source) {
     187          45 :     const auto transport_api_version = api_config_source.transport_api_version();
     188          45 :     ASSERT_IS_MAIN_OR_TEST_THREAD();
     189          45 :     if (transport_api_version != envoy::config::core::v3::ApiVersion::V3) {
     190          11 :       const std::string& warning = fmt::format(
     191          11 :           "V2 (and AUTO) xDS transport protocol versions are deprecated in {}. "
     192          11 :           "The v2 xDS major version has been removed and is no longer supported. "
     193          11 :           "You may be missing explicit V3 configuration of the transport API version, "
     194          11 :           "see the advice in https://www.envoyproxy.io/docs/envoy/latest/faq/api/envoy_v3.",
     195          11 :           api_config_source.DebugString());
     196          11 :       ENVOY_LOG_MISC(warn, warning);
     197          11 :       return absl::InvalidArgumentError(warning);
     198          11 :     }
     199          34 :     return absl::OkStatus();
     200          45 :   }
     201             : 
     202             :   /**
     203             :    * Parses RateLimit configuration from envoy::config::core::v3::ApiConfigSource to
     204             :    * RateLimitSettings.
     205             :    * @param api_config_source ApiConfigSource.
     206             :    * @return RateLimitSettings.
     207             :    */
     208             :   static RateLimitSettings
     209             :   parseRateLimitSettings(const envoy::config::core::v3::ApiConfigSource& api_config_source);
     210             : 
     211             :   /**
     212             :    * Generate a ControlPlaneStats object from stats scope.
     213             :    * @param scope for stats.
     214             :    * @return ControlPlaneStats for scope.
     215             :    */
     216          29 :   static ControlPlaneStats generateControlPlaneStats(Stats::Scope& scope) {
     217          29 :     const std::string control_plane_prefix = "control_plane.";
     218          29 :     return {ALL_CONTROL_PLANE_STATS(POOL_COUNTER_PREFIX(scope, control_plane_prefix),
     219          29 :                                     POOL_GAUGE_PREFIX(scope, control_plane_prefix),
     220          29 :                                     POOL_TEXT_READOUT_PREFIX(scope, control_plane_prefix))};
     221          29 :   }
     222             : 
     223             :   /**
     224             :    * Generate a SubscriptionStats object from stats scope.
     225             :    * @param scope for stats.
     226             :    * @return SubscriptionStats for scope.
     227             :    */
     228         205 :   static SubscriptionStats generateStats(Stats::Scope& scope) {
     229         205 :     return {ALL_SUBSCRIPTION_STATS(POOL_COUNTER(scope), POOL_GAUGE(scope), POOL_TEXT_READOUT(scope),
     230         205 :                                    POOL_HISTOGRAM(scope))};
     231         205 :   }
     232             : 
     233             :   /**
     234             :    * Get a Factory from the registry with a particular name (and templated type) with error checking
     235             :    * to ensure the name and factory are valid.
     236             :    * @param name string identifier for the particular implementation.
     237             :    * @param is_optional exception will be throw when the value is false and no factory found.
     238             :    * @return factory the factory requested or nullptr if it does not exist.
     239             :    */
     240             :   template <class Factory>
     241         742 :   static Factory* getAndCheckFactoryByName(const std::string& name, bool is_optional) {
     242         742 :     if (name.empty()) {
     243           0 :       ExceptionUtil::throwEnvoyException("Provided name for static registration lookup was empty.");
     244           0 :     }
     245             : 
     246         742 :     Factory* factory = Registry::FactoryRegistry<Factory>::getFactory(name);
     247             : 
     248         742 :     if (factory == nullptr && !is_optional) {
     249         110 :       ExceptionUtil::throwEnvoyException(
     250         110 :           fmt::format("Didn't find a registered implementation for name: '{}'", name));
     251         110 :     }
     252             : 
     253         742 :     return factory;
     254         742 :   }
     255             : 
     256             :   /**
     257             :    * Get a Factory from the registry with a particular name (and templated type) with error checking
     258             :    * to ensure the name and factory are valid.
     259             :    * @param name string identifier for the particular implementation.
     260             :    * @return factory the factory requested or nullptr if it does not exist.
     261             :    */
     262         737 :   template <class Factory> static Factory& getAndCheckFactoryByName(const std::string& name) {
     263         737 :     return *getAndCheckFactoryByName<Factory>(name, false);
     264         737 :   }
     265             : 
     266             :   /**
     267             :    * Get a Factory from the registry with a particular name or return nullptr.
     268             :    * @param name string identifier for the particular implementation.
     269             :    */
     270        2805 :   template <class Factory> static Factory* getFactoryByName(const std::string& name) {
     271        2805 :     if (name.empty()) {
     272           0 :       return nullptr;
     273           0 :     }
     274             : 
     275        2805 :     return Registry::FactoryRegistry<Factory>::getFactory(name);
     276        2805 :   }
     277             : 
     278             :   /**
     279             :    * Get a Factory from the registry or return nullptr.
     280             :    * @param message proto that contains fields 'name' and 'typed_config'.
     281             :    */
     282             :   template <class Factory, class ProtoMessage>
     283         184 :   static Factory* getFactory(const ProtoMessage& message) {
     284         184 :     Factory* factory = Utility::getFactoryByType<Factory>(message.typed_config());
     285         184 :     if (factory != nullptr ||
     286         184 :         Runtime::runtimeFeatureEnabled("envoy.reloadable_features.no_extension_lookup_by_name")) {
     287         184 :       return factory;
     288         184 :     }
     289             : 
     290           0 :     return Utility::getFactoryByName<Factory>(message.name());
     291         184 :   }
     292             : 
     293             :   /**
     294             :    * Get a Factory from the registry with error checking to ensure the name and the factory are
     295             :    * valid. And a flag to control return nullptr or throw an exception.
     296             :    * @param message proto that contains fields 'name' and 'typed_config'.
     297             :    * @param is_optional an exception will be throw when the value is false and no factory found.
     298             :    * @return factory the factory requested or nullptr if it does not exist.
     299             :    */
     300             :   template <class Factory, class ProtoMessage>
     301        1220 :   static Factory* getAndCheckFactory(const ProtoMessage& message, bool is_optional) {
     302        1220 :     Factory* factory = Utility::getFactoryByType<Factory>(message.typed_config());
     303        1220 :     if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.no_extension_lookup_by_name")) {
     304         162 :       if (factory == nullptr && !is_optional) {
     305          43 :         ExceptionUtil::throwEnvoyException(
     306          43 :             fmt::format("Didn't find a registered implementation for '{}' with type URL: '{}'",
     307          43 :                         message.name(), getFactoryType(message.typed_config())));
     308          43 :       }
     309         162 :       return factory;
     310        1220 :     } else if (factory != nullptr) {
     311        1058 :       return factory;
     312        1058 :     }
     313             : 
     314           0 :     return Utility::getAndCheckFactoryByName<Factory>(message.name(), is_optional);
     315        1220 :   }
     316             : 
     317             :   /**
     318             :    * Get a Factory from the registry with error checking to ensure the name and the factory are
     319             :    * valid.
     320             :    * @param message proto that contains fields 'name' and 'typed_config'.
     321             :    */
     322             :   template <class Factory, class ProtoMessage>
     323         761 :   static Factory& getAndCheckFactory(const ProtoMessage& message) {
     324         761 :     return *getAndCheckFactory<Factory>(message, false);
     325         761 :   }
     326             : 
     327             :   /**
     328             :    * Get type URL from a typed config.
     329             :    * @param typed_config for the extension config.
     330             :    */
     331        1461 :   static std::string getFactoryType(const ProtobufWkt::Any& typed_config) {
     332        1461 :     static const std::string& typed_struct_type =
     333        1461 :         xds::type::v3::TypedStruct::default_instance().GetTypeName();
     334        1461 :     static const std::string& legacy_typed_struct_type =
     335        1461 :         udpa::type::v1::TypedStruct::default_instance().GetTypeName();
     336             :     // Unpack methods will only use the fully qualified type name after the last '/'.
     337             :     // https://github.com/protocolbuffers/protobuf/blob/3.6.x/src/google/protobuf/any.proto#L87
     338        1461 :     auto type = std::string(TypeUtil::typeUrlToDescriptorFullName(typed_config.type_url()));
     339        1461 :     if (type == typed_struct_type) {
     340           0 :       xds::type::v3::TypedStruct typed_struct;
     341           0 :       MessageUtil::unpackTo(typed_config, typed_struct);
     342             :       // Not handling nested structs or typed structs in typed structs
     343           0 :       return std::string(TypeUtil::typeUrlToDescriptorFullName(typed_struct.type_url()));
     344        1461 :     } else if (type == legacy_typed_struct_type) {
     345           0 :       udpa::type::v1::TypedStruct typed_struct;
     346           0 :       MessageUtil::unpackTo(typed_config, typed_struct);
     347             :       // Not handling nested structs or typed structs in typed structs
     348           0 :       return std::string(TypeUtil::typeUrlToDescriptorFullName(typed_struct.type_url()));
     349           0 :     }
     350        1461 :     return type;
     351        1461 :   }
     352             : 
     353             :   /**
     354             :    * Get a Factory from the registry by type URL.
     355             :    * @param typed_config for the extension config.
     356             :    */
     357        1438 :   template <class Factory> static Factory* getFactoryByType(const ProtobufWkt::Any& typed_config) {
     358        1438 :     if (typed_config.type_url().empty()) {
     359          48 :       return nullptr;
     360          48 :     }
     361        1390 :     return Registry::FactoryRegistry<Factory>::getFactoryByType(getFactoryType(typed_config));
     362        1438 :   }
     363             : 
     364             :   /**
     365             :    * Translate a nested config into a proto message provided by the implementation factory.
     366             :    * @param enclosing_message proto that contains a field 'typed_config'. Note: the enclosing proto
     367             :    * is provided because for statically registered implementations, a custom config is generally
     368             :    * optional, which means the conversion must be done conditionally.
     369             :    * @param validation_visitor message validation visitor instance.
     370             :    * @param factory implementation factory with the method 'createEmptyConfigProto' to produce a
     371             :    * proto to be filled with the translated configuration.
     372             :    */
     373             :   template <class ProtoMessage, class Factory>
     374             :   static ProtobufTypes::MessagePtr
     375             :   translateToFactoryConfig(const ProtoMessage& enclosing_message,
     376             :                            ProtobufMessage::ValidationVisitor& validation_visitor,
     377        1405 :                            Factory& factory) {
     378        1405 :     ProtobufTypes::MessagePtr config = factory.createEmptyConfigProto();
     379             : 
     380             :     // Fail in an obvious way if a plugin does not return a proto.
     381        1405 :     RELEASE_ASSERT(config != nullptr, "");
     382             : 
     383             :     // Check that the config type is not google.protobuf.Empty
     384        1405 :     RELEASE_ASSERT(config->GetTypeName() != "google.protobuf.Empty", "");
     385             : 
     386        1405 :     translateOpaqueConfig(enclosing_message.typed_config(), validation_visitor, *config);
     387        1405 :     return config;
     388        1405 :   }
     389             : 
     390             :   /**
     391             :    * Translate the typed any field into a proto message provided by the implementation factory.
     392             :    * @param typed_config typed configuration.
     393             :    * @param validation_visitor message validation visitor instance.
     394             :    * @param factory implementation factory with the method 'createEmptyConfigProto' to produce a
     395             :    * proto to be filled with the translated configuration.
     396             :    */
     397             :   template <class Factory>
     398             :   static ProtobufTypes::MessagePtr
     399             :   translateAnyToFactoryConfig(const ProtobufWkt::Any& typed_config,
     400             :                               ProtobufMessage::ValidationVisitor& validation_visitor,
     401         389 :                               Factory& factory) {
     402         389 :     ProtobufTypes::MessagePtr config = factory.createEmptyConfigProto();
     403             : 
     404             :     // Fail in an obvious way if a plugin does not return a proto.
     405         389 :     RELEASE_ASSERT(config != nullptr, "");
     406             : 
     407             :     // Check that the config type is not google.protobuf.Empty
     408         389 :     RELEASE_ASSERT(config->GetTypeName() != "google.protobuf.Empty", "");
     409             : 
     410         389 :     translateOpaqueConfig(typed_config, validation_visitor, *config);
     411         389 :     return config;
     412         389 :   }
     413             : 
     414             :   /**
     415             :    * Truncates the message to a length less than default GRPC trailers size limit (by default 8KiB).
     416             :    */
     417             :   static std::string truncateGrpcStatusMessage(absl::string_view error_message);
     418             : 
     419             :   /**
     420             :    * Create TagProducer instance. Check all tag names for conflicts to avoid
     421             :    * unexpected tag name overwriting.
     422             :    * @param bootstrap bootstrap proto.
     423             :    * @param cli_tags tags that are provided by the cli
     424             :    * @throws EnvoyException when the conflict of tag names is found.
     425             :    */
     426             :   static Stats::TagProducerPtr
     427             :   createTagProducer(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
     428             :                     const Stats::TagVector& cli_tags);
     429             : 
     430             :   /**
     431             :    * Create StatsMatcher instance.
     432             :    */
     433             :   static Stats::StatsMatcherPtr
     434             :   createStatsMatcher(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
     435             :                      Stats::SymbolTable& symbol_table);
     436             : 
     437             :   /**
     438             :    * Create HistogramSettings instance.
     439             :    */
     440             :   static Stats::HistogramSettingsConstPtr
     441             :   createHistogramSettings(const envoy::config::bootstrap::v3::Bootstrap& bootstrap);
     442             : 
     443             :   /**
     444             :    * Obtain gRPC async client factory from a envoy::config::core::v3::ApiConfigSource.
     445             :    * @param async_client_manager gRPC async client manager.
     446             :    * @param api_config_source envoy::config::core::v3::ApiConfigSource. Must have config type GRPC.
     447             :    * @param skip_cluster_check whether to skip cluster validation.
     448             :    * @return Grpc::AsyncClientFactoryPtr gRPC async client factory.
     449             :    */
     450             :   static Grpc::AsyncClientFactoryPtr
     451             :   factoryForGrpcApiConfigSource(Grpc::AsyncClientManager& async_client_manager,
     452             :                                 const envoy::config::core::v3::ApiConfigSource& api_config_source,
     453             :                                 Stats::Scope& scope, bool skip_cluster_check);
     454             : 
     455             :   /**
     456             :    * Translate opaque config from google.protobuf.Any to defined proto message.
     457             :    * @param typed_config opaque config packed in google.protobuf.Any
     458             :    * @param validation_visitor message validation visitor instance.
     459             :    * @param out_proto the proto message instantiated by extensions
     460             :    */
     461             :   static void translateOpaqueConfig(const ProtobufWkt::Any& typed_config,
     462             :                                     ProtobufMessage::ValidationVisitor& validation_visitor,
     463             :                                     Protobuf::Message& out_proto);
     464             : 
     465             :   /**
     466             :    * Verify that any filter designed to be terminal is configured to be terminal, and vice versa.
     467             :    * @param name the name of the filter.
     468             :    * @param filter_type the type of filter.
     469             :    * @param filter_chain_type the type of filter chain.
     470             :    * @param is_terminal_filter true if the filter is designed to be terminal.
     471             :    * @param last_filter_in_current_config true if the filter is last in the configuration.
     472             :    * @throws EnvoyException if there is a mismatch between design and configuration.
     473             :    */
     474             :   static void validateTerminalFilters(const std::string& name, const std::string& filter_type,
     475             :                                       const std::string& filter_chain_type, bool is_terminal_filter,
     476         436 :                                       bool last_filter_in_current_config) {
     477         436 :     if (is_terminal_filter && !last_filter_in_current_config) {
     478           0 :       ExceptionUtil::throwEnvoyException(
     479           0 :           fmt::format("Error: terminal filter named {} of type {} must be the "
     480           0 :                       "last filter in a {} filter chain.",
     481           0 :                       name, filter_type, filter_chain_type));
     482         436 :     } else if (!is_terminal_filter && last_filter_in_current_config) {
     483           0 :       ExceptionUtil::throwEnvoyException(fmt::format(
     484           0 :           "Error: non-terminal filter named {} of type {} is the last filter in a {} filter chain.",
     485           0 :           name, filter_type, filter_chain_type));
     486           0 :     }
     487         436 :   }
     488             : 
     489             :   /**
     490             :    * Prepares the DNS failure refresh backoff strategy given the cluster configuration.
     491             :    * @param config the config that contains dns refresh information.
     492             :    * @param dns_refresh_rate_ms the default DNS refresh rate.
     493             :    * @param random the random generator.
     494             :    * @return BackOffStrategyPtr for scheduling refreshes.
     495             :    */
     496             :   template <typename T>
     497             :   static BackOffStrategyPtr prepareDnsRefreshStrategy(const T& config, uint64_t dns_refresh_rate_ms,
     498           0 :                                                       Random::RandomGenerator& random) {
     499           0 :     if (config.has_dns_failure_refresh_rate()) {
     500           0 :       uint64_t base_interval_ms =
     501           0 :           PROTOBUF_GET_MS_REQUIRED(config.dns_failure_refresh_rate(), base_interval);
     502           0 :       uint64_t max_interval_ms = PROTOBUF_GET_MS_OR_DEFAULT(config.dns_failure_refresh_rate(),
     503           0 :                                                             max_interval, base_interval_ms * 10);
     504           0 :       if (max_interval_ms < base_interval_ms) {
     505           0 :         ExceptionUtil::throwEnvoyException(
     506           0 :             "dns_failure_refresh_rate must have max_interval greater than "
     507           0 :             "or equal to the base_interval");
     508           0 :       }
     509           0 :       return std::make_unique<JitteredExponentialBackOffStrategy>(base_interval_ms, max_interval_ms,
     510           0 :                                                                   random);
     511           0 :     }
     512           0 :     return std::make_unique<FixedBackOffStrategy>(dns_refresh_rate_ms);
     513           0 :   }
     514             : 
     515             :   /**
     516             :    * Returns Jittered Exponential BackOff Strategy from BackoffStrategy config if present or
     517             :    * provided default timer values
     518             :    * @param api_config_source config
     519             :    * @param random random generator
     520             :    * @param default_base_interval_ms  Default base interval, must be > 0
     521             :    * @param default_max_interval_ms (optional) Default maximum interval
     522             :    * @return JitteredExponentialBackOffStrategyPtr if 1. Backoff Strategy is
     523             :    * found in the config or 2. default base interval and default maximum interval is specified or 3.
     524             :    * max interval is set to 10*default base interval
     525             :    */
     526             :   static JitteredExponentialBackOffStrategyPtr prepareJitteredExponentialBackOffStrategy(
     527             :       const envoy::config::core::v3::ApiConfigSource& api_config_source,
     528             :       Random::RandomGenerator& random, const uint32_t default_base_interval_ms,
     529          31 :       absl::optional<const uint32_t> default_max_interval_ms) {
     530           0 : 
     531          31 :     auto& grpc_services = api_config_source.grpc_services();
     532          31 :     if (!grpc_services.empty() && grpc_services[0].has_envoy_grpc()) {
     533          28 :       return prepareJitteredExponentialBackOffStrategy(
     534          28 :           grpc_services[0].envoy_grpc(), random, default_base_interval_ms, default_max_interval_ms);
     535          28 :     }
     536           3 :     return buildJitteredExponentialBackOffStrategy(absl::nullopt, random, default_base_interval_ms,
     537           3 :                                                    default_max_interval_ms);
     538          31 :   }
     539             : 
     540             :   /**
     541             :    * Prepares Jittered Exponential BackOff Strategy from config containing the Retry Policy
     542             :    * @param config config containing RetryPolicy <envoy_v3_api_msg_config.core.v3.RetryPolicy>
     543             :    * @param random random generator
     544             :    * @param default_base_interval_ms  Default base interval, must be > 0
     545             :    * @param default_max_interval_ms (optional) Default maximum interval
     546             :    * @return JitteredExponentialBackOffStrategyPtr if 1. RetryPolicy containing backoff values is
     547             :    * found in config or 2. default base interval and default maximum interval is specified or 3.
     548             :    * default max interval is set to 10*default base interval
     549             :    */
     550             :   template <typename T>
     551             :   static JitteredExponentialBackOffStrategyPtr prepareJitteredExponentialBackOffStrategy(
     552             :       const T& config, Random::RandomGenerator& random, const uint32_t default_base_interval_ms,
     553          28 :       absl::optional<const uint32_t> default_max_interval_ms) {
     554           0 :     // If RetryPolicy containing backoff values is found in config
     555          28 :     if (config.has_retry_policy() && config.retry_policy().has_retry_back_off()) {
     556           0 :       return buildJitteredExponentialBackOffStrategy(config.retry_policy().retry_back_off(), random,
     557           0 :                                                      default_base_interval_ms,
     558           0 :                                                      default_max_interval_ms);
     559           0 :     }
     560          28 :     return buildJitteredExponentialBackOffStrategy(absl::nullopt, random, default_base_interval_ms,
     561          28 :                                                    default_max_interval_ms);
     562          28 :   }
     563             : 
     564             : private:
     565             :   /**
     566             :    * Returns Jittered Exponential BackOff Strategy from BackoffStrategy config or default
     567             :    * values
     568             :    * @param config (optional) BackoffStrategy config
     569             :    * @param random random generator
     570             :    * @param default_base_interval_ms  Default base interval, must be > 0
     571             :    * @param default_max_interval_ms (optional) Default maximum interval
     572             :    * @return JitteredExponentialBackOffStrategyPtr if 1. Backoff Strategy is
     573             :    * specified or 2. default base interval and default maximum interval is specified or 3.
     574             :    * max interval is set to 10*default base interval
     575             :    */
     576             :   static JitteredExponentialBackOffStrategyPtr buildJitteredExponentialBackOffStrategy(
     577             :       absl::optional<const envoy::config::core::v3::BackoffStrategy> backoff,
     578             :       Random::RandomGenerator& random, const uint32_t default_base_interval_ms,
     579             :       absl::optional<const uint32_t> default_max_interval_ms);
     580             : };
     581             : } // namespace Config
     582             : } // namespace Envoy

Generated by: LCOV version 1.15