Enabling Ring Hash by default. (#27111)

pull/27119/head
donnadionne 4 years ago committed by GitHub
parent 420a98f96b
commit 59fc02a94b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 149
      src/core/ext/xds/xds_api.cc
  2. 40
      test/cpp/end2end/xds_end2end_test.cc

@ -115,17 +115,6 @@ bool XdsAggregateAndLogicalDnsClusterEnabled() {
return parse_succeeded && parsed_value;
}
// TODO(donnadionne): Check to see if ring hash policy is enabled, this will be
// removed once ring hash policy is fully integration-tested and enabled by
// default.
bool XdsRingHashEnabled() {
char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
bool parsed_value;
bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
gpr_free(value);
return parse_succeeded && parsed_value;
}
// TODO(yashykt): Check to see if xDS security is enabled. This will be
// removed once this feature is fully integration-tested and enabled by
// default.
@ -1749,81 +1738,78 @@ grpc_error_handle RouteActionParse(const EncodingContext& context,
}
}
// Get HashPolicy from RouteAction
if (XdsRingHashEnabled()) {
size_t size = 0;
const envoy_config_route_v3_RouteAction_HashPolicy* const* hash_policies =
envoy_config_route_v3_RouteAction_hash_policy(route_action, &size);
for (size_t i = 0; i < size; ++i) {
const envoy_config_route_v3_RouteAction_HashPolicy* hash_policy =
hash_policies[i];
XdsApi::Route::HashPolicy policy;
policy.terminal =
envoy_config_route_v3_RouteAction_HashPolicy_terminal(hash_policy);
const envoy_config_route_v3_RouteAction_HashPolicy_Header* header;
const envoy_config_route_v3_RouteAction_HashPolicy_FilterState*
filter_state;
if ((header = envoy_config_route_v3_RouteAction_HashPolicy_header(
hash_policy)) != nullptr) {
policy.type = XdsApi::Route::HashPolicy::Type::HEADER;
policy.header_name = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_Header_header_name(
header));
const struct envoy_type_matcher_v3_RegexMatchAndSubstitute*
regex_rewrite =
envoy_config_route_v3_RouteAction_HashPolicy_Header_regex_rewrite(
header);
if (regex_rewrite != nullptr) {
const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
envoy_type_matcher_v3_RegexMatchAndSubstitute_pattern(
regex_rewrite);
if (regex_matcher == nullptr) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern is "
"missing");
continue;
}
RE2::Options options;
policy.regex = absl::make_unique<RE2>(
UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher)),
options);
if (!policy.regex->ok()) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern does not "
"compile");
continue;
}
policy.regex_substitution = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatchAndSubstitute_substitution(
regex_rewrite));
size_t size = 0;
const envoy_config_route_v3_RouteAction_HashPolicy* const* hash_policies =
envoy_config_route_v3_RouteAction_hash_policy(route_action, &size);
for (size_t i = 0; i < size; ++i) {
const envoy_config_route_v3_RouteAction_HashPolicy* hash_policy =
hash_policies[i];
XdsApi::Route::HashPolicy policy;
policy.terminal =
envoy_config_route_v3_RouteAction_HashPolicy_terminal(hash_policy);
const envoy_config_route_v3_RouteAction_HashPolicy_Header* header;
const envoy_config_route_v3_RouteAction_HashPolicy_FilterState*
filter_state;
if ((header = envoy_config_route_v3_RouteAction_HashPolicy_header(
hash_policy)) != nullptr) {
policy.type = XdsApi::Route::HashPolicy::Type::HEADER;
policy.header_name = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_Header_header_name(
header));
const struct envoy_type_matcher_v3_RegexMatchAndSubstitute*
regex_rewrite =
envoy_config_route_v3_RouteAction_HashPolicy_Header_regex_rewrite(
header);
if (regex_rewrite != nullptr) {
const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
envoy_type_matcher_v3_RegexMatchAndSubstitute_pattern(
regex_rewrite);
if (regex_matcher == nullptr) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern is "
"missing");
continue;
}
} else if ((filter_state =
envoy_config_route_v3_RouteAction_HashPolicy_filter_state(
hash_policy)) != nullptr) {
std::string key = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_FilterState_key(
filter_state));
if (key == "io.grpc.channel_id") {
policy.type = XdsApi::Route::HashPolicy::Type::CHANNEL_ID;
} else {
gpr_log(GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier "
"FilterState but "
"key is not io.grpc.channel_id.");
RE2::Options options;
policy.regex = absl::make_unique<RE2>(
UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher)),
options);
if (!policy.regex->ok()) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern does not "
"compile");
continue;
}
policy.regex_substitution = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatchAndSubstitute_substitution(
regex_rewrite));
}
} else if ((filter_state =
envoy_config_route_v3_RouteAction_HashPolicy_filter_state(
hash_policy)) != nullptr) {
std::string key = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_FilterState_key(
filter_state));
if (key == "io.grpc.channel_id") {
policy.type = XdsApi::Route::HashPolicy::Type::CHANNEL_ID;
} else {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains unsupported policy specifier.");
gpr_log(GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier "
"FilterState but "
"key is not io.grpc.channel_id.");
continue;
}
route->hash_policies.emplace_back(std::move(policy));
} else {
gpr_log(GPR_DEBUG,
"RouteAction HashPolicy contains unsupported policy specifier.");
continue;
}
route->hash_policies.emplace_back(std::move(policy));
}
// Get retry policy
const envoy_config_route_v3_RetryPolicy* retry_policy =
@ -3232,9 +3218,8 @@ grpc_error_handle CdsResponseParse(
if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
cds_update.lb_policy = "ROUND_ROBIN";
} else if (XdsRingHashEnabled() &&
envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
envoy_config_cluster_v3_Cluster_RING_HASH) {
} else if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
envoy_config_cluster_v3_Cluster_RING_HASH) {
cds_update.lb_policy = "RING_HASH";
// Record ring hash lb config
auto* ring_hash_config =

@ -7314,7 +7314,6 @@ TEST_P(CdsTest, WrongLrsServer) {
// Tests that ring hash policy that hashes using channel id ensures all RPCs
// to go 1 particular backend.
TEST_P(CdsTest, RingHashChannelIdHashing) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7340,13 +7339,11 @@ TEST_P(CdsTest, RingHashChannelIdHashing) {
}
}
EXPECT_TRUE(found);
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Tests that ring hash policy that hashes using a header value can spread
// RPCs across all the backends.
TEST_P(CdsTest, RingHashHeaderHashing) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7387,13 +7384,11 @@ TEST_P(CdsTest, RingHashHeaderHashing) {
for (size_t i = 0; i < backends_.size(); ++i) {
EXPECT_EQ(100, backends_[i]->backend_service()->request_count());
}
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Tests that ring hash policy that hashes using a header value and regex
// rewrite to aggregate RPCs to 1 backend.
TEST_P(CdsTest, RingHashHeaderHashingWithRegexRewrite) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7440,12 +7435,10 @@ TEST_P(CdsTest, RingHashHeaderHashingWithRegexRewrite) {
}
}
EXPECT_TRUE(found);
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Tests that ring hash policy that hashes using a random value.
TEST_P(CdsTest, RingHashNoHashPolicy) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const double kDistribution50Percent = 0.5;
const double kErrorTolerance = 0.05;
const uint32_t kRpcTimeoutMs = 10000;
@ -7473,13 +7466,11 @@ TEST_P(CdsTest, RingHashNoHashPolicy) {
::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
EXPECT_THAT(static_cast<double>(request_count_2) / kNumRpcs,
::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test that ring hash policy evaluation will continue past the terminal
// policy if no results are produced yet.
TEST_P(CdsTest, RingHashContinuesPastTerminalPolicyThatDoesNotProduceResult) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7502,13 +7493,11 @@ TEST_P(CdsTest, RingHashContinuesPastTerminalPolicyThatDoesNotProduceResult) {
CheckRpcSendOk(100, rpc_options);
EXPECT_EQ(backends_[0]->backend_service()->request_count(), 100);
EXPECT_EQ(backends_[1]->backend_service()->request_count(), 0);
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test random hash is used when header hashing specified a header field that
// the RPC did not have.
TEST_P(CdsTest, RingHashOnHeaderThatIsNotPresent) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const double kDistribution50Percent = 0.5;
const double kErrorTolerance = 0.05;
const uint32_t kRpcTimeoutMs = 10000;
@ -7545,13 +7534,11 @@ TEST_P(CdsTest, RingHashOnHeaderThatIsNotPresent) {
::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
EXPECT_THAT(static_cast<double>(request_count_2) / kNumRpcs,
::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test random hash is used when only unsupported hash policies are
// configured.
TEST_P(CdsTest, RingHashUnsupportedHashPolicyDefaultToRandomHashing) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const double kDistribution50Percent = 0.5;
const double kErrorTolerance = 0.05;
const uint32_t kRpcTimeoutMs = 10000;
@ -7590,13 +7577,11 @@ TEST_P(CdsTest, RingHashUnsupportedHashPolicyDefaultToRandomHashing) {
::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
EXPECT_THAT(static_cast<double>(request_count_2) / kNumRpcs,
::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Tests that ring hash policy that hashes using a random value can spread
// RPCs across all the backends according to locality weight.
TEST_P(CdsTest, RingHashRandomHashingDistributionAccordingToEndpointWeight) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const size_t kWeight1 = 1;
const size_t kWeight2 = 2;
const size_t kWeightTotal = kWeight1 + kWeight2;
@ -7632,14 +7617,12 @@ TEST_P(CdsTest, RingHashRandomHashingDistributionAccordingToEndpointWeight) {
::testing::DoubleNear(kWeight33Percent, kErrorTolerance));
EXPECT_THAT(static_cast<double>(weight_66_request_count) / kNumRpcs,
::testing::DoubleNear(kWeight66Percent, kErrorTolerance));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Tests that ring hash policy that hashes using a random value can spread
// RPCs across all the backends according to locality weight.
TEST_P(CdsTest,
RingHashRandomHashingDistributionAccordingToLocalityAndEndpointWeight) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const size_t kWeight1 = 1 * 1;
const size_t kWeight2 = 2 * 2;
const size_t kWeightTotal = kWeight1 + kWeight2;
@ -7674,7 +7657,6 @@ TEST_P(CdsTest,
::testing::DoubleNear(kWeight20Percent, kErrorTolerance));
EXPECT_THAT(static_cast<double>(weight_80_request_count) / kNumRpcs,
::testing::DoubleNear(kWeight80Percent, kErrorTolerance));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Tests round robin is not implacted by the endpoint weight, and that the
@ -7724,7 +7706,6 @@ TEST_P(CdsTest, RingHashEndpointWeightDoesNotImpactWeightedRoundRobin) {
// RPCs to go 1 particular backend; and that subsequent hashing policies are
// ignored due to the setting of terminal.
TEST_P(CdsTest, RingHashFixedHashingTerminalPolicy) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7758,14 +7739,12 @@ TEST_P(CdsTest, RingHashFixedHashingTerminalPolicy) {
}
}
EXPECT_TRUE(found);
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test that the channel will go from idle to ready via connecting;
// (tho it is not possible to catch the connecting state before moving to
// ready)
TEST_P(CdsTest, RingHashIdleToReady) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7783,13 +7762,11 @@ TEST_P(CdsTest, RingHashIdleToReady) {
EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false));
CheckRpcSendOk();
EXPECT_EQ(GRPC_CHANNEL_READY, channel_->GetState(false));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test that when the first pick is down leading to a transient failure, we
// will move on to the next ring hash entry.
TEST_P(CdsTest, RingHashTransientFailureCheckNextOne) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7816,14 +7793,12 @@ TEST_P(CdsTest, RingHashTransientFailureCheckNextOne) {
CheckRpcSendOk(100, rpc_options);
EXPECT_EQ(0, backends_[0]->backend_service()->request_count());
EXPECT_EQ(100, backends_[1]->backend_service()->request_count());
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test that when a backend goes down, we will move on to the next subchannel
// (with a lower priority). When the backend comes back up, traffic will move
// back.
TEST_P(CdsTest, RingHashSwitchToLowerPrioirtyAndThenBack) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7853,12 +7828,10 @@ TEST_P(CdsTest, RingHashSwitchToLowerPrioirtyAndThenBack) {
CheckRpcSendOk(100, rpc_options);
EXPECT_EQ(100, backends_[0]->backend_service()->request_count());
EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test that when all backends are down, we will keep reattempting.
TEST_P(CdsTest, RingHashAllFailReattempt) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const uint32_t kConnectionTimeoutMilliseconds = 5000;
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
@ -7887,13 +7860,11 @@ TEST_P(CdsTest, RingHashAllFailReattempt) {
// Ensure we are actively connecting without any traffic.
EXPECT_TRUE(channel_->WaitForConnected(
grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds)));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test that when all backends are down and then up, we may pick a TF backend
// and we will then jump to ready backend.
TEST_P(CdsTest, RingHashTransientFailureSkipToAvailableReady) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
const uint32_t kConnectionTimeoutMilliseconds = 5000;
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
@ -7946,13 +7917,11 @@ TEST_P(CdsTest, RingHashTransientFailureSkipToAvailableReady) {
EXPECT_TRUE(channel_->WaitForConnected(
grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds)));
WaitForBackend(1, WaitForBackendOptions(), rpc_options);
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test unspported hash policy types are all ignored before a supported
// policy.
TEST_P(CdsTest, RingHashUnsupportedHashPolicyUntilChannelIdHashing) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
balancers_[0]->ads_service()->SetCdsResource(cluster);
@ -7986,13 +7955,11 @@ TEST_P(CdsTest, RingHashUnsupportedHashPolicyUntilChannelIdHashing) {
}
}
EXPECT_TRUE(found);
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test we nack when ring hash policy has invalid hash function (something
// other than XX_HASH.
TEST_P(CdsTest, RingHashPolicyHasInvalidHashFunction) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
cluster.mutable_ring_hash_lb_config()->set_hash_function(
@ -8016,12 +7983,10 @@ TEST_P(CdsTest, RingHashPolicyHasInvalidHashFunction) {
EXPECT_THAT(
response_state.error_message,
::testing::HasSubstr("ring hash lb config has invalid hash function."));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test we nack when ring hash policy has invalid ring size.
TEST_P(CdsTest, RingHashPolicyHasInvalidMinimumRingSize) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
@ -8045,12 +8010,10 @@ TEST_P(CdsTest, RingHashPolicyHasInvalidMinimumRingSize) {
EXPECT_THAT(response_state.error_message,
::testing::HasSubstr(
"min_ring_size is not in the range of 1 to 8388608."));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test we nack when ring hash policy has invalid ring size.
TEST_P(CdsTest, RingHashPolicyHasInvalidMaxmumRingSize) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
cluster.mutable_ring_hash_lb_config()->mutable_maximum_ring_size()->set_value(
@ -8074,12 +8037,10 @@ TEST_P(CdsTest, RingHashPolicyHasInvalidMaxmumRingSize) {
EXPECT_THAT(response_state.error_message,
::testing::HasSubstr(
"max_ring_size is not in the range of 1 to 8388608."));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
// Test we nack when ring hash policy has invalid ring size.
TEST_P(CdsTest, RingHashPolicyHasInvalidRingSizeMinGreaterThanMax) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", "true");
auto cluster = default_cluster_;
cluster.set_lb_policy(Cluster::RING_HASH);
cluster.mutable_ring_hash_lb_config()->mutable_maximum_ring_size()->set_value(
@ -8105,7 +8066,6 @@ TEST_P(CdsTest, RingHashPolicyHasInvalidRingSizeMinGreaterThanMax) {
EXPECT_THAT(response_state.error_message,
::testing::HasSubstr(
"min_ring_size cannot be greater than max_ring_size."));
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
}
class XdsSecurityTest : public BasicTest {

Loading…
Cancel
Save