Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/upstream/host_utility.cc
Line
Count
Source (jump to first uncovered line)
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
77
0
  case Host::HealthFlag::EDS_STATUS_DRAINING: {
78
0
    if (host.healthFlagGet(Host::HealthFlag::EDS_STATUS_DRAINING)) {
79
0
      health_status += "/eds_status_draining";
80
0
    }
81
0
    break;
82
0
  }
83
0
  }
84
0
}
85
86
} // namespace
87
88
0
std::string HostUtility::healthFlagsToString(const Host& host) {
89
0
  std::string health_status;
90
91
  // Invokes setHealthFlag for each health flag.
92
0
#define SET_HEALTH_FLAG(name, notused)                                                             \
93
0
  setHealthFlag(Upstream::Host::HealthFlag::name, host, health_status);
94
0
  HEALTH_FLAG_ENUM_VALUES(SET_HEALTH_FLAG)
95
0
#undef SET_HEALTH_FLAG
96
97
0
  if (health_status.empty()) {
98
0
    return "healthy";
99
0
  } else {
100
0
    return health_status;
101
0
  }
102
0
}
103
104
HostUtility::HostStatusSet HostUtility::createOverrideHostStatus(
105
4.81k
    const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) {
106
4.81k
  HostStatusSet override_host_status;
107
108
4.81k
  if (!common_config.has_override_host_status()) {
109
    // No override host status and [UNKNOWN, HEALTHY, DEGRADED] will be applied by default.
110
4.81k
    override_host_status.set(static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::UNKNOWN));
111
4.81k
    override_host_status.set(static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::HEALTHY));
112
4.81k
    override_host_status.set(
113
4.81k
        static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::DEGRADED));
114
4.81k
    return override_host_status;
115
4.81k
  }
116
117
0
  for (auto single_status : common_config.override_host_status().statuses()) {
118
0
    switch (static_cast<envoy::config::core::v3::HealthStatus>(single_status)) {
119
0
      PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
120
0
    case envoy::config::core::v3::HealthStatus::UNKNOWN:
121
0
    case envoy::config::core::v3::HealthStatus::HEALTHY:
122
0
    case envoy::config::core::v3::HealthStatus::UNHEALTHY:
123
0
    case envoy::config::core::v3::HealthStatus::DRAINING:
124
0
    case envoy::config::core::v3::HealthStatus::TIMEOUT:
125
0
    case envoy::config::core::v3::HealthStatus::DEGRADED:
126
0
      override_host_status.set(static_cast<uint32_t>(single_status));
127
0
      break;
128
0
    }
129
0
  }
130
0
  return override_host_status;
131
0
}
132
133
HostConstSharedPtr HostUtility::selectOverrideHost(const HostMap* host_map, HostStatusSet status,
134
1.81k
                                                   LoadBalancerContext* context) {
135
1.81k
  if (context == nullptr) {
136
0
    return nullptr;
137
0
  }
138
139
1.81k
  auto override_host = context->overrideHostToSelect();
140
1.81k
  if (!override_host.has_value()) {
141
1.81k
    return nullptr;
142
1.81k
  }
143
144
0
  if (host_map == nullptr) {
145
0
    return nullptr;
146
0
  }
147
148
0
  auto host_iter = host_map->find(override_host.value().first);
149
150
  // The override host cannot be found in the host map.
151
0
  if (host_iter == host_map->end()) {
152
0
    return nullptr;
153
0
  }
154
155
0
  HostConstSharedPtr host = host_iter->second;
156
0
  ASSERT(host != nullptr);
157
158
0
  if (status[static_cast<uint32_t>(host->healthStatus())]) {
159
0
    return host;
160
0
  }
161
0
  return nullptr;
162
0
}
163
164
1.81k
bool HostUtility::allowLBChooseHost(LoadBalancerContext* context) {
165
1.81k
  if (context == nullptr) {
166
0
    return true;
167
0
  }
168
169
1.81k
  auto override_host = context->overrideHostToSelect();
170
1.81k
  if (!override_host.has_value()) {
171
1.81k
    return true;
172
1.81k
  }
173
174
  // Return opposite value to "strict" setting.
175
0
  return !override_host.value().second;
176
1.81k
}
177
178
void HostUtility::forEachHostMetric(
179
    const ClusterManager& cluster_manager,
180
    const std::function<void(Stats::PrimitiveCounterSnapshot&& metric)>& counter_cb,
181
3.03k
    const std::function<void(Stats::PrimitiveGaugeSnapshot&& metric)>& gauge_cb) {
182
3.03k
  for (const auto& [unused_name, cluster_ref] : cluster_manager.clusters().active_clusters_) {
183
2.41k
    Upstream::ClusterInfoConstSharedPtr cluster_info = cluster_ref.get().info();
184
2.41k
    if (cluster_info->perEndpointStatsEnabled()) {
185
0
      const std::string cluster_name =
186
0
          Stats::Utility::sanitizeStatsName(cluster_info->observabilityName());
187
188
0
      const Stats::TagVector& fixed_tags = cluster_info->statsScope().store().fixedTags();
189
190
0
      for (auto& host_set : cluster_ref.get().prioritySet().hostSetsPerPriority()) {
191
0
        for (auto& host : host_set->hosts()) {
192
193
0
          Stats::TagVector tags;
194
0
          tags.reserve(fixed_tags.size() + 3);
195
0
          tags.insert(tags.end(), fixed_tags.begin(), fixed_tags.end());
196
0
          tags.emplace_back(Stats::Tag{Envoy::Config::TagNames::get().CLUSTER_NAME, cluster_name});
197
0
          tags.emplace_back(Stats::Tag{"envoy.endpoint_address", host->address()->asString()});
198
199
0
          const auto& hostname = host->hostname();
200
0
          if (!hostname.empty()) {
201
0
            tags.push_back({"envoy.endpoint_hostname", hostname});
202
0
          }
203
204
0
          auto set_metric_metadata = [&](absl::string_view metric_name,
205
0
                                         Stats::PrimitiveMetricMetadata& metric) {
206
0
            metric.setName(
207
0
                absl::StrCat("cluster.", cluster_name, ".endpoint.",
208
0
                             Stats::Utility::sanitizeStatsName(host->address()->asStringView()),
209
0
                             ".", metric_name));
210
0
            metric.setTagExtractedName(absl::StrCat("cluster.endpoint.", metric_name));
211
0
            metric.setTags(tags);
212
213
            // Validate that all components were sanitized.
214
0
            ASSERT(metric.name() == Stats::Utility::sanitizeStatsName(metric.name()));
215
0
            ASSERT(metric.tagExtractedName() ==
216
0
                   Stats::Utility::sanitizeStatsName(metric.tagExtractedName()));
217
0
          };
218
219
0
          for (auto& [metric_name, primitive] : host->counters()) {
220
0
            Stats::PrimitiveCounterSnapshot metric(primitive.get());
221
0
            set_metric_metadata(metric_name, metric);
222
223
0
            counter_cb(std::move(metric));
224
0
          }
225
226
0
          auto gauges = host->gauges();
227
228
          // Add synthetic "healthy" gauge.
229
0
          Stats::PrimitiveGauge healthy_gauge;
230
0
          healthy_gauge.set((host->coarseHealth() == Host::Health::Healthy) ? 1 : 0);
231
0
          gauges.emplace_back(absl::string_view("healthy"), healthy_gauge);
232
233
0
          for (auto& [metric_name, primitive] : gauges) {
234
0
            Stats::PrimitiveGaugeSnapshot metric(primitive.get());
235
0
            set_metric_metadata(metric_name, metric);
236
0
            gauge_cb(std::move(metric));
237
0
          }
238
0
        }
239
0
      }
240
0
    }
241
2.41k
  }
242
3.03k
}
243
244
} // namespace Upstream
245
} // namespace Envoy