1
#pragma once
2

            
3
#include "envoy/access_log/access_log.h"
4
#include "envoy/common/callback.h"
5
#include "envoy/common/random_generator.h"
6
#include "envoy/config/core/v3/health_check.pb.h"
7
#include "envoy/data/core/v3/health_check_event.pb.h"
8
#include "envoy/event/timer.h"
9
#include "envoy/runtime/runtime.h"
10
#include "envoy/stats/scope.h"
11
#include "envoy/type/matcher/string.pb.h"
12
#include "envoy/upstream/health_checker.h"
13

            
14
#include "source/common/common/logger.h"
15
#include "source/common/common/matchers.h"
16
#include "source/common/network/transport_socket_options_impl.h"
17

            
18
namespace Envoy {
19
namespace Upstream {
20

            
21
/**
22
 * All health checker stats. @see stats_macros.h
23
 */
24
#define ALL_HEALTH_CHECKER_STATS(COUNTER, GAUGE)                                                   \
25
359
  COUNTER(attempt)                                                                                 \
26
359
  COUNTER(failure)                                                                                 \
27
359
  COUNTER(network_failure)                                                                         \
28
359
  COUNTER(passive_failure)                                                                         \
29
359
  COUNTER(success)                                                                                 \
30
359
  COUNTER(verify_cluster)                                                                          \
31
359
  GAUGE(degraded, Accumulate)                                                                      \
32
359
  GAUGE(healthy, Accumulate)
33

            
34
/**
35
 * Definition of all health checker stats. @see stats_macros.h
36
 */
37
struct HealthCheckerStats {
38
  ALL_HEALTH_CHECKER_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT)
39
};
40

            
41
/**
42
 * Base implementation for all health checkers.
43
 */
44
class HealthCheckerImplBase : public HealthChecker,
45
                              protected Logger::Loggable<Logger::Id::hc>,
46
                              public std::enable_shared_from_this<HealthCheckerImplBase> {
47
public:
48
  // Upstream::HealthChecker
49
417
  void addHostCheckCompleteCb(HostStatusCb callback) override { callbacks_.push_back(callback); }
50
  void start() override;
51
591
  std::shared_ptr<const Network::TransportSocketOptionsImpl> transportSocketOptions() const {
52
591
    return transport_socket_options_;
53
591
  }
54
405
  MetadataConstSharedPtr transportSocketMatchMetadata() const {
55
405
    return transport_socket_match_metadata_;
56
405
  }
57

            
58
protected:
59
  class ActiveHealthCheckSession : public Event::DeferredDeletable {
60
  public:
61
    ~ActiveHealthCheckSession() override;
62
    HealthTransition setUnhealthy(envoy::data::core::v3::HealthCheckFailureType type,
63
                                  bool retriable);
64
    void onDeferredDeleteBase();
65
352
    void start() { onInitialInterval(); }
66

            
67
  protected:
68
    ActiveHealthCheckSession(HealthCheckerImplBase& parent, HostSharedPtr host);
69

            
70
    void handleSuccess(bool degraded = false);
71
    void handleFailure(envoy::data::core::v3::HealthCheckFailureType type, bool retriable = false);
72

            
73
    HostSharedPtr host_;
74

            
75
  private:
76
    // Clears the pending flag if it is set. By clearing this flag we're marking the host as having
77
    // been health checked.
78
    // Returns the changed state to use following the flag update.
79
    HealthTransition clearPendingFlag(HealthTransition changed_state);
80
    virtual void onInterval() PURE;
81
    void onIntervalBase();
82
    virtual void onTimeout() PURE;
83
    void onTimeoutBase();
84
    virtual void onDeferredDelete() PURE;
85
    void onInitialInterval();
86

            
87
    HealthCheckerImplBase& parent_;
88
    Event::TimerPtr interval_timer_;
89
    Event::TimerPtr timeout_timer_;
90
    uint32_t num_unhealthy_{};
91
    uint32_t num_healthy_{};
92
    bool first_check_{true};
93
    TimeSource& time_source_;
94
  };
95

            
96
  using ActiveHealthCheckSessionPtr = std::unique_ptr<ActiveHealthCheckSession>;
97

            
98
  HealthCheckerImplBase(const Cluster& cluster, const envoy::config::core::v3::HealthCheck& config,
99
                        Event::Dispatcher& dispatcher, Runtime::Loader& runtime,
100
                        Random::RandomGenerator& random, HealthCheckEventLoggerPtr&& event_logger);
101
  ~HealthCheckerImplBase() override;
102

            
103
  virtual ActiveHealthCheckSessionPtr makeSession(HostSharedPtr host) PURE;
104
  virtual envoy::data::core::v3::HealthCheckerType healthCheckerType() const PURE;
105

            
106
  const bool always_log_health_check_failures_;
107
  const bool always_log_health_check_success_;
108
  const Cluster& cluster_;
109
  Event::Dispatcher& dispatcher_;
110
  const std::chrono::milliseconds timeout_;
111
  const uint32_t unhealthy_threshold_;
112
  const uint32_t healthy_threshold_;
113
  HealthCheckerStats stats_;
114
  Runtime::Loader& runtime_;
115
  Random::RandomGenerator& random_;
116
  const bool reuse_connection_;
117
  HealthCheckEventLoggerPtr event_logger_;
118

            
119
private:
120
  struct HealthCheckHostMonitorImpl : public HealthCheckHostMonitor {
121
    HealthCheckHostMonitorImpl(const std::shared_ptr<HealthCheckerImplBase>& health_checker,
122
                               const HostSharedPtr& host)
123
352
        : health_checker_(health_checker), host_(host) {}
124

            
125
    // Upstream::HealthCheckHostMonitor
126
    void setUnhealthy(UnhealthyType type) override;
127

            
128
    std::weak_ptr<HealthCheckerImplBase> health_checker_;
129
    std::weak_ptr<Host> host_;
130
  };
131

            
132
  void addHosts(const HostVector& hosts);
133
  void decHealthy();
134
  void decDegraded();
135
  HealthCheckerStats generateStats(Stats::Scope& scope);
136
  void incHealthy();
137
  void incDegraded();
138
  std::chrono::milliseconds interval(HealthState state, HealthTransition changed_state) const;
139
  std::chrono::milliseconds intervalWithJitter(uint64_t base_time_ms,
140
                                               std::chrono::milliseconds interval_jitter) const;
141
  void onClusterMemberUpdate(const HostVector& hosts_added, const HostVector& hosts_removed);
142
  void runCallbacks(HostSharedPtr host, HealthTransition changed_state,
143
                    HealthState current_check_result);
144
  void setUnhealthyCrossThread(const HostSharedPtr& host,
145
                               HealthCheckHostMonitor::UnhealthyType type);
146
  static std::shared_ptr<const Network::TransportSocketOptionsImpl>
147
  initTransportSocketOptions(const envoy::config::core::v3::HealthCheck& config);
148
  static MetadataConstSharedPtr
149
  initTransportSocketMatchMetadata(const envoy::config::core::v3::HealthCheck& config);
150

            
151
  std::list<HostStatusCb> callbacks_;
152
  const std::chrono::milliseconds interval_;
153
  const std::chrono::milliseconds no_traffic_interval_;
154
  const std::chrono::milliseconds no_traffic_healthy_interval_;
155
  const std::chrono::milliseconds initial_jitter_;
156
  const std::chrono::milliseconds interval_jitter_;
157
  const uint32_t interval_jitter_percent_;
158
  const std::chrono::milliseconds unhealthy_interval_;
159
  const std::chrono::milliseconds unhealthy_edge_interval_;
160
  const std::chrono::milliseconds healthy_edge_interval_;
161
  absl::node_hash_map<HostSharedPtr, ActiveHealthCheckSessionPtr> active_sessions_;
162
  const std::shared_ptr<const Network::TransportSocketOptionsImpl> transport_socket_options_;
163
  const MetadataConstSharedPtr transport_socket_match_metadata_;
164
  const Common::CallbackHandlePtr member_update_cb_;
165
};
166

            
167
} // namespace Upstream
168
} // namespace Envoy