Line data Source code
1 : #include "source/common/upstream/host_utility.h" 2 : 3 : #include <string> 4 : 5 : #include "source/common/config/well_known_names.h" 6 : #include "source/common/runtime/runtime_features.h" 7 : 8 : namespace Envoy { 9 : namespace Upstream { 10 : namespace { 11 : 12 0 : void setHealthFlag(Upstream::Host::HealthFlag flag, const Host& host, std::string& health_status) { 13 0 : switch (flag) { 14 0 : case Host::HealthFlag::FAILED_ACTIVE_HC: { 15 0 : if (host.healthFlagGet(Host::HealthFlag::FAILED_ACTIVE_HC)) { 16 0 : health_status += "/failed_active_hc"; 17 0 : } 18 0 : break; 19 0 : } 20 : 21 0 : case Host::HealthFlag::FAILED_OUTLIER_CHECK: { 22 0 : if (host.healthFlagGet(Host::HealthFlag::FAILED_OUTLIER_CHECK)) { 23 0 : health_status += "/failed_outlier_check"; 24 0 : } 25 0 : break; 26 0 : } 27 : 28 0 : case Host::HealthFlag::FAILED_EDS_HEALTH: { 29 0 : if (host.healthFlagGet(Host::HealthFlag::FAILED_EDS_HEALTH)) { 30 0 : health_status += "/failed_eds_health"; 31 0 : } 32 0 : break; 33 0 : } 34 : 35 0 : case Host::HealthFlag::DEGRADED_ACTIVE_HC: { 36 0 : if (host.healthFlagGet(Host::HealthFlag::DEGRADED_ACTIVE_HC)) { 37 0 : health_status += "/degraded_active_hc"; 38 0 : } 39 0 : break; 40 0 : } 41 : 42 0 : case Host::HealthFlag::DEGRADED_EDS_HEALTH: { 43 0 : if (host.healthFlagGet(Host::HealthFlag::DEGRADED_EDS_HEALTH)) { 44 0 : health_status += "/degraded_eds_health"; 45 0 : } 46 0 : break; 47 0 : } 48 : 49 0 : case Host::HealthFlag::PENDING_DYNAMIC_REMOVAL: { 50 0 : if (host.healthFlagGet(Host::HealthFlag::PENDING_DYNAMIC_REMOVAL)) { 51 0 : health_status += "/pending_dynamic_removal"; 52 0 : } 53 0 : break; 54 0 : } 55 : 56 0 : case Host::HealthFlag::PENDING_ACTIVE_HC: { 57 0 : if (host.healthFlagGet(Host::HealthFlag::PENDING_ACTIVE_HC)) { 58 0 : health_status += "/pending_active_hc"; 59 0 : } 60 0 : break; 61 0 : } 62 : 63 0 : case Host::HealthFlag::EXCLUDED_VIA_IMMEDIATE_HC_FAIL: { 64 0 : if (host.healthFlagGet(Host::HealthFlag::EXCLUDED_VIA_IMMEDIATE_HC_FAIL)) { 65 0 : health_status += "/excluded_via_immediate_hc_fail"; 66 0 : } 67 0 : break; 68 0 : } 69 : 70 0 : case Host::HealthFlag::ACTIVE_HC_TIMEOUT: { 71 0 : if (host.healthFlagGet(Host::HealthFlag::ACTIVE_HC_TIMEOUT)) { 72 0 : health_status += "/active_hc_timeout"; 73 0 : } 74 0 : break; 75 0 : } 76 0 : } 77 0 : } 78 : 79 : } // namespace 80 : 81 0 : std::string HostUtility::healthFlagsToString(const Host& host) { 82 0 : std::string health_status; 83 : 84 : // Invokes setHealthFlag for each health flag. 85 0 : #define SET_HEALTH_FLAG(name, notused) \ 86 0 : setHealthFlag(Upstream::Host::HealthFlag::name, host, health_status); 87 0 : HEALTH_FLAG_ENUM_VALUES(SET_HEALTH_FLAG) 88 0 : #undef SET_HEALTH_FLAG 89 : 90 0 : if (health_status.empty()) { 91 0 : return "healthy"; 92 0 : } else { 93 0 : return health_status; 94 0 : } 95 0 : } 96 : 97 : HostUtility::HostStatusSet HostUtility::createOverrideHostStatus( 98 306 : const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) { 99 306 : HostStatusSet override_host_status; 100 : 101 306 : if (!common_config.has_override_host_status()) { 102 : // No override host status and [UNKNOWN, HEALTHY, DEGRADED] will be applied by default. 103 306 : override_host_status.set(static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::UNKNOWN)); 104 306 : override_host_status.set(static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::HEALTHY)); 105 306 : override_host_status.set( 106 306 : static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::DEGRADED)); 107 306 : return override_host_status; 108 306 : } 109 : 110 0 : for (auto single_status : common_config.override_host_status().statuses()) { 111 0 : switch (static_cast<envoy::config::core::v3::HealthStatus>(single_status)) { 112 0 : PANIC_ON_PROTO_ENUM_SENTINEL_VALUES; 113 0 : case envoy::config::core::v3::HealthStatus::UNKNOWN: 114 0 : case envoy::config::core::v3::HealthStatus::HEALTHY: 115 0 : case envoy::config::core::v3::HealthStatus::UNHEALTHY: 116 0 : case envoy::config::core::v3::HealthStatus::DRAINING: 117 0 : case envoy::config::core::v3::HealthStatus::TIMEOUT: 118 0 : case envoy::config::core::v3::HealthStatus::DEGRADED: 119 0 : override_host_status.set(static_cast<uint32_t>(single_status)); 120 0 : break; 121 0 : } 122 0 : } 123 0 : return override_host_status; 124 0 : } 125 : 126 : HostConstSharedPtr HostUtility::selectOverrideHost(const HostMap* host_map, HostStatusSet status, 127 251 : LoadBalancerContext* context) { 128 251 : if (context == nullptr) { 129 0 : return nullptr; 130 0 : } 131 : 132 251 : auto override_host = context->overrideHostToSelect(); 133 251 : if (!override_host.has_value()) { 134 251 : return nullptr; 135 251 : } 136 : 137 0 : if (host_map == nullptr) { 138 0 : return nullptr; 139 0 : } 140 : 141 0 : auto host_iter = host_map->find(override_host.value().first); 142 : 143 : // The override host cannot be found in the host map. 144 0 : if (host_iter == host_map->end()) { 145 0 : return nullptr; 146 0 : } 147 : 148 0 : HostConstSharedPtr host = host_iter->second; 149 0 : ASSERT(host != nullptr); 150 : 151 0 : if (status[static_cast<uint32_t>(host->healthStatus())]) { 152 0 : return host; 153 0 : } 154 0 : return nullptr; 155 0 : } 156 : 157 251 : bool HostUtility::allowLBChooseHost(LoadBalancerContext* context) { 158 251 : if (context == nullptr) { 159 0 : return true; 160 0 : } 161 : 162 251 : auto override_host = context->overrideHostToSelect(); 163 251 : if (!override_host.has_value()) { 164 251 : return true; 165 251 : } 166 : 167 : // Return opposite value to "strict" setting. 168 0 : return !override_host.value().second; 169 251 : } 170 : 171 : void HostUtility::forEachHostMetric( 172 : const ClusterManager& cluster_manager, 173 : const std::function<void(Stats::PrimitiveCounterSnapshot&& metric)>& counter_cb, 174 111 : const std::function<void(Stats::PrimitiveGaugeSnapshot&& metric)>& gauge_cb) { 175 172 : for (const auto& [unused_name, cluster_ref] : cluster_manager.clusters().active_clusters_) { 176 159 : Upstream::ClusterInfoConstSharedPtr cluster_info = cluster_ref.get().info(); 177 159 : if (cluster_info->perEndpointStatsEnabled()) { 178 0 : const std::string cluster_name = 179 0 : Stats::Utility::sanitizeStatsName(cluster_info->observabilityName()); 180 : 181 0 : const Stats::TagVector& fixed_tags = cluster_info->statsScope().store().fixedTags(); 182 : 183 0 : for (auto& host_set : cluster_ref.get().prioritySet().hostSetsPerPriority()) { 184 0 : for (auto& host : host_set->hosts()) { 185 : 186 0 : Stats::TagVector tags; 187 0 : tags.reserve(fixed_tags.size() + 3); 188 0 : tags.insert(tags.end(), fixed_tags.begin(), fixed_tags.end()); 189 0 : tags.emplace_back(Stats::Tag{Envoy::Config::TagNames::get().CLUSTER_NAME, cluster_name}); 190 0 : tags.emplace_back(Stats::Tag{"envoy.endpoint_address", host->address()->asString()}); 191 : 192 0 : const auto& hostname = host->hostname(); 193 0 : if (!hostname.empty()) { 194 0 : tags.push_back({"envoy.endpoint_hostname", hostname}); 195 0 : } 196 : 197 0 : auto set_metric_metadata = [&](absl::string_view metric_name, 198 0 : Stats::PrimitiveMetricMetadata& metric) { 199 0 : metric.setName( 200 0 : absl::StrCat("cluster.", cluster_name, ".endpoint.", 201 0 : Stats::Utility::sanitizeStatsName(host->address()->asStringView()), 202 0 : ".", metric_name)); 203 0 : metric.setTagExtractedName(absl::StrCat("cluster.endpoint.", metric_name)); 204 0 : metric.setTags(tags); 205 : 206 : // Validate that all components were sanitized. 207 0 : ASSERT(metric.name() == Stats::Utility::sanitizeStatsName(metric.name())); 208 0 : ASSERT(metric.tagExtractedName() == 209 0 : Stats::Utility::sanitizeStatsName(metric.tagExtractedName())); 210 0 : }; 211 : 212 0 : for (auto& [metric_name, primitive] : host->counters()) { 213 0 : Stats::PrimitiveCounterSnapshot metric(primitive.get()); 214 0 : set_metric_metadata(metric_name, metric); 215 : 216 0 : counter_cb(std::move(metric)); 217 0 : } 218 : 219 0 : auto gauges = host->gauges(); 220 : 221 : // Add synthetic "healthy" gauge. 222 0 : Stats::PrimitiveGauge healthy_gauge; 223 0 : healthy_gauge.set((host->coarseHealth() == Host::Health::Healthy) ? 1 : 0); 224 0 : gauges.emplace_back(absl::string_view("healthy"), healthy_gauge); 225 : 226 0 : for (auto& [metric_name, primitive] : gauges) { 227 0 : Stats::PrimitiveGaugeSnapshot metric(primitive.get()); 228 0 : set_metric_metadata(metric_name, metric); 229 0 : gauge_cb(std::move(metric)); 230 0 : } 231 0 : } 232 0 : } 233 0 : } 234 159 : } 235 111 : } 236 : 237 : } // namespace Upstream 238 : } // namespace Envoy