Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
2894271
Redis fault injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 15, 2020
827f332
format fix
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 15, 2020
4d83a32
fix build issues
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 15, 2020
99aace9
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 15, 2020
780bd44
formatting
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 15, 2020
b67b102
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 20, 2020
9679b33
fix docs and proto
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 20, 2020
b1a08f2
Respond to comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 22, 2020
6f472a1
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 22, 2020
46325db
fix conflict
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 22, 2020
6f0c543
fix docs link
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Apr 23, 2020
abcaa1b
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 1, 2020
b1c2a08
respond to comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 1, 2020
e7afabf
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 4, 2020
ef0545a
try separating out no fault case to fix test
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 6, 2020
03f8238
Revert "try separating out no fault case to fix test"
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 6, 2020
23ad135
Tidy up test and default actions
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 6, 2020
62ae483
try something else
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 7, 2020
412b74c
remove new tests, see if they are the issue
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 7, 2020
88e2ae3
add command splitter null response
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 7, 2020
7a86b58
respond to henry comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 7, 2020
38bbbc7
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 7, 2020
4c80aa2
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 8, 2020
23db915
remove faults again
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 8, 2020
c4339c1
try defaulting for all tests
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 9, 2020
f8dc205
remove fault code, see if that works and work backward
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 10, 2020
86f2289
remove even more stuff from command splitter
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 10, 2020
253d6a3
remove any trace of fault work for command splitter
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 11, 2020
375ce5d
clang tidy
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 11, 2020
20e52a9
Revert "remove any trace of fault work for command splitter"
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 11, 2020
7f09ce6
set delay to false explicitly
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 11, 2020
6f0f82b
add stuff back in
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 13, 2020
e62cd46
Merge branch 'master' of github.com:HenryYYang/envoy into redis-fault…
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 13, 2020
aa561ab
fix clang tidy
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 13, 2020
a593eb5
fix clang tidy
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 13, 2020
b839bda
Update per Henry comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 14, 2020
eae5c0f
Merge branch 'redis-fault-injection' of github.com:HenryYYang/envoy i…
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 14, 2020
76d07f9
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 14, 2020
c9483a5
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 14, 2020
0ea8739
fix clang tidy
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 14, 2020
da490cf
Respond to henry comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 19, 2020
0aa369c
fix tidy issue
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg May 19, 2020
b678124
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 1, 2020
37a2901
respond to mklein comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 1, 2020
eac80ba
Update dispatcher and tests
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 9, 2020
a952625
fix memory leak
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 18, 2020
73aadf4
fix tests
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 18, 2020
68fb506
Merge branch 'master' of github.com:HenryYYang/envoy into redis-fault…
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 18, 2020
c310d9b
format
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 18, 2020
d429faa
Merge branch 'master' of github.com:HenryYYang/envoy into redis-fault…
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 22, 2020
abe5a0a
Update version history
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 22, 2020
0b62a99
fix ambigious getInteger call
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 22, 2020
b7f8486
add matcher to tests with getInteger wildcard
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 23, 2020
638d2d8
fix one more test
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 23, 2020
0667411
attempt to fix CI redis_integration_test failure in linux env
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 23, 2020
c963fec
Remove timer destruction
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 24, 2020
b26d949
Merge branch 'master' of github.com:HenryYYang/envoy into redis-fault…
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 24, 2020
1f5bd06
add new auth method to delay fault
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 24, 2020
03cef03
add new auth method to delay fault
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 24, 2020
8eac747
Merge branch 'redis-fault-injection' of github.com:HenryYYang/envoy i…
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 24, 2020
bf3d97f
Add test coverage for test helper
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 24, 2020
5877bb5
fix clang-tidy issues
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 25, 2020
d0c19a2
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 25, 2020
c6a720e
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 26, 2020
8190e8c
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 27, 2020
a03c392
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jun 27, 2020
7603989
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 1, 2020
9d03016
Respond to comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 1, 2020
b5ccc44
use factory for command splitter creation
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 10, 2020
2db0f8a
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 10, 2020
83b278f
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 11, 2020
474af56
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 12, 2020
37db613
fix memory leak
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 12, 2020
8805ae7
add override keyword
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 12, 2020
b63cbf9
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 12, 2020
5f7544d
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 12, 2020
7b4ca69
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 13, 2020
6bc4aa5
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 13, 2020
a58ef91
Kick CI
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 13, 2020
b4e6357
add dispatcher to timer see if fixes CI issue
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 13, 2020
873c093
add other dispatcher
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 13, 2020
8befff3
increase shards to 2 for test for tsan
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 14, 2020
3c14dbe
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 14, 2020
b67b1c7
Fix command_splitter_impl_test
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 15, 2020
0708bbd
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 15, 2020
829d8a0
respond to mklein comments
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 15, 2020
0404ef0
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 15, 2020
3c33eb1
Move fault amortization back into fault code
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 16, 2020
f61db6f
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 17, 2020
c29ae1a
Merge branch 'master' into redis-fault-injection
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 17, 2020
20ad1ca
fix comment
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 17, 2020
48e5c67
fix clang tidy
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg Jul 17, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Redis Proxy :ref:`configuration overview <config_network_filters_redis_proxy>`.
// [#extension: envoy.filters.network.redis_proxy]

// [#next-free-field: 7]
// [#next-free-field: 8]
message RedisProxy {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.network.redis_proxy.v2.RedisProxy";
Expand Down Expand Up @@ -182,6 +182,32 @@ message RedisProxy {
Route catch_all_route = 4;
}

// RedisFault defines faults used for fault injection.
message RedisFault {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.network.redis_proxy.v2.RedisProxy.RedisFault";
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated

enum RedisFaultType {
// Delays requests. This is the base fault; other faults can have delays added.
DELAY = 0;

// Returns errors on requests.
ERROR = 1;
}

// Fault type.
RedisFaultType fault_type = 1 [(validate.rules).enum = {defined_only: true}];

// Percentage of requests fault applies to.
Comment thread
mattklein123 marked this conversation as resolved.
config.core.v3.RuntimeFractionalPercent fault_enabled = 2;

// Delay for all faults. If not set, defaults to zero
google.protobuf.Duration delay = 3;

// Commands fault is restricted to, if any.
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
repeated string commands = 4;
}

reserved 2;

reserved "cluster";
Expand Down Expand Up @@ -234,6 +260,35 @@ message RedisProxy {
// client. If an AUTH command is received when the password is not set, then an "ERR Client sent
// AUTH, but no password is set" error will be returned.
config.core.v3.DataSource downstream_auth_password = 6 [(udpa.annotations.sensitive) = true];

// List of faults to inject. Faults currently come in two flavors:
// - Delay, which delays a request.
// - Error, which responds to a request with an error. Errors can also have delays attached.
//
// Example:
//
// .. code-block:: yaml
//
// faults:
// - fault_type: ERROR
// fault_enabled:
// default_value:
// numerator: 10
// denominator: HUNDRED
// runtime_key: "bogus_key"
// commands:
// - GET
// - fault_type: DELAY
// fault_enabled:
// default_value:
// numerator: 10
// denominator: HUNDRED
// runtime_key: "bogus_key"
// delay: 2s
//
// See the :ref:`fault injection section
// <config_network_filters_redis_proxy_fault_injection>` for more information on how to configure this.
repeated RedisFault faults = 7;
}

// RedisProtocolOptions specifies Redis upstream protocol options. This object is used in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ changed to microseconds by setting the configuration parameter :ref:`latency_in_
total, Counter, Number of commands
success, Counter, Number of commands that were successful
error, Counter, Number of commands that returned a partial or complete error response
latency, Histogram, Command execution time in milliseconds
latency, Histogram, Command execution time in milliseconds (including delay faults)
error_fault, Counter, Number of commands that had an error fault injected
delay_fault, Counter, Number of commands that had a delay fault injected

.. _config_network_filters_redis_proxy_per_command_stats:

Expand All @@ -70,3 +72,16 @@ The Redis proxy filter supports the following runtime settings:
redis.drain_close_enabled
% of connections that will be drain closed if the server is draining and would otherwise
attempt a drain close. Defaults to 100.

.. _config_network_filters_redis_proxy_fault_injection:

Fault Injection
---------------

The Redis filter can perform fault injection. Currently, Delay and Error faults are supported.
Delay faults delay a request, and Error faults respond with an error. Moreover, errors can be delayed.

Note that if a delay is injected, the delay is additive- if the request took 400ms and a delay of 100ms
is injected, then the total request latency is 500ms. Also, due to implementation of the redis proxy,
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
a delayed request will delay everything that comes in after it, due to the proxy's need to respect the
order of commands it receives.
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Changes
`envoy.reloadable_features.new_http2_connection_pool_behavior`.
* logger: added :ref:`--log-format-prefix-with-location <operations_cli>` command line option to prefix '%v' with file path and line number.
* network filters: added a :ref:`postgres proxy filter <config_network_filters_postgres_proxy>`.
* redis fault injection: added :ref:`fault injection for redis proxy <envoy_v3_api_field_extensions.filters.network.redis_proxy.v3.RedisProxy.faults>`, described further in :ref:`configuration documentation <config_network_filters_redis_proxy>`.
* request_id: added to :ref:`always_set_request_id_in_response setting <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.always_set_request_id_in_response>`
to set :ref:`x-request-id <config_http_conn_man_headers_x-request-id>` header in response even if
tracing is not forced.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions source/extensions/filters/network/common/redis/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,22 @@ envoy_cc_library(
"//source/common/stats:timespan_lib",
],
)

envoy_cc_library(
name = "fault_interface",
hdrs = ["fault.h"],
deps = [],
)

envoy_cc_library(
name = "fault_lib",
srcs = ["fault_impl.cc"],
hdrs = ["fault_impl.h"],
deps = [
":codec_lib",
":fault_interface",
"//include/envoy/upstream:upstream_interface",
"//source/common/protobuf:utility_lib",
"@envoy_api//envoy/extensions/filters/network/redis_proxy/v3:pkg_cc_proto",
],
)
36 changes: 36 additions & 0 deletions source/extensions/filters/network/common/redis/fault.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <string>

#include "envoy/api/api.h"

namespace Envoy {
namespace Extensions {
namespace NetworkFilters {
namespace Common {
namespace Redis {

/**
* Fault Type.
*/
enum class FaultType { Delay, Error };

class FaultManager {
public:
virtual ~FaultManager() = default;

/**
* Get fault type and delay given a Redis command.
* @param command supplies the Redis command string.
*/
virtual absl::optional<std::pair<FaultType, std::chrono::milliseconds>>
getFaultForCommand(std::string command) PURE;
};

using FaultManagerPtr = std::shared_ptr<FaultManager>;
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated

} // namespace Redis
} // namespace Common
} // namespace NetworkFilters
} // namespace Extensions
} // namespace Envoy
141 changes: 141 additions & 0 deletions source/extensions/filters/network/common/redis/fault_impl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "extensions/filters/network/common/redis/fault_impl.h"

namespace Envoy {
namespace Extensions {
namespace NetworkFilters {
namespace Common {
namespace Redis {

Fault::Fault(envoy::extensions::filters::network::redis_proxy::v3::RedisProxy_RedisFault base_fault)
: commands_(getCommands(base_fault)) {
// // Get delay
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
delay_ms_ = std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(base_fault, delay, 0));

// Get fault type
switch (base_fault.fault_type()) {
case envoy::extensions::filters::network::redis_proxy::v3::RedisProxy::RedisFault::DELAY:
fault_type_ = FaultType::Delay;
break;
case envoy::extensions::filters::network::redis_proxy::v3::RedisProxy::RedisFault::ERROR:
fault_type_ = FaultType::Error;
break;
default:
NOT_REACHED_GCOVR_EXCL_LINE;
break;
}

// Get the default value/runtime key
if (base_fault.has_fault_enabled()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this means if fault_enabled is not set, it's disabled, right? Please update documentation for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted from earlier discussions and have an open todo. Focusing on figuring out why tests fail in CI and not local first.

has_fault_enabled_ = true;
if (base_fault.fault_enabled().has_default_value()) {
if (base_fault.fault_enabled().default_value().denominator() ==
envoy::type::v3::FractionalPercent::HUNDRED) {
default_value_ = base_fault.fault_enabled().default_value().numerator();
} else {
auto denominator = ProtobufPercentHelper::fractionalPercentDenominatorToInt(
base_fault.fault_enabled().default_value().denominator());
default_value_ =
(base_fault.fault_enabled().default_value().numerator() * 100) / denominator;
}
}
runtime_key_ = base_fault.fault_enabled().runtime_key();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this code is needed, you should just use FractionalPercent which wraps RuntimeFractionalPercent

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runtime_.snapshot().getInteger(...) takes the default value as int, like most of the other featureEnabled(...) methods. The featureEnabled(...) methods that take a FractionalPercent default value return a boolean, which doesn't tell us what our amortized probability is. Then, we'd need to do the calculation for the amortized percentage with a check on the denominator.

}
};

std::vector<std::string> Fault::getCommands(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this is a redundant value copying, is this only used for initializing the commands_ field?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, this only for initialization. We want to make all the commands lowercase, hence the method. Would you prefer the lowercasing be a linter check?

envoy::extensions::filters::network::redis_proxy::v3::RedisProxy_RedisFault base_fault) {
std::vector<std::string> commands;
for (auto command : base_fault.commands()) {
commands.emplace_back(absl::AsciiStrToLower(command));
}
return commands;
}

FaultManagerImpl::FaultManagerImpl(
Runtime::RandomGenerator& random, Runtime::Loader& runtime,
const Protobuf::RepeatedPtrField<
::envoy::extensions::filters::network::redis_proxy::v3::RedisProxy_RedisFault>
faults)
: random_(random), runtime_(runtime) {

// Next, create the fault map that maps commands to pointers to Fault objects.
// Group faults by command
for (auto base_fault : faults) {
auto fault_ptr = std::make_shared<Fault>(base_fault);
if (fault_ptr->commands_.size() > 0) {
for (std::string command : fault_ptr->commands_) {
fault_map_[command].push_back(fault_ptr);
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
}
} else {
// Generic "ALL" entry in map for faults that map to all keys; also add to each command
fault_map_[ALL_KEY].push_back(fault_ptr);
}
}

// Add the ALL keys faults to each command too so that we can just query faults by command.
// Get all ALL_KEY faults.
FaultMap::iterator it_outer = fault_map_.find(ALL_KEY);
if (it_outer != fault_map_.end()) {
// For each ALL_KEY fault...
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
for (auto fault_ptr : it_outer->second) {
// Loop through all unique commands other than ALL_KEY and add the fault.
FaultMap::iterator it_inner;
for (it_inner = fault_map_.begin(); it_inner != fault_map_.end(); it_inner++) {
std::string command = it_inner->first;
if (command != ALL_KEY) {
fault_map_[command].push_back(fault_ptr);
}
}
}
}
}

// Fault checking algorithm:
//
// For example, if we have an ERROR fault at 5% for all commands, and a DELAY fault at 10% for GET,
// if we receive a GET, we want 5% of GETs to get DELAY, and 5% to get ERROR. Thus, we need to
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
// amortize the percentages.
//
// 0. Get random number.
// 1. Get faults for given command.s
Comment thread
FAYiEKcbD0XFqF2QK2E4viAHg8rMm2VbjYKdjTg marked this conversation as resolved.
Outdated
// 2. For each fault, calculate the amortized fault injection percentage.
absl::optional<std::pair<FaultType, std::chrono::milliseconds>>
FaultManagerImpl::getFaultForCommandInternal(std::string command) {
auto random_number = random_.random() % 100;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create the random number only if we have a matching command. Also what do we do if the fault_injection_percentage adds up higher than 100?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I was under the impression we were going to treat that as user error. I'll add that to the documentation section.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we checking for this user error anywhere?

int amortized_fault = 0;

FaultMap::iterator it_outer = fault_map_.find(command);
if (it_outer != fault_map_.end()) {
for (auto fault_ptr : it_outer->second) {
auto fault_injection_percentage = runtime_.snapshot().getInteger(
fault_ptr->runtime_key_.value(), fault_ptr->default_value_.value());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would calling value() on an unset optional throw exception here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call- I'll add a check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll also add a test.

if (random_number < (fault_injection_percentage + amortized_fault)) {
return std::make_pair(fault_ptr->fault_type_, fault_ptr->delay_ms_);
} else {
amortized_fault += fault_injection_percentage;
}
}
}

return absl::nullopt;
}

absl::optional<std::pair<FaultType, std::chrono::milliseconds>>
FaultManagerImpl::getFaultForCommand(std::string command) {
// Check if faults exist for given command; else use ALL_KEY and search for general faults.
if (!fault_map_.empty()) {
if (fault_map_.count(command) > 0) {
return getFaultForCommandInternal(command);
} else {
return getFaultForCommandInternal(ALL_KEY);
}
}

return absl::nullopt;
}

} // namespace Redis
} // namespace Common
} // namespace NetworkFilters
} // namespace Extensions
} // namespace Envoy
Loading