Line data Source code
1 : #include "source/common/upstream/health_checker_impl.h" 2 : 3 : #include <cstdint> 4 : #include <iterator> 5 : #include <memory> 6 : 7 : #include "envoy/config/core/v3/health_check.pb.h" 8 : #include "envoy/data/core/v3/health_check_event.pb.h" 9 : #include "envoy/server/health_checker_config.h" 10 : #include "envoy/type/v3/http.pb.h" 11 : #include "envoy/type/v3/range.pb.h" 12 : 13 : #include "source/common/buffer/zero_copy_input_stream_impl.h" 14 : #include "source/common/common/empty_string.h" 15 : #include "source/common/common/enum_to_int.h" 16 : #include "source/common/common/macros.h" 17 : #include "source/common/config/utility.h" 18 : #include "source/common/config/well_known_names.h" 19 : #include "source/common/grpc/common.h" 20 : #include "source/common/http/header_map_impl.h" 21 : #include "source/common/http/header_utility.h" 22 : #include "source/common/network/address_impl.h" 23 : #include "source/common/network/socket_impl.h" 24 : #include "source/common/network/utility.h" 25 : #include "source/common/router/router.h" 26 : #include "source/common/runtime/runtime_features.h" 27 : #include "source/common/upstream/host_utility.h" 28 : 29 : #include "absl/strings/match.h" 30 : #include "absl/strings/str_cat.h" 31 : 32 : namespace Envoy { 33 : namespace Upstream { 34 : 35 : // Helper functions to get the correct hostname for an L7 health check. 36 : const std::string& HealthCheckerFactory::getHostname(const HostSharedPtr& host, 37 : const std::string& config_hostname, 38 48 : const ClusterInfoConstSharedPtr& cluster) { 39 48 : if (!host->hostnameForHealthChecks().empty()) { 40 0 : return host->hostnameForHealthChecks(); 41 0 : } 42 : 43 48 : if (!config_hostname.empty()) { 44 2 : return config_hostname; 45 2 : } 46 : 47 46 : return cluster->name(); 48 48 : } 49 : 50 : absl::StatusOr<HealthCheckerSharedPtr> 51 : HealthCheckerFactory::create(const envoy::config::core::v3::HealthCheck& health_check_config, 52 : Upstream::Cluster& cluster, 53 0 : Server::Configuration::ServerFactoryContext& server_context) { 54 0 : Server::Configuration::CustomHealthCheckerFactory* factory = nullptr; 55 : 56 0 : switch (health_check_config.health_checker_case()) { 57 0 : case envoy::config::core::v3::HealthCheck::HealthCheckerCase::HEALTH_CHECKER_NOT_SET: 58 0 : return absl::InvalidArgumentError("invalid cluster config"); 59 0 : case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kHttpHealthCheck: 60 0 : factory = &Config::Utility::getAndCheckFactoryByName< 61 0 : Server::Configuration::CustomHealthCheckerFactory>("envoy.health_checkers.http"); 62 0 : break; 63 0 : case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kTcpHealthCheck: 64 0 : factory = &Config::Utility::getAndCheckFactoryByName< 65 0 : Server::Configuration::CustomHealthCheckerFactory>("envoy.health_checkers.tcp"); 66 0 : break; 67 0 : case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kGrpcHealthCheck: 68 0 : if (!(cluster.info()->features() & Upstream::ClusterInfo::Features::HTTP2)) { 69 0 : return absl::InvalidArgumentError(fmt::format( 70 0 : "{} cluster must support HTTP/2 for gRPC healthchecking", cluster.info()->name())); 71 0 : } 72 0 : factory = &Config::Utility::getAndCheckFactoryByName< 73 0 : Server::Configuration::CustomHealthCheckerFactory>("envoy.health_checkers.grpc"); 74 0 : break; 75 0 : case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kCustomHealthCheck: { 76 0 : factory = 77 0 : &Config::Utility::getAndCheckFactory<Server::Configuration::CustomHealthCheckerFactory>( 78 0 : health_check_config.custom_health_check()); 79 0 : } 80 0 : } 81 : 82 0 : std::unique_ptr<Server::Configuration::HealthCheckerFactoryContext> context( 83 0 : new HealthCheckerFactoryContextImpl(cluster, server_context)); 84 : 85 0 : if (!health_check_config.event_log_path().empty() /* deprecated */ || 86 0 : !health_check_config.event_logger().empty()) { 87 0 : HealthCheckEventLoggerPtr event_logger; 88 0 : event_logger = std::make_unique<HealthCheckEventLoggerImpl>(health_check_config, *context); 89 0 : context->setEventLogger(std::move(event_logger)); 90 0 : } 91 0 : return factory->createCustomHealthChecker(health_check_config, *context); 92 0 : } 93 : 94 : absl::StatusOr<PayloadMatcher::MatchSegments> PayloadMatcher::loadProtoBytes( 95 44 : const Protobuf::RepeatedPtrField<envoy::config::core::v3::HealthCheck::Payload>& byte_array) { 96 44 : MatchSegments result; 97 : 98 44 : for (const auto& entry : byte_array) { 99 18 : std::vector<uint8_t> decoded; 100 18 : if (entry.has_text()) { 101 17 : decoded = Hex::decode(entry.text()); 102 17 : if (decoded.empty()) { 103 0 : return absl::InvalidArgumentError(fmt::format("invalid hex string '{}'", entry.text())); 104 0 : } 105 17 : } else { 106 1 : decoded.assign(entry.binary().begin(), entry.binary().end()); 107 1 : } 108 18 : if (!decoded.empty()) { 109 18 : result.push_back(decoded); 110 18 : } 111 18 : } 112 : 113 44 : return result; 114 44 : } 115 : 116 11 : bool PayloadMatcher::match(const MatchSegments& expected, const Buffer::Instance& buffer) { 117 11 : uint64_t start_index = 0; 118 11 : for (const std::vector<uint8_t>& segment : expected) { 119 8 : ssize_t search_result = buffer.search(segment.data(), segment.size(), start_index); 120 8 : if (search_result == -1) { 121 5 : return false; 122 5 : } 123 : 124 3 : start_index = search_result + segment.size(); 125 3 : } 126 : 127 6 : return true; 128 11 : } 129 : 130 0 : std::ostream& operator<<(std::ostream& out, HealthState state) { 131 0 : switch (state) { 132 0 : case HealthState::Unhealthy: 133 0 : out << "Unhealthy"; 134 0 : break; 135 0 : case HealthState::Healthy: 136 0 : out << "Healthy"; 137 0 : break; 138 0 : } 139 0 : return out; 140 0 : } 141 : 142 0 : std::ostream& operator<<(std::ostream& out, HealthTransition changed_state) { 143 0 : switch (changed_state) { 144 0 : case HealthTransition::Unchanged: 145 0 : out << "Unchanged"; 146 0 : break; 147 0 : case HealthTransition::Changed: 148 0 : out << "Changed"; 149 0 : break; 150 0 : case HealthTransition::ChangePending: 151 0 : out << "ChangePending"; 152 0 : break; 153 0 : } 154 0 : return out; 155 0 : } 156 : 157 : } // namespace Upstream 158 : } // namespace Envoy