diff --git a/api/envoy/config/cluster/v3/cluster.proto b/api/envoy/config/cluster/v3/cluster.proto index e98414f8f2a4c..89b1b5f256316 100644 --- a/api/envoy/config/cluster/v3/cluster.proto +++ b/api/envoy/config/cluster/v3/cluster.proto @@ -486,7 +486,7 @@ message Cluster { } // Common configuration for all load balancer implementations. - // [#next-free-field: 8] + // [#next-free-field: 9] message CommonLbConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Cluster.CommonLbConfig"; @@ -595,6 +595,14 @@ message Cluster { // Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) ConsistentHashingLbConfig consistent_hashing_lb_config = 7; + + // This controls what hosts are considered valid when using + // :ref:`host overrides `, which is used by some + // filters to modify the load balancing decision. + // + // If this is unset then [UNKNOWN, HEALTHY, DEGRADED] will be applied by default. If this is + // set with an empty set of statuses then host overrides will be ignored by the load balancing. + core.v3.HealthStatusSet override_host_status = 8; } message RefreshRate { diff --git a/api/envoy/config/core/v3/health_check.proto b/api/envoy/config/core/v3/health_check.proto index fcae6eb697c44..7dd49d2bf639c 100644 --- a/api/envoy/config/core/v3/health_check.proto +++ b/api/envoy/config/core/v3/health_check.proto @@ -54,6 +54,12 @@ enum HealthStatus { DEGRADED = 5; } +message HealthStatusSet { + // An order-independent set of health status. + repeated HealthStatus statuses = 1 + [(validate.rules).repeated = {items {enum {defined_only: true}}}]; +} + // [#next-free-field: 25] message HealthCheck { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.core.HealthCheck"; diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancing.rst b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancing.rst index de648a4b8c73f..be284b6e99eaf 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancing.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancing.rst @@ -16,3 +16,4 @@ Load Balancing zone_aware subsets slow_start + override_host diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/override_host.rst b/docs/root/intro/arch_overview/upstream/load_balancing/override_host.rst new file mode 100644 index 0000000000000..8c6d708d80b36 --- /dev/null +++ b/docs/root/intro/arch_overview/upstream/load_balancing/override_host.rst @@ -0,0 +1,19 @@ +.. _arch_overview_load_balancing_override_host: + +Override host +============= + +Load balancing algorithms (round robin, random, etc.) are used to select upstream hosts by default. +Also, Envoy supports overriding the results of the load balancing algorithms by specifying a valid +override host address. If a valid override host address is specified and the corresponding upstream +host has the +:ref:`expected health status `, +that upstream host will be selected preferentially. + +For example, :ref:`stateful session filter ` will specify +override host address directly based on the downstream request attributes. Then the results of load +balancing algorithms will be ignored. By this way, stateful session stickiness can be achieved. + +In summary, override host provides a mechanism by which L4/L7 extensions can influence the final +results of upstream load balancing. This mechanism can be used by different extensions in different +scenarios. diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 4bc41e24b30b2..d2433239832ad 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -55,6 +55,7 @@ New Features ------------ * access_log: make consistent access_log format fields ``%(DOWN|DIRECT_DOWN|UP)STREAM_(LOCAL|REMOTE)_*%`` to provide all combinations of local & remote addresses for upstream & downstream connections. * admin: :http:post:`/logging` now accepts ``/logging?paths=name1:level1,name2:level2,...`` to change multiple log levels at once. +* cluster: support :ref:`override host status restriction `. * config: added new file based xDS configuration via :ref:`path_config_source `. :ref:`watched_directory ` can be used to setup an independent watch for when to reload the file path, for example when using diff --git a/envoy/upstream/load_balancer.h b/envoy/upstream/load_balancer.h index 75252fae82d63..288aba5fb61d8 100644 --- a/envoy/upstream/load_balancer.h +++ b/envoy/upstream/load_balancer.h @@ -89,22 +89,11 @@ class LoadBalancerContext { */ virtual Network::TransportSocketOptionsConstSharedPtr upstreamTransportSocketOptions() const PURE; - // Using uint32_t to express expected status of override host. Every bit in the OverrideHostStatus - // represent an enum value of Host::Health. The specific correspondence is shown below: - // - // * 0b001: Host::Health::Unhealthy - // * 0b010: Host::Health::Degraded - // * 0b100: Host::Health::Healthy - // - // If multiple bit fields are set, it is acceptable as long as the status of override host is in - // any of these statuses. - using OverrideHostStatus = uint32_t; - using OverrideHost = std::pair; - + using OverrideHost = absl::string_view; /** * Returns the host the load balancer should select directly. If the expected host exists and - * the health status of the host matches the expectation, the load balancer can bypass the load - * balancing algorithm and return the corresponding host directly. + * the host can be selected directly, the load balancer can bypass the load balancing algorithm + * and return the corresponding host directly. */ virtual absl::optional overrideHostToSelect() const PURE; }; diff --git a/source/common/router/router.h b/source/common/router/router.h index f731c14158f92..346c7f7891f2d 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -431,13 +431,7 @@ class Filter : Logger::Loggable, return {}; } - auto override_host = callbacks_->upstreamOverrideHost(); - if (override_host.has_value()) { - // TODO(wbpcode): Currently we need to provide additional expected host status to the load - // balancer. This should be resolved after the `overrideHostToSelect()` refactoring. - return std::make_pair(std::string(override_host.value()), ~static_cast(0)); - } - return {}; + return callbacks_->upstreamOverrideHost(); } /** diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index 36c446bcc430d..ff3218b3d3b78 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -1,6 +1,7 @@ #include "source/common/upstream/load_balancer_impl.h" #include +#include #include #include #include @@ -24,10 +25,6 @@ static const std::string RuntimeZoneEnabled = "upstream.zone_routing.enabled"; static const std::string RuntimeMinClusterSize = "upstream.zone_routing.min_cluster_size"; static const std::string RuntimePanicThreshold = "upstream.healthy_panic_threshold"; -static constexpr uint32_t UnhealthyStatus = 1u << static_cast(Host::Health::Unhealthy); -static constexpr uint32_t DegradedStatus = 1u << static_cast(Host::Health::Degraded); -static constexpr uint32_t HealthyStatus = 1u << static_cast(Host::Health::Healthy); - bool tooManyPreconnects(size_t num_preconnect_picks, uint32_t healthy_hosts) { // Currently we only allow the number of preconnected connections to equal the // number of healthy hosts. @@ -118,7 +115,8 @@ LoadBalancerBase::LoadBalancerBase( : stats_(stats), runtime_(runtime), random_(random), default_healthy_panic_percent_(PROTOBUF_PERCENT_TO_ROUNDED_INTEGER_OR_DEFAULT( common_config, healthy_panic_threshold, 100, 50)), - priority_set_(priority_set) { + priority_set_(priority_set), + override_host_status_(LoadBalancerContextBase::createOverrideHostStatus(common_config)) { for (auto& host_set : priority_set_.hostSetsPerPriority()) { recalculatePerPriorityState(host_set->priority(), priority_set_, per_priority_load_, per_priority_health_, per_priority_degraded_, total_healthy_hosts_); @@ -517,20 +515,39 @@ bool ZoneAwareLoadBalancerBase::earlyExitNonLocalityRouting() { return false; } -bool LoadBalancerContextBase::validateOverrideHostStatus(Host::Health health, - OverrideHostStatus status) { - switch (health) { - case Host::Health::Unhealthy: - return status & UnhealthyStatus; - case Host::Health::Degraded: - return status & DegradedStatus; - case Host::Health::Healthy: - return status & HealthyStatus; +HostStatusSet LoadBalancerContextBase::createOverrideHostStatus( + const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) { + HostStatusSet override_host_status; + + if (!common_config.has_override_host_status()) { + // No override host status and 'Healthy' and 'Degraded' will be applied by default. + override_host_status.set(static_cast(Host::Health::Healthy)); + override_host_status.set(static_cast(Host::Health::Degraded)); + return override_host_status; + } + + for (auto single_status : common_config.override_host_status().statuses()) { + switch (static_cast(single_status)) { + PANIC_ON_PROTO_ENUM_SENTINEL_VALUES; + case envoy::config::core::v3::HealthStatus::UNKNOWN: + case envoy::config::core::v3::HealthStatus::HEALTHY: + override_host_status.set(static_cast(Host::Health::Healthy)); + break; + case envoy::config::core::v3::HealthStatus::UNHEALTHY: + case envoy::config::core::v3::HealthStatus::DRAINING: + case envoy::config::core::v3::HealthStatus::TIMEOUT: + override_host_status.set(static_cast(Host::Health::Unhealthy)); + break; + case envoy::config::core::v3::HealthStatus::DEGRADED: + override_host_status.set(static_cast(Host::Health::Degraded)); + break; + } } - return false; + return override_host_status; } HostConstSharedPtr LoadBalancerContextBase::selectOverrideHost(const HostMap* host_map, + HostStatusSet status, LoadBalancerContext* context) { if (context == nullptr) { return nullptr; @@ -545,7 +562,7 @@ HostConstSharedPtr LoadBalancerContextBase::selectOverrideHost(const HostMap* ho return nullptr; } - auto host_iter = host_map->find(override_host.value().first); + auto host_iter = host_map->find(override_host.value()); // The override host cannot be found in the host map. if (host_iter == host_map->end()) { @@ -555,17 +572,15 @@ HostConstSharedPtr LoadBalancerContextBase::selectOverrideHost(const HostMap* ho HostConstSharedPtr host = host_iter->second; ASSERT(host != nullptr); - // Verify the host status. - if (LoadBalancerContextBase::validateOverrideHostStatus(host->health(), - override_host.value().second)) { + if (status[static_cast(host->health())]) { return host; } return nullptr; } HostConstSharedPtr ZoneAwareLoadBalancerBase::chooseHost(LoadBalancerContext* context) { - HostConstSharedPtr host = - LoadBalancerContextBase::selectOverrideHost(cross_priority_host_map_.get(), context); + HostConstSharedPtr host = LoadBalancerContextBase::selectOverrideHost( + cross_priority_host_map_.get(), override_host_status_, context); if (host != nullptr) { return host; } @@ -652,8 +667,8 @@ uint32_t ZoneAwareLoadBalancerBase::tryChooseLocalLocalityHosts(const HostSet& h return random_.random() % number_of_localities; } - // Random sampling to select specific locality for cross locality traffic based on the additional - // capacity in localities. + // Random sampling to select specific locality for cross locality traffic based on the + // additional capacity in localities. uint64_t threshold = random_.random() % state.residual_capacity_[number_of_localities - 1]; // This potentially can be optimized to be O(log(N)) where N is the number of localities. @@ -923,8 +938,8 @@ HostConstSharedPtr EdfLoadBalancerBase::peekAnotherHost(LoadBalancerContext* con // As has been commented in both EdfLoadBalancerBase::refresh and // BaseDynamicClusterImpl::updateDynamicHostList, we must do a runtime pivot here to determine - // whether to use EDF or do unweighted (fast) selection. EDF is non-null iff the original weights - // of 2 or more hosts differ. + // whether to use EDF or do unweighted (fast) selection. EDF is non-null iff the original + // weights of 2 or more hosts differ. if (scheduler.edf_ != nullptr) { return scheduler.edf_->peekAgain([this](const Host& host) { return hostWeight(host); }); } else { @@ -949,8 +964,8 @@ HostConstSharedPtr EdfLoadBalancerBase::chooseHostOnce(LoadBalancerContext* cont // As has been commented in both EdfLoadBalancerBase::refresh and // BaseDynamicClusterImpl::updateDynamicHostList, we must do a runtime pivot here to determine - // whether to use EDF or do unweighted (fast) selection. EDF is non-null iff the original weights - // of 2 or more hosts differ. + // whether to use EDF or do unweighted (fast) selection. EDF is non-null iff the original + // weights of 2 or more hosts differ. if (scheduler.edf_ != nullptr) { auto host = scheduler.edf_->pickAndAdd([this](const Host& host) { return hostWeight(host); }); return host; diff --git a/source/common/upstream/load_balancer_impl.h b/source/common/upstream/load_balancer_impl.h index 78f2c200cc87e..8d81f9dc267b5 100644 --- a/source/common/upstream/load_balancer_impl.h +++ b/source/common/upstream/load_balancer_impl.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -24,6 +25,8 @@ namespace Upstream { // Priority levels and localities are considered overprovisioned with this factor. static constexpr uint32_t kDefaultOverProvisioningFactor = 140; +using HostStatusSet = std::bitset<32>; + /** * Base class for all LB implementations. */ @@ -155,17 +158,31 @@ class LoadBalancerBase : public LoadBalancer { // The total count of healthy hosts across all priority levels. uint32_t total_healthy_hosts_; + // Expected override host statues. Every bit in the OverrideHostStatus represent an enum value of + // Host::Health. The specific correspondence is shown below: + // + // * 0b001: Host::Health::Unhealthy + // * 0b010: Host::Health::Degraded + // * 0b100: Host::Health::Healthy + // + // If multiple bit fields are set, it is acceptable as long as the status of override host is in + // any of these statuses. + const HostStatusSet override_host_status_{}; + private: Common::CallbackHandlePtr priority_update_cb_; }; class LoadBalancerContextBase : public LoadBalancerContext { public: - static bool validateOverrideHostStatus(Host::Health health, OverrideHostStatus status); - - static HostConstSharedPtr selectOverrideHost(const HostMap* host_map, + // A utility function to select override host from host map according to load balancer context. + static HostConstSharedPtr selectOverrideHost(const HostMap* host_map, HostStatusSet status, LoadBalancerContext* context); + // A utility function to create override host status from lb config. + static HostStatusSet createOverrideHostStatus( + const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config); + absl::optional computeHashKey() override { return {}; } const Network::Connection* downstreamConnection() const override { return nullptr; } diff --git a/source/common/upstream/subset_lb.cc b/source/common/upstream/subset_lb.cc index c080c643d3fa9..70fd4c5acae64 100644 --- a/source/common/upstream/subset_lb.cc +++ b/source/common/upstream/subset_lb.cc @@ -42,7 +42,8 @@ SubsetLoadBalancer::SubsetLoadBalancer( original_local_priority_set_(local_priority_set), locality_weight_aware_(subsets.localityWeightAware()), scale_locality_weight_(subsets.scaleLocalityWeight()), list_as_any_(subsets.listAsAny()), - time_source_(time_source) { + time_source_(time_source), + override_host_status_(LoadBalancerContextBase::createOverrideHostStatus(common_config)) { ASSERT(subsets.isEnabled()); if (fallback_policy_ != envoy::config::cluster::v3::Cluster::LbSubsetConfig::NO_FALLBACK) { @@ -283,8 +284,8 @@ void SubsetLoadBalancer::initSelectorFallbackSubset( } HostConstSharedPtr SubsetLoadBalancer::chooseHost(LoadBalancerContext* context) { - HostConstSharedPtr override_host = - LoadBalancerContextBase::selectOverrideHost(cross_priority_host_map_.get(), context); + HostConstSharedPtr override_host = LoadBalancerContextBase::selectOverrideHost( + cross_priority_host_map_.get(), override_host_status_, context); if (override_host != nullptr) { return override_host; } diff --git a/source/common/upstream/subset_lb.h b/source/common/upstream/subset_lb.h index 9772852879485..82950e1ba88d7 100644 --- a/source/common/upstream/subset_lb.h +++ b/source/common/upstream/subset_lb.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,6 +14,7 @@ #include "source/common/common/macros.h" #include "source/common/protobuf/protobuf.h" #include "source/common/protobuf/utility.h" +#include "source/common/upstream/load_balancer_impl.h" #include "source/common/upstream/upstream_impl.h" #include "absl/container/node_hash_map.h" @@ -297,6 +299,8 @@ class SubsetLoadBalancer : public LoadBalancer, Logger::Loggabledegraded_per_priority_load_ = degraded_per_priority_load_; lb->per_priority_state_ = per_priority_state_; lb->cross_priority_host_map_ = cross_priority_host_map_; - + lb->override_host_status_ = override_host_status_; return lb; } diff --git a/source/common/upstream/thread_aware_lb_impl.h b/source/common/upstream/thread_aware_lb_impl.h index a29e4a2c39591..f16f634f522c9 100644 --- a/source/common/upstream/thread_aware_lb_impl.h +++ b/source/common/upstream/thread_aware_lb_impl.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "envoy/common/callback.h" #include "envoy/config/cluster/v3/cluster.pb.h" @@ -109,7 +111,7 @@ class ThreadAwareLoadBalancerBase : public LoadBalancerBase, public ThreadAwareL Random::RandomGenerator& random, const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) : LoadBalancerBase(priority_set, stats, runtime, random, common_config), - factory_(new LoadBalancerFactoryImpl(stats, random)) {} + factory_(new LoadBalancerFactoryImpl(stats, random, override_host_status_)) {} private: struct PerPriorityState { @@ -138,6 +140,7 @@ class ThreadAwareLoadBalancerBase : public LoadBalancerBase, public ThreadAwareL ClusterStats& stats_; Random::RandomGenerator& random_; + HostStatusSet override_host_status_{}; std::shared_ptr> per_priority_state_; std::shared_ptr healthy_per_priority_load_; std::shared_ptr degraded_per_priority_load_; @@ -147,14 +150,16 @@ class ThreadAwareLoadBalancerBase : public LoadBalancerBase, public ThreadAwareL }; struct LoadBalancerFactoryImpl : public LoadBalancerFactory { - LoadBalancerFactoryImpl(ClusterStats& stats, Random::RandomGenerator& random) - : stats_(stats), random_(random) {} + LoadBalancerFactoryImpl(ClusterStats& stats, Random::RandomGenerator& random, + HostStatusSet status) + : stats_(stats), random_(random), override_host_status_(status) {} // Upstream::LoadBalancerFactory LoadBalancerPtr create() override; ClusterStats& stats_; Random::RandomGenerator& random_; + HostStatusSet override_host_status_{}; absl::Mutex mutex_; std::shared_ptr> per_priority_state_ ABSL_GUARDED_BY(mutex_); // This is split out of PerPriorityState so LoadBalancerBase::ChoosePriority can be reused. diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 6404703e9b480..4796718fcae70 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -6074,8 +6074,7 @@ TEST_F(RouterTest, RequestWithUpstreamOverrideHost) { .WillOnce(Return(absl::make_optional("1.2.3.4"))); auto override_host = router_.overrideHostToSelect(); - EXPECT_EQ("1.2.3.4", override_host->first); - EXPECT_EQ(~static_cast(0), override_host->second); + EXPECT_EQ("1.2.3.4", override_host.value()); Http::TestRequestHeaderMapImpl headers{{"x-envoy-retry-on", "5xx"}, {"x-envoy-internal", "true"}}; HttpTestUtility::addDefaultHeaders(headers); diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index c2420c9215f2b..d38e58f09f48c 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -63,9 +65,9 @@ class TestZoneAwareLoadBalancer : public ZoneAwareLoadBalancerBase { namespace { -static constexpr uint32_t UnhealthyStatus = 1u << static_cast(Host::Health::Unhealthy); -static constexpr uint32_t DegradedStatus = 1u << static_cast(Host::Health::Degraded); -static constexpr uint32_t HealthyStatus = 1u << static_cast(Host::Health::Healthy); +static constexpr HostStatusSet UnhealthyStatus = 1u << static_cast(Host::Health::Unhealthy); +static constexpr HostStatusSet DegradedStatus = 1u << static_cast(Host::Health::Degraded); +static constexpr HostStatusSet HealthyStatus = 1u << static_cast(Host::Health::Healthy); class LoadBalancerTestBase : public Event::TestUsingSimulatedTime, public testing::TestWithParam { @@ -635,7 +637,7 @@ TEST_F(ZoneAwareLoadBalancerBaseTest, SelectOverrideHostTestInLb) { NiceMock context; { - LoadBalancerContext::OverrideHost override_host{"1.2.3.4", HealthyStatus | DegradedStatus}; + LoadBalancerContext::OverrideHost override_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(Return(absl::make_optional(override_host))); @@ -652,7 +654,7 @@ TEST_F(ZoneAwareLoadBalancerBaseTest, SelectOverrideHostTestInLb) { auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(Return(Host::Health::Unhealthy)); - LoadBalancerContext::OverrideHost override_host{"1.2.3.4", HealthyStatus | DegradedStatus}; + LoadBalancerContext::OverrideHost override_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(Return(absl::make_optional(override_host))); @@ -662,8 +664,8 @@ TEST_F(ZoneAwareLoadBalancerBaseTest, SelectOverrideHostTestInLb) { priority_set_.cross_priority_host_map_ = host_map; host_set_.runCallbacks({}, {}); - // Host status does not match the expected host status, therefore `chooseHostOnce` will be - // called. + // Host status does not match the expected host status (Healthy & Degraded by default), + // therefore `chooseHostOnce` will be called. EXPECT_EQ(lb_.choose_host_once_host_, lb_.chooseHost(&context)); } @@ -671,7 +673,7 @@ TEST_F(ZoneAwareLoadBalancerBaseTest, SelectOverrideHostTestInLb) { auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(Return(Host::Health::Degraded)); - LoadBalancerContext::OverrideHost override_host{"1.2.3.4", HealthyStatus | DegradedStatus}; + LoadBalancerContext::OverrideHost override_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(Return(absl::make_optional(override_host))); @@ -2557,65 +2559,128 @@ TEST(LoadBalancerContextBaseTest, LoadBalancerContextBaseTest) { EXPECT_EQ(absl::nullopt, context.overrideHostToSelect()); } - EXPECT_TRUE(LoadBalancerContextBase::validateOverrideHostStatus(Host::Health::Unhealthy, - UnhealthyStatus)); - EXPECT_TRUE( - LoadBalancerContextBase::validateOverrideHostStatus(Host::Health::Healthy, HealthyStatus)); - EXPECT_FALSE( - LoadBalancerContextBase::validateOverrideHostStatus(Host::Health::Healthy, UnhealthyStatus)); + { + envoy::config::cluster::v3::Cluster::CommonLbConfig lb_config; + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::UNKNOWN); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::HEALTHY); + EXPECT_EQ(LoadBalancerContextBase::createOverrideHostStatus(lb_config), HealthyStatus); + } + { + envoy::config::cluster::v3::Cluster::CommonLbConfig lb_config; + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::UNHEALTHY); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::DRAINING); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::TIMEOUT); + + EXPECT_EQ(LoadBalancerContextBase::createOverrideHostStatus(lb_config), UnhealthyStatus); + } + { + envoy::config::cluster::v3::Cluster::CommonLbConfig lb_config; + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::DEGRADED); + EXPECT_EQ(LoadBalancerContextBase::createOverrideHostStatus(lb_config), DegradedStatus); + } + { + envoy::config::cluster::v3::Cluster::CommonLbConfig lb_config; + EXPECT_EQ(LoadBalancerContextBase::createOverrideHostStatus(lb_config), 0b110u); + } + { + envoy::config::cluster::v3::Cluster::CommonLbConfig lb_config; + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::UNHEALTHY); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::DRAINING); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::TIMEOUT); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::UNKNOWN); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::HEALTHY); + + EXPECT_EQ(LoadBalancerContextBase::createOverrideHostStatus(lb_config), 0b101u); + } + + { + envoy::config::cluster::v3::Cluster::CommonLbConfig lb_config; + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::UNHEALTHY); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::DRAINING); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::TIMEOUT); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::UNKNOWN); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::HEALTHY); + lb_config.mutable_override_host_status()->add_statuses( + ::envoy::config::core::v3::HealthStatus::DEGRADED); + EXPECT_EQ(LoadBalancerContextBase::createOverrideHostStatus(lb_config), 0b111u); + } } -TEST(LoadBalancerContextBaseTest, selectOverrideHostTest) { +TEST(LoadBalancerContextBaseTest, SelectOverrideHostTest) { NiceMock context; + const HostStatusSet all_health_statuses = UnhealthyStatus | DegradedStatus | HealthyStatus; + { // No valid host map. - EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(nullptr, &context)); + EXPECT_EQ(nullptr, + LoadBalancerContextBase::selectOverrideHost(nullptr, all_health_statuses, &context)); } { // No valid load balancer context. auto host_map = std::make_shared(); - EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(host_map.get(), nullptr)); + EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(host_map.get(), + all_health_statuses, nullptr)); } { // No valid expected host. EXPECT_CALL(context, overrideHostToSelect()).WillOnce(Return(absl::nullopt)); auto host_map = std::make_shared(); - EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(host_map.get(), &context)); + EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(host_map.get(), + all_health_statuses, &context)); } { // The host map does not contain the expected host. - LoadBalancerContext::OverrideHost override_host{"1.2.3.4", HealthyStatus}; + LoadBalancerContext::OverrideHost override_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(Return(absl::make_optional(override_host))); auto host_map = std::make_shared(); - EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(host_map.get(), &context)); + EXPECT_EQ(nullptr, + LoadBalancerContextBase::selectOverrideHost(host_map.get(), HealthyStatus, &context)); } { // The status of host is not as expected. auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(Return(Host::Health::Unhealthy)); - LoadBalancerContext::OverrideHost override_host{"1.2.3.4", HealthyStatus}; + LoadBalancerContext::OverrideHost override_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(Return(absl::make_optional(override_host))); auto host_map = std::make_shared(); host_map->insert({"1.2.3.4", mock_host}); - EXPECT_EQ(nullptr, LoadBalancerContextBase::selectOverrideHost(host_map.get(), &context)); + EXPECT_EQ(nullptr, + LoadBalancerContextBase::selectOverrideHost(host_map.get(), HealthyStatus, &context)); } { // Get expected host. auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(Return(Host::Health::Degraded)); - LoadBalancerContext::OverrideHost override_host{"1.2.3.4", HealthyStatus | DegradedStatus}; + LoadBalancerContext::OverrideHost override_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(Return(absl::make_optional(override_host))); auto host_map = std::make_shared(); host_map->insert({"1.2.3.4", mock_host}); - EXPECT_EQ(mock_host, LoadBalancerContextBase::selectOverrideHost(host_map.get(), &context)); + EXPECT_EQ(mock_host, LoadBalancerContextBase::selectOverrideHost( + host_map.get(), HealthyStatus | DegradedStatus, &context)); } } diff --git a/test/common/upstream/maglev_lb_test.cc b/test/common/upstream/maglev_lb_test.cc index d8472c5a5aefe..934d5ec6ba183 100644 --- a/test/common/upstream/maglev_lb_test.cc +++ b/test/common/upstream/maglev_lb_test.cc @@ -88,9 +88,7 @@ TEST_F(MaglevLoadBalancerTest, SelectOverrideHost) { auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(testing::Return(Host::Health::Degraded)); - LoadBalancerContext::OverrideHost expected_host{ - "1.2.3.4", 1u << static_cast(Host::Health::Healthy) | - 1u << static_cast(Host::Health::Degraded)}; + LoadBalancerContext::OverrideHost expected_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()) .WillOnce(testing::Return(absl::make_optional(expected_host))); diff --git a/test/common/upstream/ring_hash_lb_test.cc b/test/common/upstream/ring_hash_lb_test.cc index 99b9d402e6b46..c83fddedf0a24 100644 --- a/test/common/upstream/ring_hash_lb_test.cc +++ b/test/common/upstream/ring_hash_lb_test.cc @@ -124,9 +124,7 @@ TEST_P(RingHashLoadBalancerTest, SelectOverrideHost) { auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(Return(Host::Health::Degraded)); - LoadBalancerContext::OverrideHost expected_host{ - "1.2.3.4", 1u << static_cast(Host::Health::Healthy) | - 1u << static_cast(Host::Health::Degraded)}; + LoadBalancerContext::OverrideHost expected_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()).WillOnce(Return(absl::make_optional(expected_host))); // Mock membership update and update host map shared pointer in the lb. diff --git a/test/common/upstream/subset_lb_test.cc b/test/common/upstream/subset_lb_test.cc index 133d15cacba90..801f74440ef7a 100644 --- a/test/common/upstream/subset_lb_test.cc +++ b/test/common/upstream/subset_lb_test.cc @@ -515,9 +515,7 @@ TEST_F(SubsetLoadBalancerTest, SelectOverrideHost) { auto mock_host = std::make_shared>(); EXPECT_CALL(*mock_host, health()).WillOnce(Return(Host::Health::Degraded)); - LoadBalancerContext::OverrideHost expected_host{ - "1.2.3.4", 1u << static_cast(Host::Health::Healthy) | - 1u << static_cast(Host::Health::Degraded)}; + LoadBalancerContext::OverrideHost expected_host{"1.2.3.4"}; EXPECT_CALL(context, overrideHostToSelect()).WillOnce(Return(absl::make_optional(expected_host))); // Mock membership update and update host map shared pointer in the lb.