1
#include "source/extensions/health_checkers/thrift/thrift.h"
2

            
3
#include "source/extensions/filters/network/thrift_proxy/thrift.h"
4

            
5
namespace Envoy {
6
namespace Extensions {
7
namespace HealthCheckers {
8
namespace ThriftHealthChecker {
9

            
10
namespace {
11

            
12
// Helper functions to get the correct hostname for an L7 health check.
13
const std::string& getHostname(const Upstream::HostSharedPtr& host,
14
7
                               const Upstream::ClusterInfoConstSharedPtr& cluster) {
15
7
  return host->hostnameForHealthChecks().empty() ? cluster->name()
16
7
                                                 : host->hostnameForHealthChecks();
17
7
}
18

            
19
} // namespace
20

            
21
ThriftHealthChecker::ThriftHealthChecker(
22
    const Upstream::Cluster& cluster, const envoy::config::core::v3::HealthCheck& config,
23
    const envoy::extensions::health_checkers::thrift::v3::Thrift& thrift_config,
24
    Event::Dispatcher& dispatcher, Runtime::Loader& runtime,
25
    Upstream::HealthCheckEventLoggerPtr&& event_logger, Api::Api& api,
26
    ClientFactory& client_factory)
27
12
    : HealthCheckerImplBase(cluster, config, dispatcher, runtime, api.randomGenerator(),
28
12
                            std::move(event_logger)),
29
12
      method_name_(thrift_config.method_name()),
30
12
      transport_(ProtoUtils::getTransportType(thrift_config.transport())),
31
12
      protocol_(ProtoUtils::getProtocolType(thrift_config.protocol())),
32
12
      client_factory_(client_factory) {
33
12
  if (transport_ == TransportType::Auto || protocol_ == ProtocolType::Auto ||
34
12
      protocol_ == ProtocolType::Twitter) {
35
2
    throw EnvoyException(
36
2
        fmt::format("Unsupported transport or protocol in thrift health check configuration: {}",
37
2
                    thrift_config.DebugString()));
38
2
  }
39
12
}
40

            
41
ThriftHealthChecker::ThriftActiveHealthCheckSession::ThriftActiveHealthCheckSession(
42
    ThriftHealthChecker& parent, const Upstream::HostSharedPtr& host)
43
7
    : ActiveHealthCheckSession(parent, host), parent_(parent),
44
7
      hostname_(getHostname(host, parent_.cluster_.info())) {
45
7
  ENVOY_LOG(trace, "ThriftActiveHealthCheckSession construct hostname={}", hostname_);
46
7
}
47

            
48
7
ThriftHealthChecker::ThriftActiveHealthCheckSession::~ThriftActiveHealthCheckSession() {
49
7
  ENVOY_LOG(trace, "ThriftActiveHealthCheckSession destruct");
50
7
  ASSERT(client_ == nullptr);
51
7
}
52

            
53
7
void ThriftHealthChecker::ThriftActiveHealthCheckSession::onDeferredDelete() {
54
7
  if (client_) {
55
7
    expect_close_ = true;
56
7
    client_->close();
57
7
  }
58
7
}
59

            
60
26
void ThriftHealthChecker::ThriftActiveHealthCheckSession::onInterval() {
61
26
  ENVOY_LOG(trace, "ThriftActiveHealthCheckSession onInterval");
62
26
  if (!client_) {
63
15
    ENVOY_LOG(trace, "ThriftActiveHealthCheckSession construct client");
64
15
    client_ = parent_.client_factory_.create(
65
15
        *this, parent_.transport_, parent_.protocol_, parent_.method_name_, host_,
66
15
        /* health checker seq id */ 0, /* fixed_seq_id */ true);
67
15
    client_->start();
68
15
    expect_close_ = false;
69
15
  }
70

            
71
26
  client_->sendRequest();
72
26
}
73

            
74
2
void ThriftHealthChecker::ThriftActiveHealthCheckSession::onTimeout() {
75
2
  if (client_) {
76
2
    expect_close_ = true;
77
2
    client_->close();
78
2
  }
79
2
}
80

            
81
15
void ThriftHealthChecker::ThriftActiveHealthCheckSession::onResponseResult(bool is_success) {
82
15
  if (is_success) {
83
7
    handleSuccess();
84
8
  } else {
85
    // TODO(kuochunghsu): We might want to define retriable response.
86
8
    handleFailure(envoy::data::core::v3::ACTIVE, /* retriable */ false);
87
8
  }
88

            
89
15
  if (client_ && !parent_.reuse_connection_) {
90
2
    expect_close_ = true;
91
2
    client_->close();
92
2
  }
93
15
}
94

            
95
Upstream::Host::CreateConnectionData
96
ThriftHealthChecker::ThriftActiveHealthCheckSession::createConnection() {
97
  return host_->createHealthCheckConnection(parent_.dispatcher_, parent_.transportSocketOptions(),
98
                                            parent_.transportSocketMatchMetadata().get());
99
}
100

            
101
15
void ThriftHealthChecker::ThriftActiveHealthCheckSession::onEvent(Network::ConnectionEvent event) {
102
15
  if (event == Network::ConnectionEvent::RemoteClose ||
103
15
      event == Network::ConnectionEvent::LocalClose) {
104
15
    ENVOY_LOG(trace, "on event close, is_local_close={} expect_close={}",
105
15
              event == Network::ConnectionEvent::LocalClose, expect_close_);
106
15
    if (!expect_close_) {
107
4
      handleFailure(envoy::data::core::v3::NETWORK);
108
4
    }
109

            
110
15
    if (client_) {
111
      // Report failure if the connection was closed without receiving a full response.
112
15
      parent_.dispatcher_.deferredDelete(std::move(client_));
113
15
    }
114
15
  }
115
15
}
116

            
117
} // namespace ThriftHealthChecker
118
} // namespace HealthCheckers
119
} // namespace Extensions
120
} // namespace Envoy