-
Notifications
You must be signed in to change notification settings - Fork 5.4k
http fault: implement header controlled faults #6318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
b34e7ff
2bc39f5
97f2905
7def5ef
eda7fa8
92cfdd6
606a364
c6ea7fc
70506d1
574385b
a79a8b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,15 +16,6 @@ The scope of failures is restricted to those that are observable by an | |
| application communicating over the network. CPU and disk failures on the | ||
| local host cannot be emulated. | ||
|
|
||
| Currently, the fault injection filter has the following limitations: | ||
|
|
||
| * Abort codes are restricted to HTTP status codes only | ||
| * Delays are restricted to fixed duration. | ||
|
|
||
| Future versions will include support for restricting faults to specific | ||
| routes, injecting *gRPC* and *HTTP/2* specific error codes and delay | ||
| durations based on distributions. | ||
|
|
||
| Configuration | ||
| ------------- | ||
|
|
||
|
|
@@ -36,6 +27,44 @@ Configuration | |
| * :ref:`v2 API reference <envoy_api_msg_config.filter.http.fault.v2.HTTPFault>` | ||
| * This filter should be configured with the name *envoy.fault*. | ||
|
|
||
| .. _config_http_filters_fault_injection_http_header: | ||
|
|
||
| Controlling fault injection via HTTP headers | ||
| -------------------------------------------- | ||
|
|
||
| The fault filter has the capability to allow fault configuration to be specified by the caller. | ||
| This is useful in certain scenarios in which it is desired to allow the client to specify its own | ||
| fault configuration. The currently supported header controls are: | ||
|
|
||
| * Request delay configuration via the *x-envoy-fault-delay-request* header. The header value | ||
| should be an integer that specifies the number of milliseconds to throttle the latency for. | ||
|
mattklein123 marked this conversation as resolved.
|
||
| * Response rate limit configuration via the *x-envoy-fault-throughput-response* header. The | ||
| header value should be an integer that specified the limit in KiB/s and must be > 0. | ||
|
mattklein123 marked this conversation as resolved.
|
||
|
|
||
| .. attention:: | ||
|
|
||
| Allowing header control is inherently dangerous if exposed to untrusted clients. In this case, | ||
| it is suggested to use the :ref:`max_active_faults | ||
| <envoy_api_field_config.filter.http.fault.v2.HTTPFault.max_active_faults>` setting to limit the | ||
| maximum concurrent faults that can be active at any given time. | ||
|
|
||
| The following is an example configuration that enables header control for both of the above | ||
| options: | ||
|
|
||
| .. code-block:: yaml | ||
|
|
||
| name: envoy.fault | ||
| config: | ||
| max_active_faults: 100 | ||
| delay: | ||
| header_delay: {} | ||
| percentage: | ||
| numerator: 100 | ||
| response_rate_limit: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. per previous discussion, i suggest cutting the percentage here and opting for a semantic like, "if you specify delay, it will be injected with 100% certainty". That would make it easier for people to test, imo
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above comment. |
||
| header_limit: {} | ||
| percentage: | ||
| numerator: 100 | ||
|
|
||
| .. _config_http_filters_fault_injection_runtime: | ||
|
|
||
| Runtime | ||
|
mattklein123 marked this conversation as resolved.
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| licenses(["notice"]) # Apache 2 | ||
|
|
||
| load( | ||
| "//bazel:envoy_build_system.bzl", | ||
| "envoy_cc_library", | ||
| "envoy_package", | ||
| ) | ||
|
|
||
| envoy_package() | ||
|
|
||
| envoy_cc_library( | ||
| name = "fault_config_lib", | ||
| srcs = ["fault_config.cc"], | ||
| hdrs = ["fault_config.h"], | ||
| deps = [ | ||
| "//include/envoy/http:header_map_interface", | ||
| "//source/common/protobuf:utility_lib", | ||
| "@envoy_api//envoy/config/filter/fault/v2:fault_cc", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| #include "extensions/filters/common/fault/fault_config.h" | ||
|
|
||
| #include "common/protobuf/utility.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Extensions { | ||
| namespace Filters { | ||
| namespace Common { | ||
| namespace Fault { | ||
|
|
||
| FaultDelayConfig::FaultDelayConfig(const envoy::config::filter::fault::v2::FaultDelay& delay_config) | ||
| : percentage_(delay_config.percentage()) { | ||
| switch (delay_config.fault_delay_secifier_case()) { | ||
| case envoy::config::filter::fault::v2::FaultDelay::kFixedDelay: | ||
| provider_ = std::make_unique<FixedDelayProvider>( | ||
| std::chrono::milliseconds(PROTOBUF_GET_MS_REQUIRED(delay_config, fixed_delay))); | ||
| break; | ||
| case envoy::config::filter::fault::v2::FaultDelay::kHeaderDelay: | ||
| provider_ = std::make_unique<HeaderDelayProvider>(); | ||
| break; | ||
| case envoy::config::filter::fault::v2::FaultDelay::FAULT_DELAY_SECIFIER_NOT_SET: | ||
| NOT_REACHED_GCOVR_EXCL_LINE; | ||
| } | ||
| } | ||
|
|
||
| absl::optional<std::chrono::milliseconds> | ||
| FaultDelayConfig::HeaderDelayProvider::duration(const Http::HeaderEntry* header) const { | ||
| if (header == nullptr) { | ||
| return absl::nullopt; | ||
| } | ||
|
|
||
| uint64_t value; | ||
| if (!StringUtil::atoull(header->value().getStringView().data(), value)) { | ||
| return absl::nullopt; | ||
| } | ||
|
|
||
| return std::chrono::milliseconds(value); | ||
| } | ||
|
|
||
| FaultRateLimitConfig::FaultRateLimitConfig( | ||
| const envoy::config::filter::fault::v2::FaultRateLimit& rate_limit_config) | ||
| : percentage_(rate_limit_config.percentage()) { | ||
| switch (rate_limit_config.limit_type_case()) { | ||
| case envoy::config::filter::fault::v2::FaultRateLimit::kFixedLimit: | ||
| provider_ = | ||
| std::make_unique<FixedRateLimitProvider>(rate_limit_config.fixed_limit().limit_kbps()); | ||
| break; | ||
| case envoy::config::filter::fault::v2::FaultRateLimit::kHeaderLimit: | ||
| provider_ = std::make_unique<HeaderRateLimitProvider>(); | ||
| break; | ||
| case envoy::config::filter::fault::v2::FaultRateLimit::LIMIT_TYPE_NOT_SET: | ||
| NOT_REACHED_GCOVR_EXCL_LINE; | ||
| } | ||
| } | ||
|
|
||
| absl::optional<uint64_t> | ||
| FaultRateLimitConfig::HeaderRateLimitProvider::rateKbps(const Http::HeaderEntry* header) const { | ||
| if (header == nullptr) { | ||
| return absl::nullopt; | ||
| } | ||
|
|
||
| uint64_t value; | ||
| if (!StringUtil::atoull(header->value().getStringView().data(), value)) { | ||
| return absl::nullopt; | ||
| } | ||
|
|
||
| if (value == 0) { | ||
| return absl::nullopt; | ||
| } | ||
|
|
||
| return value; | ||
| } | ||
|
|
||
| } // namespace Fault | ||
| } // namespace Common | ||
| } // namespace Filters | ||
| } // namespace Extensions | ||
| } // namespace Envoy |
Uh oh!
There was an error while loading. Please reload this page.