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
|