Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

health_check: add Cached custom health checker #24742

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ extensions/filters/http/oauth2 @derekargueta @snowp
/*/extensions/path/uri_template_lib @alyssawilk @yanjunxiang-google
/*/extensions/path/uri_template_lib/proto @alyssawilk @yanjunxiang-google

# cached health checker extension
/*/extensions/health_checkers/cached @hudayou @mainx07 @mattklein123

# mobile
/mobile/ @jpsim @Augustyniak @RyanTheOptimist @alyssawilk @abeyad

Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ proto_library(
"//envoy/extensions/filters/udp/udp_proxy/v3:pkg",
"//envoy/extensions/formatter/metadata/v3:pkg",
"//envoy/extensions/formatter/req_without_query/v3:pkg",
"//envoy/extensions/health_checkers/cached/v3:pkg",
"//envoy/extensions/health_checkers/redis/v3:pkg",
"//envoy/extensions/health_checkers/thrift/v3:pkg",
"//envoy/extensions/http/cache/file_system_http_cache/v3:pkg",
Expand Down
1 change: 1 addition & 0 deletions api/envoy/data/core/v3/health_check_event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum HealthCheckerType {
GRPC = 2;
REDIS = 3;
THRIFT = 4;
CACHED = 5;
}

// [#next-free-field: 10]
Expand Down
9 changes: 9 additions & 0 deletions api/envoy/extensions/health_checkers/cached/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"],
)
73 changes: 73 additions & 0 deletions api/envoy/extensions/health_checkers/cached/v3/cached.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
syntax = "proto3";

package envoy.extensions.health_checkers.cached.v3;

import "google/protobuf/duration.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.health_checkers.cached.v3";
option java_outer_classname = "CachedProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/health_checkers/cached/v3;cachedv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Cached]
// Cached health checker :ref:`configuration overview <config_health_checkers_cached>`.
// [#extension: envoy.health_checkers.cached]

// [#next-free-field: 9]
message Cached {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can/should the cached server be an upstream cluster?
This should take care of all the connection parameters.

Copy link
Contributor Author

@hudayou hudayou Jan 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this parameters are for a cache server
The purpose is to avoid query upstream cluster and just use the cache

https://github.com/envoyproxy/envoy/blob/badad5f2aadde7523be4e422146ff10a099055db/source/extensions/health_checkers/cached/hiredis.cc

// [#next-free-field: 7]
message TlsOptions {
// whether tls is enabled for the cache server.
bool enabled = 1;

// cacert is an optional name of a CA certificate/bundle file to load
// and use for validation of the cache server.
string cacert = 2;

// capath is an optional directory path where trusted CA certificate files are
// stored in an OpenSSL-compatible structure.
string capath = 3;

// cert and key are optional names of a client side
// certificate and private key files to use for authentication. They need to
// be both specified or omitted.
string cert = 4;

// cert and key are optional names of a client side
// certificate and private key files to use for authentication. They need to
// be both specified or omitted.
string key = 5;

// sni is an optional and will be used as a server name indication
// (SNI) TLS extension.
string sni = 6;
}

// hostname of the cache server.
string host = 1;

// port number of the cache server.
uint32 port = 2 [(validate.rules).uint32 = {lte: 65535}];

// username used to authenticate with the cache server.
string user = 3;

// password used to authenticate with the cache server.
string password = 4;

// database number of the cache server.
uint32 db = 5 [(validate.rules).uint32 = {lt: 2147483647}];

// connect timeout of the cache server.
google.protobuf.Duration connect_timeout = 6;

// command timeout of the cache server.
google.protobuf.Duration command_timeout = 7;

// tls options of the cache server.
TlsOptions tls_options = 8;
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ proto_library(
"//envoy/extensions/filters/udp/udp_proxy/v3:pkg",
"//envoy/extensions/formatter/metadata/v3:pkg",
"//envoy/extensions/formatter/req_without_query/v3:pkg",
"//envoy/extensions/health_checkers/cached/v3:pkg",
"//envoy/extensions/health_checkers/redis/v3:pkg",
"//envoy/extensions/health_checkers/thrift/v3:pkg",
"//envoy/extensions/http/cache/file_system_http_cache/v3:pkg",
Expand Down
27 changes: 27 additions & 0 deletions bazel/foreign_cc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,33 @@ envoy_cmake(
],
)

envoy_cmake(
name = "hiredis",
cache_entries = {
"ENABLE_SSL": "on",
"DISABLE_TESTS": "on",
},
env = {
"CXXFLAGS": "-fPIC",
"CFLAGS": "-fPIC",
},
lib_source = "@com_github_hiredis//:all",
out_static_libs = select({
"//bazel:windows_x86_64": [
"hiredis_static.lib",
"hiredis_ssl_static.lib",
],
"//conditions:default": [
"libhiredis.a",
"libhiredis_ssl.a",
],
}),
deps = [
"//external:crypto",
"//external:ssl",
],
)

envoy_cmake(
name = "event",
cache_entries = {
Expand Down
103 changes: 103 additions & 0 deletions bazel/foreign_cc/hiredis.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d52d0c..e03b5d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,9 +44,7 @@ IF(WIN32)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN)
ENDIF()

-ADD_LIBRARY(hiredis SHARED ${hiredis_sources})
ADD_LIBRARY(hiredis_static STATIC ${hiredis_sources})
-ADD_LIBRARY(hiredis::hiredis ALIAS hiredis)
ADD_LIBRARY(hiredis::hiredis_static ALIAS hiredis_static)

IF(NOT MSVC)
@@ -54,25 +52,18 @@ IF(NOT MSVC)
PROPERTIES OUTPUT_NAME hiredis)
ENDIF()

-SET_TARGET_PROPERTIES(hiredis
- PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE
- VERSION "${HIREDIS_SONAME}")
IF(MSVC)
SET_TARGET_PROPERTIES(hiredis_static
PROPERTIES COMPILE_FLAGS /Z7)
ENDIF()
IF(WIN32 OR MINGW)
- TARGET_LINK_LIBRARIES(hiredis PUBLIC ws2_32 crypt32)
TARGET_LINK_LIBRARIES(hiredis_static PUBLIC ws2_32 crypt32)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- TARGET_LINK_LIBRARIES(hiredis PUBLIC m)
TARGET_LINK_LIBRARIES(hiredis_static PUBLIC m)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
- TARGET_LINK_LIBRARIES(hiredis PUBLIC socket)
TARGET_LINK_LIBRARIES(hiredis_static PUBLIC socket)
ENDIF()

-TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
TARGET_INCLUDE_DIRECTORIES(hiredis_static PUBLIC $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
@@ -103,7 +94,7 @@ set(CPACK_RPM_PACKAGE_AUTOREQPROV ON)

include(CPack)

-INSTALL(TARGETS hiredis hiredis_static
+INSTALL(TARGETS hiredis_static
EXPORT hiredis-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -161,8 +152,6 @@ IF(ENABLE_SSL)
FIND_PACKAGE(OpenSSL REQUIRED)
SET(hiredis_ssl_sources
ssl.c)
- ADD_LIBRARY(hiredis_ssl SHARED
- ${hiredis_ssl_sources})
ADD_LIBRARY(hiredis_ssl_static STATIC
${hiredis_ssl_sources})
IF(NOT MSVC)
@@ -174,26 +163,19 @@ IF(ENABLE_SSL)
SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup")
ENDIF()

- SET_TARGET_PROPERTIES(hiredis_ssl
- PROPERTIES
- WINDOWS_EXPORT_ALL_SYMBOLS TRUE
- VERSION "${HIREDIS_SONAME}")
IF(MSVC)
SET_TARGET_PROPERTIES(hiredis_ssl_static
PROPERTIES COMPILE_FLAGS /Z7)
ENDIF()

- TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl_static PRIVATE "${OPENSSL_INCLUDE_DIR}")

- TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
IF (WIN32 OR MINGW)
- TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis)
TARGET_LINK_LIBRARIES(hiredis_ssl_static PUBLIC hiredis_static)
ENDIF()
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)

- INSTALL(TARGETS hiredis_ssl hiredis_ssl_static
+ INSTALL(TARGETS hiredis_ssl_static
EXPORT hiredis_ssl-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/ssl.c b/ssl.c
index 7d7ff66..491ce5a 100644
--- a/ssl.c
+++ b/ssl.c
@@ -40,6 +40,12 @@
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
#else
#include <pthread.h>
#endif
16 changes: 16 additions & 0 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def envoy_dependencies(skip_targets = []):
_com_google_protobuf()
_io_opencensus_cpp()
_com_github_curl()
_com_github_hiredis()
_com_github_envoyproxy_sqlparser()
_v8()
_com_googlesource_chromium_base_trace_event_common()
Expand Down Expand Up @@ -862,6 +863,21 @@ cc_library(name = "curl", visibility = ["//visibility:public"], deps = ["@envoy/
actual = "@envoy//bazel/foreign_cc:curl",
)

def _com_github_hiredis():
external_http_archive(
name = "com_github_hiredis",
build_file_content = BUILD_ALL_CONTENT + """
cc_library(name = "hiredis", visibility = ["//visibility:public"], deps = ["@envoy//bazel/foreign_cc:hiredis"])
""",
# To fix wincrypt symbols conflict
patches = ["@envoy//bazel/foreign_cc:hiredis.patch"],
patch_args = ["-p1"],
)
native.bind(
name = "hiredis",
actual = "@envoy//bazel/foreign_cc:hiredis",
)

def _v8():
external_http_archive(
name = "v8",
Expand Down
17 changes: 17 additions & 0 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,23 @@ REPOSITORY_LOCATIONS_SPEC = dict(
license = "curl",
license_url = "https://github.com/curl/curl/blob/curl-{underscore_version}/COPYING",
),
com_github_hiredis = dict(
project_name = "hiredis",
project_desc = "Minimalistic C client for Redis >= 1.2",
project_url = "https://github.com/redis/hiredis",
version = "1.1.0",
sha256 = "fe6d21741ec7f3fc9df409d921f47dfc73a4d8ff64f4ac6f1d95f951bf7f53d6",
strip_prefix = "hiredis-{version}",
urls = ["https://github.com/redis/hiredis/archive/refs/tags/v{version}.tar.gz"],
use_category = ["dataplane_ext"],
extensions = [
"envoy.health_checkers.cached",
],
release_date = "2022-11-16",
cpe = "N/A",
license = "BSD-3-Clause",
license_url = "https://github.com/redis/hiredis/blob/v{version}/COPYING",
),
v8 = dict(
project_name = "V8",
project_desc = "Google’s open source high-performance JavaScript and WebAssembly engine, written in C++",
Expand Down
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ new_features:
- area: health_check
change: |
added an optional bool flag :ref:`disable_active_health_check <envoy_v3_api_field_config.endpoint.v3.Endpoint.HealthCheckConfig.disable_active_health_check>` to disable the active health check for the endpoint.
- area: health check
change: |
added :ref:`cached health check <envoy_v3_api_msg_extensions.health_checkers.cached.v3.Cached>` as a :ref:`custom health check <envoy_v3_api_msg_config.core.v3.HealthCheck.CustomHealthCheck>`.
- area: mobile
change: |
started merging the Envoy mobile library into the main Envoy repo.
Expand Down
31 changes: 31 additions & 0 deletions docs/root/configuration/upstream/health_checkers/cached.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.. _config_health_checkers_cached:

Cached Health Checker
=====================

The Cached Health Checker (with :code:`envoy.health_checkers.cached` as name) subscribe to a redis cache for upstream host health check notification.
Once the health check result is set in the redis cache by a third party checker, a keyspace set event is recevied from the redis cache, then it get
the health check result and store it in a in memory cache.


An example for :ref:`custom_health_check <envoy_v3_api_msg_config.core.v3.HealthCheck.CustomHealthCheck>`
using the Cached health checker is shown below:


.. code-block:: yaml

custom_health_check:
name: envoy.health_checkers.cached
typed_config:
"@type": type.googleapis.com/envoy.extensions.health_checkers.cached.v3.Cached
host: localhost
port: 6400
password: foobared
db: 100
tls_options:
enabled: true
cacert: /etc/redis/ca.crt
cert: /etc/redis/client.crt
key: /etc/redis/client.key

* :ref:`v3 API reference <envoy_v3_api_msg_config.core.v3.HealthCheck.CustomHealthCheck>`
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ Health checkers
.. toctree::
:maxdepth: 2

cached
redis
thrift
3 changes: 3 additions & 0 deletions docs/root/intro/arch_overview/upstream/health_checking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ unhealthy, successes required before marking a host healthy, etc.):
* **L3/L4**: During L3/L4 health checking, Envoy will send a configurable byte buffer to the
upstream host. It expects the byte buffer to be echoed in the response if the host is to be
considered healthy. Envoy also supports connect only L3/L4 health checking.
* **Cached**: With cached health checking, Envoy will subscribe to a Redis cache and get the cached
health check result once receiving the keyspace key set events from it. See
:ref:`cached <envoy_v3_api_msg_extensions.health_checkers.cached.v3.Cached>`.
* **Redis**: Envoy will send a Redis PING command and expect a PONG response. The upstream Redis
server can respond with anything other than PONG to cause an immediate active health check
failure. Optionally, Envoy can perform EXISTS on a user-specified key. If the key does not exist
Expand Down
6 changes: 6 additions & 0 deletions envoy/server/health_checker_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "envoy/config/core/v3/health_check.pb.h"
#include "envoy/config/typed_config.h"
#include "envoy/runtime/runtime.h"
#include "envoy/singleton/manager.h"
#include "envoy/upstream/health_checker.h"

namespace Envoy {
Expand Down Expand Up @@ -46,6 +47,11 @@ class HealthCheckerFactoryContext {
* @return Api::Api& the API used by the server.
*/
virtual Api::Api& api() PURE;

/**
* @return Singleton::Manager& the server-wide singleton manager.
*/
virtual Singleton::Manager& singletonManager() PURE;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion source/common/upstream/cluster_factory_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ ClusterFactoryImplBase::create(Server::Configuration::ServerFactoryContext& serv
new_cluster_pair.first->setHealthChecker(HealthCheckerFactory::create(
cluster.health_checks()[0], *new_cluster_pair.first, context.runtime(),
context.mainThreadDispatcher(), context.logManager(), context.messageValidationVisitor(),
context.api()));
context.api(), context.singletonManager()));
}
}

Expand Down
Loading