Coverage Report

Created: 2023-11-12 09:30

/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
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
6.53k
    const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config) {
99
6.53k
  HostStatusSet override_host_status;
100
101
6.53k
  if (!common_config.has_override_host_status()) {
102
    // No override host status and [UNKNOWN, HEALTHY, DEGRADED] will be applied by default.
103
6.53k
    override_host_status.set(static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::UNKNOWN));
104
6.53k
    override_host_status.set(static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::HEALTHY));
105
6.53k
    override_host_status.set(
106
6.53k
        static_cast<uint32_t>(envoy::config::core::v3::HealthStatus::DEGRADED));
107
6.53k
    return override_host_status;
108
6.53k
  }
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
2.39k
                                                   LoadBalancerContext* context) {
128
2.39k
  if (context == nullptr) {
129
0
    return nullptr;
130
0
  }
131
132
2.39k
  auto override_host = context->overrideHostToSelect();
133
2.39k
  if (!override_host.has_value()) {
134
2.39k
    return nullptr;
135
2.39k
  }
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());
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
void HostUtility::forEachHostMetric(
158
    const ClusterManager& cluster_manager,
159
    const std::function<void(Stats::PrimitiveCounterSnapshot&& metric)>& counter_cb,
160
3.78k
    const std::function<void(Stats::PrimitiveGaugeSnapshot&& metric)>& gauge_cb) {
161
3.78k
  for (const auto& [unused_name, cluster_ref] : cluster_manager.clusters().active_clusters_) {
162
3.28k
    Upstream::ClusterInfoConstSharedPtr cluster_info = cluster_ref.get().info();
163
3.28k
    if (cluster_info->perEndpointStatsEnabled()) {
164
0
      const std::string cluster_name =
165
0
          Stats::Utility::sanitizeStatsName(cluster_info->observabilityName());
166
167
0
      const Stats::TagVector& fixed_tags = cluster_info->statsScope().store().fixedTags();
168
169
0
      for (auto& host_set : cluster_ref.get().prioritySet().hostSetsPerPriority()) {
170
0
        for (auto& host : host_set->hosts()) {
171
172
0
          Stats::TagVector tags;
173
0
          tags.reserve(fixed_tags.size() + 3);
174
0
          tags.insert(tags.end(), fixed_tags.begin(), fixed_tags.end());
175
0
          tags.emplace_back(Stats::Tag{Envoy::Config::TagNames::get().CLUSTER_NAME, cluster_name});
176
0
          tags.emplace_back(Stats::Tag{"envoy.endpoint_address", host->address()->asString()});
177
178
0
          const auto& hostname = host->hostname();
179
0
          if (!hostname.empty()) {
180
0
            tags.push_back({"envoy.endpoint_hostname", hostname});
181
0
          }
182
183
0
          auto set_metric_metadata = [&](absl::string_view metric_name,
184
0
                                         Stats::PrimitiveMetricMetadata& metric) {
185
0
            metric.setName(
186
0
                absl::StrCat("cluster.", cluster_name, ".endpoint.",
187
0
                             Stats::Utility::sanitizeStatsName(host->address()->asStringView()),
188
0
                             ".", metric_name));
189
0
            metric.setTagExtractedName(absl::StrCat("cluster.endpoint.", metric_name));
190
0
            metric.setTags(tags);
191
192
            // Validate that all components were sanitized.
193
0
            ASSERT(metric.name() == Stats::Utility::sanitizeStatsName(metric.name()));
194
0
            ASSERT(metric.tagExtractedName() ==
195
0
                   Stats::Utility::sanitizeStatsName(metric.tagExtractedName()));
196
0
          };
197
198
0
          for (auto& [metric_name, primitive] : host->counters()) {
199
0
            Stats::PrimitiveCounterSnapshot metric(primitive.get());
200
0
            set_metric_metadata(metric_name, metric);
201
202
0
            counter_cb(std::move(metric));
203
0
          }
204
205
0
          auto gauges = host->gauges();
206
207
          // Add synthetic "healthy" gauge.
208
0
          Stats::PrimitiveGauge healthy_gauge;
209
0
          healthy_gauge.set((host->coarseHealth() == Host::Health::Healthy) ? 1 : 0);
210
0
          gauges.emplace_back(absl::string_view("healthy"), healthy_gauge);
211
212
0
          for (auto& [metric_name, primitive] : gauges) {
213
0
            Stats::PrimitiveGaugeSnapshot metric(primitive.get());
214
0
            set_metric_metadata(metric_name, metric);
215
0
            gauge_cb(std::move(metric));
216
0
          }
217
0
        }
218
0
      }
219
0
    }
220
3.28k
  }
221
3.78k
}
222
223
} // namespace Upstream
224
} // namespace Envoy