Line data Source code
1 : #pragma once 2 : 3 : #include <cstdint> 4 : 5 : #include "envoy/access_log/access_log.h" 6 : #include "envoy/api/api.h" 7 : #include "envoy/common/random_generator.h" 8 : #include "envoy/config/core/v3/health_check.pb.h" 9 : #include "envoy/data/core/v3/health_check_event.pb.h" 10 : #include "envoy/grpc/status.h" 11 : #include "envoy/network/socket.h" 12 : #include "envoy/server/factory_context.h" 13 : #include "envoy/server/health_checker_config.h" 14 : #include "envoy/type/v3/http.pb.h" 15 : #include "envoy/type/v3/range.pb.h" 16 : #include "envoy/upstream/health_checker.h" 17 : 18 : #include "source/common/common/dump_state_utils.h" 19 : #include "source/common/common/logger.h" 20 : #include "source/common/grpc/codec.h" 21 : #include "source/common/http/codec_client.h" 22 : #include "source/common/router/header_parser.h" 23 : #include "source/common/stream_info/stream_info_impl.h" 24 : #include "source/common/upstream/health_checker_event_logger.h" 25 : 26 : #include "src/proto/grpc/health/v1/health.pb.h" 27 : 28 : namespace Envoy { 29 : namespace Upstream { 30 : 31 : constexpr uint64_t kDefaultMaxBytesInBuffer = 1024; 32 : 33 : /** 34 : * HealthCheckerHash and HealthCheckerEqualTo are used to allow the HealthCheck proto to be used as 35 : * a flat_hash_map key. 36 : */ 37 : struct HealthCheckerHash { 38 0 : size_t operator()(const envoy::config::core::v3::HealthCheck& health_check) const { 39 0 : return MessageUtil::hash(health_check); 40 0 : } 41 : }; 42 : 43 : struct HealthCheckerEqualTo { 44 : bool operator()(const envoy::config::core::v3::HealthCheck& lhs, 45 0 : const envoy::config::core::v3::HealthCheck& rhs) const { 46 0 : return Protobuf::util::MessageDifferencer::Equals(lhs, rhs); 47 0 : } 48 : }; 49 : 50 : /** 51 : * Health checker factory context. 52 : */ 53 : class HealthCheckerFactoryContextImpl : public Server::Configuration::HealthCheckerFactoryContext { 54 : public: 55 : HealthCheckerFactoryContextImpl(Upstream::Cluster& cluster, 56 : Server::Configuration::ServerFactoryContext& server_context) 57 : : cluster_(cluster), runtime_(server_context.runtime()), 58 : dispatcher_(server_context.mainThreadDispatcher()), 59 : validation_visitor_(server_context.messageValidationVisitor()), 60 : log_manager_(server_context.accessLogManager()), api_(server_context.api()), 61 0 : server_context_(server_context) {} 62 0 : Upstream::Cluster& cluster() override { return cluster_; } 63 0 : Envoy::Runtime::Loader& runtime() override { return runtime_; } 64 0 : Event::Dispatcher& mainThreadDispatcher() override { return dispatcher_; } 65 0 : HealthCheckEventLoggerPtr eventLogger() override { return std::move(event_logger_); } 66 0 : ProtobufMessage::ValidationVisitor& messageValidationVisitor() override { 67 0 : return validation_visitor_; 68 0 : } 69 0 : Api::Api& api() override { return api_; } 70 : 71 0 : AccessLog::AccessLogManager& accessLogManager() override { return log_manager_; } 72 0 : void setEventLogger(HealthCheckEventLoggerPtr event_logger) override { 73 0 : event_logger_ = std::move(event_logger); 74 0 : } 75 : 76 0 : Server::Configuration::ServerFactoryContext& serverFactoryContext() override { 77 0 : return server_context_; 78 0 : }; 79 : 80 : private: 81 : Upstream::Cluster& cluster_; 82 : Envoy::Runtime::Loader& runtime_; 83 : Event::Dispatcher& dispatcher_; 84 : ProtobufMessage::ValidationVisitor& validation_visitor_; 85 : AccessLog::AccessLogManager& log_manager_; 86 : Api::Api& api_; 87 : HealthCheckEventLoggerPtr event_logger_; 88 : Server::Configuration::ServerFactoryContext& server_context_; 89 : }; 90 : 91 : /** 92 : * Factory for creating health checker implementations. 93 : */ 94 : class HealthCheckerFactory : public Logger::Loggable<Logger::Id::health_checker> { 95 : public: 96 : // Helper functions to get the correct hostname for an L7 health check. 97 : static const std::string& getHostname(const HostSharedPtr& host, 98 : const std::string& config_hostname, 99 : const ClusterInfoConstSharedPtr& cluster); 100 : /** 101 : * Create a health checker or return an error. 102 : * @param health_check_config supplies the health check proto. 103 : * @param cluster supplies the owning cluster. 104 : * @param server_context reference to the Server context object 105 : * @return a health checker. 106 : */ 107 : static absl::StatusOr<HealthCheckerSharedPtr> 108 : create(const envoy::config::core::v3::HealthCheck& health_check_config, 109 : Upstream::Cluster& cluster, Server::Configuration::ServerFactoryContext& server_context); 110 : }; 111 : 112 : /** 113 : * Utility class for loading a binary health checking config and matching it against a buffer. 114 : * Split out for ease of testing. The type of matching performed is the following (this is the 115 : * MongoDB health check request and response): 116 : * 117 : * "send": [ 118 : {"text": "39000000"}, 119 : {"text": "EEEEEEEE"}, 120 : {"text": "00000000"}, 121 : {"text": "d4070000"}, 122 : {"text": "00000000"}, 123 : {"text": "746573742e"}, 124 : {"text": "24636d6400"}, 125 : {"text": "00000000"}, 126 : {"text": "FFFFFFFF"}, 127 : 128 : {"text": "13000000"}, 129 : {"text": "01"}, 130 : {"text": "70696e6700"}, 131 : {"text": "000000000000f03f"}, 132 : {"text": "00"} 133 : ], 134 : "receive": [ 135 : {"text": "EEEEEEEE"}, 136 : {"text": "01000000"}, 137 : {"text": "00000000"}, 138 : {"text": "0000000000000000"}, 139 : {"text": "00000000"}, 140 : {"text": "11000000"}, 141 : {"text": "01"}, 142 : {"text": "6f6b"}, 143 : {"text": "00000000000000f03f"}, 144 : {"text": "00"} 145 : ] 146 : * Each text or binary filed in Payload is converted to a binary block. 147 : * The text is Hex string by default. 148 : * 149 : * During each health check cycle, all of the "send" bytes are sent to the target server. Each 150 : * binary block can be of arbitrary length and is just concatenated together when sent. 151 : * 152 : * On the receive side, "fuzzy" matching is performed such that each binary block must be found, 153 : * and in the order specified, but not necessary contiguous. Thus, in the example above, 154 : * "FFFFFFFF" could be inserted in the response between "EEEEEEEE" and "01000000" and the check 155 : * would still pass. 156 : * 157 : */ 158 : class PayloadMatcher { 159 : public: 160 : using MatchSegments = std::list<std::vector<uint8_t>>; 161 : 162 : static absl::StatusOr<MatchSegments> loadProtoBytes( 163 : const Protobuf::RepeatedPtrField<envoy::config::core::v3::HealthCheck::Payload>& byte_array); 164 : static bool match(const MatchSegments& expected, const Buffer::Instance& buffer); 165 : }; 166 : 167 : } // namespace Upstream 168 : } // namespace Envoy