diff --git a/CMakeLists.txt b/CMakeLists.txt
index d2980d57c78ab..bc696ef510372 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -676,6 +676,9 @@ protobuf_generate_grpc_cpp_with_import_path_correction(
protobuf_generate_grpc_cpp_with_import_path_correction(
src/proto/grpc/testing/xds/v3/fault_common.proto src/proto/grpc/testing/xds/v3/fault_common.proto
)
+protobuf_generate_grpc_cpp_with_import_path_correction(
+ src/proto/grpc/testing/xds/v3/health_check.proto src/proto/grpc/testing/xds/v3/health_check.proto
+)
protobuf_generate_grpc_cpp_with_import_path_correction(
src/proto/grpc/testing/xds/v3/http_connection_manager.proto src/proto/grpc/testing/xds/v3/http_connection_manager.proto
)
@@ -2079,6 +2082,7 @@ add_library(grpc
src/core/ext/xds/xds_cluster_specifier_plugin.cc
src/core/ext/xds/xds_common_types.cc
src/core/ext/xds/xds_endpoint.cc
+ src/core/ext/xds/xds_health_status.cc
src/core/ext/xds/xds_http_fault_filter.cc
src/core/ext/xds/xds_http_filters.cc
src/core/ext/xds/xds_http_rbac_filter.cc
@@ -22259,6 +22263,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -22398,6 +22406,10 @@ add_executable(xds_cluster_resource_type_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.pb.h
@@ -22524,6 +22536,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -22768,6 +22784,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -23042,6 +23062,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -23218,6 +23242,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -23345,6 +23373,10 @@ add_executable(xds_endpoint_resource_type_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h
@@ -23447,6 +23479,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -23860,6 +23896,10 @@ add_executable(xds_lb_policy_registry_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.pb.h
@@ -24129,6 +24169,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -24370,6 +24414,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -24542,6 +24590,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -24830,6 +24882,10 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
diff --git a/Makefile b/Makefile
index 1e42f9f29068c..ab772200ee08b 100644
--- a/Makefile
+++ b/Makefile
@@ -1362,6 +1362,7 @@ LIBGRPC_SRC = \
src/core/ext/xds/xds_cluster_specifier_plugin.cc \
src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_endpoint.cc \
+ src/core/ext/xds/xds_health_status.cc \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_filters.cc \
src/core/ext/xds/xds_http_rbac_filter.cc \
@@ -3203,6 +3204,7 @@ src/core/ext/xds/xds_cluster.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_cluster_specifier_plugin.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_common_types.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_endpoint.cc: $(OPENSSL_DEP)
+src/core/ext/xds/xds_health_status.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_http_fault_filter.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_http_filters.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_http_rbac_filter.cc: $(OPENSSL_DEP)
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index f247570fe248f..5b67cfa92db37 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -705,6 +705,7 @@ libs:
- src/core/ext/xds/xds_cluster_specifier_plugin.h
- src/core/ext/xds/xds_common_types.h
- src/core/ext/xds/xds_endpoint.h
+ - src/core/ext/xds/xds_health_status.h
- src/core/ext/xds/xds_http_fault_filter.h
- src/core/ext/xds/xds_http_filters.h
- src/core/ext/xds/xds_http_rbac_filter.h
@@ -1459,6 +1460,7 @@ libs:
- src/core/ext/xds/xds_cluster_specifier_plugin.cc
- src/core/ext/xds/xds_common_types.cc
- src/core/ext/xds/xds_endpoint.cc
+ - src/core/ext/xds/xds_health_status.cc
- src/core/ext/xds/xds_http_fault_filter.cc
- src/core/ext/xds/xds_http_filters.cc
- src/core/ext/xds/xds_http_rbac_filter.cc
@@ -12512,6 +12514,7 @@ targets:
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/expr.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -12555,6 +12558,7 @@ targets:
- src/proto/grpc/testing/xds/v3/config_source.proto
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/outlier_detection.proto
- src/proto/grpc/testing/xds/v3/percent.proto
- src/proto/grpc/testing/xds/v3/regex.proto
@@ -12594,6 +12598,7 @@ targets:
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/expr.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -12681,6 +12686,7 @@ targets:
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/expr.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -12785,6 +12791,7 @@ targets:
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/expr.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -12842,6 +12849,7 @@ targets:
- src/proto/grpc/testing/xds/v3/extension.proto
- src/proto/grpc/testing/xds/v3/fault.proto
- src/proto/grpc/testing/xds/v3/fault_common.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -12876,11 +12884,13 @@ targets:
gtest: true
build: test
language: c++
- headers: []
+ headers:
+ - test/core/util/scoped_env_var.h
src:
- src/proto/grpc/testing/xds/v3/address.proto
- src/proto/grpc/testing/xds/v3/base.proto
- src/proto/grpc/testing/xds/v3/endpoint.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/percent.proto
- test/core/xds/xds_endpoint_resource_type_test.cc
deps:
@@ -12913,6 +12923,7 @@ targets:
- src/proto/grpc/testing/xds/v3/extension.proto
- src/proto/grpc/testing/xds/v3/fault.proto
- src/proto/grpc/testing/xds/v3/fault_common.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -13053,6 +13064,7 @@ targets:
- src/proto/grpc/testing/xds/v3/config_source.proto
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/outlier_detection.proto
- src/proto/grpc/testing/xds/v3/percent.proto
- src/proto/grpc/testing/xds/v3/ring_hash.proto
@@ -13144,6 +13156,7 @@ targets:
- src/proto/grpc/testing/xds/v3/extension.proto
- src/proto/grpc/testing/xds/v3/fault.proto
- src/proto/grpc/testing/xds/v3/fault_common.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -13218,6 +13231,7 @@ targets:
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/expr.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -13275,6 +13289,7 @@ targets:
- src/proto/grpc/testing/xds/v3/endpoint.proto
- src/proto/grpc/testing/xds/v3/expr.proto
- src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
@@ -13373,6 +13388,7 @@ targets:
- src/proto/grpc/testing/xds/v3/extension.proto
- src/proto/grpc/testing/xds/v3/fault.proto
- src/proto/grpc/testing/xds/v3/fault_common.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
- src/proto/grpc/testing/xds/v3/http_connection_manager.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/listener.proto
diff --git a/config.m4 b/config.m4
index d08006262f675..db476c3bb391f 100644
--- a/config.m4
+++ b/config.m4
@@ -445,6 +445,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/xds/xds_cluster_specifier_plugin.cc \
src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_endpoint.cc \
+ src/core/ext/xds/xds_health_status.cc \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_filters.cc \
src/core/ext/xds/xds_http_rbac_filter.cc \
diff --git a/config.w32 b/config.w32
index a18ab80c5c1dd..3edbcb8466d39 100644
--- a/config.w32
+++ b/config.w32
@@ -411,6 +411,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\xds\\xds_cluster_specifier_plugin.cc " +
"src\\core\\ext\\xds\\xds_common_types.cc " +
"src\\core\\ext\\xds\\xds_endpoint.cc " +
+ "src\\core\\ext\\xds\\xds_health_status.cc " +
"src\\core\\ext\\xds\\xds_http_fault_filter.cc " +
"src\\core\\ext\\xds\\xds_http_filters.cc " +
"src\\core\\ext\\xds\\xds_http_rbac_filter.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index dde1e1c995f5d..90811ceefccfe 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -664,6 +664,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_cluster_specifier_plugin.h',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.h',
+ 'src/core/ext/xds/xds_health_status.h',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_http_rbac_filter.h',
@@ -1561,6 +1562,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_cluster_specifier_plugin.h',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.h',
+ 'src/core/ext/xds/xds_health_status.h',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_http_rbac_filter.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index f9953080c4c87..54e3d01a4aa1f 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -993,6 +993,8 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.cc',
'src/core/ext/xds/xds_endpoint.h',
+ 'src/core/ext/xds/xds_health_status.cc',
+ 'src/core/ext/xds/xds_health_status.h',
'src/core/ext/xds/xds_http_fault_filter.cc',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.cc',
@@ -2201,6 +2203,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_cluster_specifier_plugin.h',
'src/core/ext/xds/xds_common_types.h',
'src/core/ext/xds/xds_endpoint.h',
+ 'src/core/ext/xds/xds_health_status.h',
'src/core/ext/xds/xds_http_fault_filter.h',
'src/core/ext/xds/xds_http_filters.h',
'src/core/ext/xds/xds_http_rbac_filter.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index e7d14bfb13b5d..72a23ce55b9c4 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -904,6 +904,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/xds/xds_common_types.h )
s.files += %w( src/core/ext/xds/xds_endpoint.cc )
s.files += %w( src/core/ext/xds/xds_endpoint.h )
+ s.files += %w( src/core/ext/xds/xds_health_status.cc )
+ s.files += %w( src/core/ext/xds/xds_health_status.h )
s.files += %w( src/core/ext/xds/xds_http_fault_filter.cc )
s.files += %w( src/core/ext/xds/xds_http_fault_filter.h )
s.files += %w( src/core/ext/xds/xds_http_filters.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 98e9c9593904c..77237bac74562 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -775,6 +775,7 @@
'src/core/ext/xds/xds_cluster_specifier_plugin.cc',
'src/core/ext/xds/xds_common_types.cc',
'src/core/ext/xds/xds_endpoint.cc',
+ 'src/core/ext/xds/xds_health_status.cc',
'src/core/ext/xds/xds_http_fault_filter.cc',
'src/core/ext/xds/xds_http_filters.cc',
'src/core/ext/xds/xds_http_rbac_filter.cc',
diff --git a/package.xml b/package.xml
index 126b014c63fc4..92b4ed1d3f7f4 100644
--- a/package.xml
+++ b/package.xml
@@ -886,6 +886,8 @@
+
+
diff --git a/src/core/BUILD b/src/core/BUILD
index aea67d366170a..ddd38f6c4f8e2 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -3578,6 +3578,7 @@ grpc_cc_library(
"ext/xds/xds_cluster_specifier_plugin.cc",
"ext/xds/xds_common_types.cc",
"ext/xds/xds_endpoint.cc",
+ "ext/xds/xds_health_status.cc",
"ext/xds/xds_http_fault_filter.cc",
"ext/xds/xds_http_filters.cc",
"ext/xds/xds_http_rbac_filter.cc",
@@ -3599,6 +3600,7 @@ grpc_cc_library(
"ext/xds/xds_cluster_specifier_plugin.h",
"ext/xds/xds_common_types.h",
"ext/xds/xds_endpoint.h",
+ "ext/xds/xds_health_status.h",
"ext/xds/xds_http_fault_filter.h",
"ext/xds/xds_http_filters.h",
"ext/xds/xds_http_rbac_filter.h",
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
index 8d31b99542281..239f92135e654 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
@@ -358,7 +358,7 @@ absl::Status CdsLb::UpdateLocked(UpdateArgs args) {
// Generates the discovery mechanism config for the specified cluster name.
//
-// If no CdsUpdate has been received for the cluster, starts the watcher
+// If no CDS update has been received for the cluster, starts the watcher
// if needed, and returns false. Otherwise, generates the discovery
// mechanism config, adds it to *discovery_mechanisms, and returns true.
//
@@ -462,6 +462,13 @@ absl::StatusOr CdsLb::GenerateDiscoveryMechanismForCluster(
mechanism["lrsLoadReportingServer"] =
state.update->lrs_load_reporting_server->ToJson();
}
+ if (!state.update->host_override_statuses.empty()) {
+ Json::Array status_list;
+ for (const auto& status : state.update->host_override_statuses) {
+ status_list.emplace_back(status.ToString());
+ }
+ mechanism["overrideHostStatus"] = std::move(status_list);
+ }
discovery_mechanisms->emplace_back(std::move(mechanism));
return true;
}
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
index 6035b796cef95..ae1c4cfd22a6b 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
@@ -97,6 +97,8 @@ class XdsClusterResolverLbConfig : public LoadBalancingPolicy::Config {
std::string eds_service_name;
std::string dns_hostname;
+ Json::Array host_override_statuses;
+
// This is type Json::Object instead of OutlierDetectionConfig, because we
// don't actually need to validate the contents of the outlier detection
// config here. In this case, the JSON is generated by the CDS policy
@@ -112,6 +114,7 @@ class XdsClusterResolverLbConfig : public LoadBalancingPolicy::Config {
type == other.type &&
eds_service_name == other.eds_service_name &&
dns_hostname == other.dns_hostname &&
+ host_override_statuses == other.host_override_statuses &&
outlier_detection_lb_config == other.outlier_detection_lb_config);
}
@@ -869,6 +872,7 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
for (size_t priority = 0;
priority < discovery_entry.latest_update->priorities.size();
++priority) {
+ // Determine what xDS LB policy to use.
Json child_policy;
if (!discovery_entry.discovery_mechanism->override_child_policy()
.empty()) {
@@ -877,7 +881,14 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
} else {
child_policy = config_->xds_lb_policy();
}
- // Wrap it in the drop policy.
+ // Wrap the xDS LB policy in the xds_override_host policy.
+ Json::Array xds_override_host_config = {Json::Object{
+ {"xds_override_host_experimental",
+ Json::Object{
+ {"overrideHostStatus", discovery_config.host_override_statuses},
+ {"childPolicy", std::move(child_policy)},
+ }}}};
+ // Wrap it in the xds_cluster_impl policy.
Json::Array drop_categories;
if (discovery_entry.latest_update->drop_config != nullptr) {
for (const auto& category :
@@ -890,7 +901,7 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
}
Json::Object xds_cluster_impl_config = {
{"clusterName", discovery_config.cluster_name},
- {"childPolicy", std::move(child_policy)},
+ {"childPolicy", std::move(xds_override_host_config)},
{"dropCategories", std::move(drop_categories)},
{"maxConcurrentRequests", discovery_config.max_concurrent_requests},
};
@@ -902,6 +913,7 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
xds_cluster_impl_config["lrsLoadReportingServer"] =
discovery_config.lrs_load_reporting_server->ToJson();
}
+ // Wrap it in the outlier_detection policy.
Json::Object outlier_detection_config;
if (discovery_entry.config().outlier_detection_lb_config.has_value()) {
outlier_detection_config =
@@ -1032,6 +1044,8 @@ XdsClusterResolverLbConfig::DiscoveryMechanism::JsonLoader(const JsonArgs&) {
&DiscoveryMechanism::max_concurrent_requests)
.OptionalField("outlierDetection",
&DiscoveryMechanism::outlier_detection_lb_config)
+ .OptionalField("overrideHostStatus",
+ &DiscoveryMechanism::host_override_statuses)
.Finish();
return loader;
}
diff --git a/src/core/ext/xds/xds_cluster.cc b/src/core/ext/xds/xds_cluster.cc
index 52f809d352415..309be09b18339 100644
--- a/src/core/ext/xds/xds_cluster.cc
+++ b/src/core/ext/xds/xds_cluster.cc
@@ -35,6 +35,7 @@
#include "envoy/config/core/v3/address.upb.h"
#include "envoy/config/core/v3/base.upb.h"
#include "envoy/config/core/v3/config_source.upb.h"
+#include "envoy/config/core/v3/health_check.upb.h"
#include "envoy/config/endpoint/v3/endpoint.upb.h"
#include "envoy/config/endpoint/v3/endpoint_components.upb.h"
#include "envoy/extensions/clusters/aggregate/v3/cluster.upb.h"
@@ -121,6 +122,15 @@ std::string XdsClusterResource::ToString() const {
}
contents.push_back(
absl::StrCat("max_concurrent_requests=", max_concurrent_requests));
+ if (!host_override_statuses.empty()) {
+ std::vector statuses;
+ statuses.reserve(host_override_statuses.size());
+ for (const auto& status : host_override_statuses) {
+ statuses.push_back(status.ToString());
+ }
+ contents.push_back(absl::StrCat("override_host_statuses={",
+ absl::StrJoin(statuses, ", "), "}"));
+ }
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
@@ -617,6 +627,29 @@ absl::StatusOr CdsResourceParse(
}
cds_update.outlier_detection = outlier_detection_update;
}
+ // Validate override host status.
+ if (XdsHostOverrideEnabled()) {
+ const auto* common_lb_config =
+ envoy_config_cluster_v3_Cluster_common_lb_config(cluster);
+ if (common_lb_config != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".common_lb_config");
+ const auto* override_host_status =
+ envoy_config_cluster_v3_Cluster_CommonLbConfig_override_host_status(
+ common_lb_config);
+ if (override_host_status != nullptr) {
+ ValidationErrors::ScopedField field(&errors, ".override_host_status");
+ size_t size;
+ const int32_t* statuses = envoy_config_core_v3_HealthStatusSet_statuses(
+ override_host_status, &size);
+ for (size_t i = 0; i < size; ++i) {
+ auto status = XdsHealthStatus::FromUpb(statuses[i]);
+ if (status.has_value()) {
+ cds_update.host_override_statuses.insert(*status);
+ }
+ }
+ }
+ }
+ }
// Return result.
if (!errors.ok()) return errors.status("errors validating Cluster resource");
return cds_update;
diff --git a/src/core/ext/xds/xds_cluster.h b/src/core/ext/xds/xds_cluster.h
index a8812c1a28d46..d070abb68c757 100644
--- a/src/core/ext/xds/xds_cluster.h
+++ b/src/core/ext/xds/xds_cluster.h
@@ -38,6 +38,7 @@
#include "src/core/ext/xds/xds_bootstrap_grpc.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/ext/xds/xds_common_types.h"
+#include "src/core/ext/xds/xds_health_status.h"
#include "src/core/ext/xds/xds_resource_type.h"
#include "src/core/ext/xds/xds_resource_type_impl.h"
#include "src/core/lib/json/json.h"
@@ -95,12 +96,15 @@ struct XdsClusterResource : public XdsResourceType::ResourceData {
absl::optional outlier_detection;
+ std::set host_override_statuses;
+
bool operator==(const XdsClusterResource& other) const {
return type == other.type && lb_policy_config == other.lb_policy_config &&
lrs_load_reporting_server == other.lrs_load_reporting_server &&
common_tls_context == other.common_tls_context &&
max_concurrent_requests == other.max_concurrent_requests &&
- outlier_detection == other.outlier_detection;
+ outlier_detection == other.outlier_detection &&
+ host_override_statuses == other.host_override_statuses;
}
std::string ToString() const;
diff --git a/src/core/ext/xds/xds_endpoint.cc b/src/core/ext/xds/xds_endpoint.cc
index 180491a063749..e548a9415252d 100644
--- a/src/core/ext/xds/xds_endpoint.cc
+++ b/src/core/ext/xds/xds_endpoint.cc
@@ -44,6 +44,8 @@
#include
#include "src/core/ext/xds/upb_utils.h"
+#include "src/core/ext/xds/xds_cluster.h"
+#include "src/core/ext/xds/xds_health_status.h"
#include "src/core/ext/xds/xds_resource_type.h"
#include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
@@ -150,13 +152,15 @@ absl::optional ServerAddressParse(
const envoy_config_endpoint_v3_LbEndpoint* lb_endpoint,
ValidationErrors* errors) {
// health_status
- // If not HEALTHY or UNKNOWN, skip this endpoint.
const int32_t health_status =
envoy_config_endpoint_v3_LbEndpoint_health_status(lb_endpoint);
- if (health_status != envoy_config_core_v3_UNKNOWN &&
+ if (!XdsHostOverrideEnabled() &&
+ health_status != envoy_config_core_v3_UNKNOWN &&
health_status != envoy_config_core_v3_HEALTHY) {
return absl::nullopt;
}
+ auto status = XdsHealthStatus::FromUpb(health_status);
+ if (!status.has_value()) return absl::nullopt;
// load_balancing_weight
uint32_t weight = 1;
{
@@ -217,6 +221,8 @@ absl::optional ServerAddressParse(
attributes;
attributes[ServerAddressWeightAttribute::kServerAddressWeightAttributeKey] =
std::make_unique(weight);
+ attributes[XdsEndpointHealthStatusAttribute::kKey] =
+ std::make_unique(*status);
return ServerAddress(grpc_address, ChannelArgs(), std::move(attributes));
}
diff --git a/src/core/ext/xds/xds_health_status.cc b/src/core/ext/xds/xds_health_status.cc
new file mode 100644
index 0000000000000..4b0addf93c3ca
--- /dev/null
+++ b/src/core/ext/xds/xds_health_status.cc
@@ -0,0 +1,75 @@
+//
+// Copyright 2022 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include
+
+#include "src/core/ext/xds/xds_health_status.h"
+
+#include "envoy/config/core/v3/health_check.upb.h"
+
+namespace grpc_core {
+
+absl::optional XdsHealthStatus::FromUpb(uint32_t status) {
+ switch (status) {
+ case envoy_config_core_v3_UNKNOWN:
+ return XdsHealthStatus(kUnknown);
+ case envoy_config_core_v3_HEALTHY:
+ return XdsHealthStatus(kHealthy);
+ case envoy_config_core_v3_DRAINING:
+ return XdsHealthStatus(kDraining);
+ default:
+ return absl::nullopt;
+ }
+}
+
+absl::optional XdsHealthStatus::FromString(
+ absl::string_view status) {
+ if (status == "UNKNOWN") return XdsHealthStatus(kUnknown);
+ if (status == "HEALTHY") return XdsHealthStatus(kHealthy);
+ if (status == "DRAINING") return XdsHealthStatus(kDraining);
+ return absl::nullopt;
+}
+
+const char* XdsHealthStatus::ToString() const {
+ switch (status_) {
+ case kUnknown:
+ return "UNKNOWN";
+ case kHealthy:
+ return "HEALTHY";
+ case kDraining:
+ return "DRAINING";
+ }
+}
+
+bool operator<(const XdsHealthStatus& hs1, const XdsHealthStatus& hs2) {
+ return hs1.status() < hs2.status();
+}
+
+const char* XdsEndpointHealthStatusAttribute::kKey =
+ "xds_endpoint_health_status";
+
+int XdsEndpointHealthStatusAttribute::Cmp(
+ const AttributeInterface* other) const {
+ const auto* other_attr =
+ static_cast(other);
+ return QsortCompare(status_, other_attr->status_);
+}
+
+std::string XdsEndpointHealthStatusAttribute::ToString() const {
+ return absl::StrCat("{status_=", status_.ToString(), "}");
+}
+
+} // namespace grpc_core
diff --git a/src/core/ext/xds/xds_health_status.h b/src/core/ext/xds/xds_health_status.h
new file mode 100644
index 0000000000000..d92d69accfbee
--- /dev/null
+++ b/src/core/ext/xds/xds_health_status.h
@@ -0,0 +1,78 @@
+//
+// Copyright 2022 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef GRPC_CORE_EXT_XDS_XDS_HEALTH_STATUS_H
+#define GRPC_CORE_EXT_XDS_XDS_HEALTH_STATUS_H
+
+#include
+
+#include
+
+#include "absl/types/optional.h"
+
+#include "src/core/lib/resolver/server_address.h"
+
+namespace grpc_core {
+
+class XdsHealthStatus {
+ public:
+ enum HealthStatus { kUnknown, kHealthy, kDraining };
+
+ // Returns an XdsHealthStatus for supported enum values, else nullopt.
+ static absl::optional FromUpb(uint32_t status);
+ static absl::optional FromString(absl::string_view status);
+
+ explicit XdsHealthStatus(HealthStatus status) : status_(status) {}
+
+ HealthStatus status() const { return status_; }
+
+ bool operator==(const XdsHealthStatus& other) const {
+ return status_ == other.status_;
+ }
+
+ const char* ToString() const;
+
+ private:
+ HealthStatus status_;
+};
+
+bool operator<(const XdsHealthStatus& hs1, const XdsHealthStatus& hs2);
+
+class XdsEndpointHealthStatusAttribute
+ : public ServerAddress::AttributeInterface {
+ public:
+ static const char* kKey;
+
+ explicit XdsEndpointHealthStatusAttribute(XdsHealthStatus status)
+ : status_(status) {}
+
+ XdsHealthStatus status() const { return status_; }
+
+ std::unique_ptr Copy() const override {
+ return std::make_unique(status_);
+ }
+
+ int Cmp(const AttributeInterface* other) const override;
+
+ std::string ToString() const override;
+
+ private:
+ XdsHealthStatus status_;
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_CORE_EXT_XDS_XDS_HEALTH_STATUS_H
diff --git a/src/core/lib/json/json_object_loader.cc b/src/core/lib/json/json_object_loader.cc
index 6a5168e45d805..b9d49b76a780e 100644
--- a/src/core/lib/json/json_object_loader.cc
+++ b/src/core/lib/json/json_object_loader.cc
@@ -110,6 +110,16 @@ void LoadUnprocessedJsonObject::LoadInto(const Json& json, const JsonArgs&,
*static_cast(dst) = json.object_value();
}
+void LoadUnprocessedJsonArray::LoadInto(const Json& json, const JsonArgs&,
+ void* dst,
+ ValidationErrors* errors) const {
+ if (json.type() != Json::Type::ARRAY) {
+ errors->AddError("is not an array");
+ return;
+ }
+ *static_cast(dst) = json.array_value();
+}
+
void LoadVector::LoadInto(const Json& json, const JsonArgs& args, void* dst,
ValidationErrors* errors) const {
if (json.type() != Json::Type::ARRAY) {
diff --git a/src/core/lib/json/json_object_loader.h b/src/core/lib/json/json_object_loader.h
index 9ee279cd45716..29f534c7e087c 100644
--- a/src/core/lib/json/json_object_loader.h
+++ b/src/core/lib/json/json_object_loader.h
@@ -214,6 +214,16 @@ class LoadUnprocessedJsonObject : public LoaderInterface {
~LoadUnprocessedJsonObject() = default;
};
+// Loads an unprocessed JSON array value.
+class LoadUnprocessedJsonArray : public LoaderInterface {
+ public:
+ void LoadInto(const Json& json, const JsonArgs& /*args*/, void* dst,
+ ValidationErrors* errors) const override;
+
+ protected:
+ ~LoadUnprocessedJsonArray() = default;
+};
+
// Load a vector of some type.
class LoadVector : public LoaderInterface {
public:
@@ -328,6 +338,11 @@ class AutoLoader final : public LoadUnprocessedJsonObject {
private:
~AutoLoader() = default;
};
+template <>
+class AutoLoader final : public LoadUnprocessedJsonArray {
+ private:
+ ~AutoLoader() = default;
+};
// Specializations of AutoLoader for vectors.
template
diff --git a/src/proto/grpc/testing/xds/v3/BUILD b/src/proto/grpc/testing/xds/v3/BUILD
index 890eb54eff65d..b82a47cccbf12 100644
--- a/src/proto/grpc/testing/xds/v3/BUILD
+++ b/src/proto/grpc/testing/xds/v3/BUILD
@@ -93,6 +93,7 @@ grpc_proto_library(
"config_source_proto",
"endpoint_proto",
"extension_proto",
+ "health_check_proto",
"outlier_detection_proto",
],
)
@@ -106,10 +107,18 @@ grpc_proto_library(
deps = [
"address_proto",
"base_proto",
+ "health_check_proto",
"percent_proto",
],
)
+grpc_proto_library(
+ name = "health_check_proto",
+ srcs = [
+ "health_check.proto",
+ ],
+)
+
grpc_proto_library(
name = "extension_proto",
srcs = [
diff --git a/src/proto/grpc/testing/xds/v3/cluster.proto b/src/proto/grpc/testing/xds/v3/cluster.proto
index dcdcc82a50d54..531fbd7e0b8b9 100644
--- a/src/proto/grpc/testing/xds/v3/cluster.proto
+++ b/src/proto/grpc/testing/xds/v3/cluster.proto
@@ -22,6 +22,7 @@ import "src/proto/grpc/testing/xds/v3/base.proto";
import "src/proto/grpc/testing/xds/v3/config_source.proto";
import "src/proto/grpc/testing/xds/v3/endpoint.proto";
import "src/proto/grpc/testing/xds/v3/extension.proto";
+import "src/proto/grpc/testing/xds/v3/health_check.proto";
import "src/proto/grpc/testing/xds/v3/outlier_detection.proto";
import "google/protobuf/any.proto";
@@ -137,6 +138,10 @@ message Cluster {
string service_name = 2;
}
+ message CommonLbConfig {
+ core.v3.HealthStatusSet override_host_status = 8;
+ }
+
// Supplies the name of the cluster which must be unique across all clusters.
// The cluster name is used when emitting
// :ref:`statistics ` if :ref:`alt_stat_name
@@ -218,6 +223,8 @@ message Cluster {
RingHashLbConfig ring_hash_lb_config = 23;
}
+ CommonLbConfig common_lb_config = 27;
+
// Optional custom transport socket implementation to use for upstream connections.
// To setup TLS, set a transport socket with name `tls` and
// :ref:`UpstreamTlsContexts ` in the `typed_config`.
diff --git a/src/proto/grpc/testing/xds/v3/endpoint.proto b/src/proto/grpc/testing/xds/v3/endpoint.proto
index 7cbea7f443f7b..7886fb3c6afd2 100644
--- a/src/proto/grpc/testing/xds/v3/endpoint.proto
+++ b/src/proto/grpc/testing/xds/v3/endpoint.proto
@@ -20,38 +20,13 @@ package envoy.config.endpoint.v3;
import "src/proto/grpc/testing/xds/v3/address.proto";
import "src/proto/grpc/testing/xds/v3/base.proto";
+import "src/proto/grpc/testing/xds/v3/health_check.proto";
import "src/proto/grpc/testing/xds/v3/percent.proto";
import "google/protobuf/wrappers.proto";
// [#protodoc-title: Endpoints]
-// Endpoint health status.
-enum HealthStatus {
- // The health status is not known. This is interpreted by Envoy as *HEALTHY*.
- UNKNOWN = 0;
-
- // Healthy.
- HEALTHY = 1;
-
- // Unhealthy.
- UNHEALTHY = 2;
-
- // Connection draining in progress. E.g.,
- // ``_
- // or
- // ``_.
- // This is interpreted by Envoy as *UNHEALTHY*.
- DRAINING = 3;
-
- // Health check timed out. This is part of HDS and is interpreted by Envoy as
- // *UNHEALTHY*.
- TIMEOUT = 4;
-
- // Degraded.
- DEGRADED = 5;
-}
-
// Upstream host identifier.
message Endpoint {
// The upstream host address.
@@ -75,7 +50,7 @@ message LbEndpoint {
}
// Optional health status when known and supplied by EDS server.
- HealthStatus health_status = 2;
+ core.v3.HealthStatus health_status = 2;
// The optional load balancing weight of the upstream host; at least 1.
// Envoy uses the load balancing weight in some of the built in load
diff --git a/src/proto/grpc/testing/xds/v3/health_check.proto b/src/proto/grpc/testing/xds/v3/health_check.proto
new file mode 100644
index 0000000000000..14a8f1e31a0b9
--- /dev/null
+++ b/src/proto/grpc/testing/xds/v3/health_check.proto
@@ -0,0 +1,55 @@
+// Copyright 2022 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.config.core.v3;
+
+// [#protodoc-title: Health check]
+// * Health checking :ref:`architecture overview `.
+// * If health checking is configured for a cluster, additional statistics are emitted. They are
+// documented :ref:`here `.
+
+// Endpoint health status.
+enum HealthStatus {
+ // The health status is not known. This is interpreted by Envoy as ``HEALTHY``.
+ UNKNOWN = 0;
+
+ // Healthy.
+ HEALTHY = 1;
+
+ // Unhealthy.
+ UNHEALTHY = 2;
+
+ // Connection draining in progress. E.g.,
+ // ``_
+ // or
+ // ``_.
+ // This is interpreted by Envoy as ``UNHEALTHY``.
+ DRAINING = 3;
+
+ // Health check timed out. This is part of HDS and is interpreted by Envoy as
+ // ``UNHEALTHY``.
+ TIMEOUT = 4;
+
+ // Degraded.
+ DEGRADED = 5;
+}
+
+message HealthStatusSet {
+ // An order-independent set of health status.
+ repeated HealthStatus statuses = 1;
+}
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index c73edf1948830..29291b9d1d058 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -420,6 +420,7 @@
'src/core/ext/xds/xds_cluster_specifier_plugin.cc',
'src/core/ext/xds/xds_common_types.cc',
'src/core/ext/xds/xds_endpoint.cc',
+ 'src/core/ext/xds/xds_health_status.cc',
'src/core/ext/xds/xds_http_fault_filter.cc',
'src/core/ext/xds/xds_http_filters.cc',
'src/core/ext/xds/xds_http_rbac_filter.cc',
diff --git a/test/core/json/json_object_loader_test.cc b/test/core/json/json_object_loader_test.cc
index 1c41e1cb7c666..848e6f3cff092 100644
--- a/test/core/json/json_object_loader_test.cc
+++ b/test/core/json/json_object_loader_test.cc
@@ -569,6 +569,67 @@ TEST(JsonObjectLoader, JsonObjectFields) {
<< test_struct.status();
}
+//
+// Json::Array tests
+//
+
+TEST(JsonObjectLoader, JsonArrayFields) {
+ struct TestStruct {
+ Json::Array value;
+ Json::Array optional_value;
+ absl::optional absl_optional_value;
+ std::unique_ptr unique_ptr_value;
+
+ static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
+ static const auto* loader =
+ JsonObjectLoader()
+ .Field("value", &TestStruct::value)
+ .OptionalField("optional_value", &TestStruct::optional_value)
+ .OptionalField("absl_optional_value",
+ &TestStruct::absl_optional_value)
+ .OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
+ .Finish();
+ return loader;
+ }
+ };
+ // Valid object.
+ auto test_struct = Parse("{\"value\": [1, \"a\"]}");
+ ASSERT_TRUE(test_struct.ok()) << test_struct.status();
+ EXPECT_EQ(Json{test_struct->value}.Dump(), "[1,\"a\"]");
+ EXPECT_EQ(Json{test_struct->optional_value}.Dump(), "[]");
+ EXPECT_FALSE(test_struct->absl_optional_value.has_value());
+ EXPECT_EQ(test_struct->unique_ptr_value, nullptr);
+ // Fails if required field is not present.
+ test_struct = Parse("{}");
+ EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(test_struct.status().message(),
+ "errors validating JSON: [field:value error:field not present]")
+ << test_struct.status();
+ // Optional fields present.
+ test_struct = Parse(
+ "{\"value\": [1, \"a\"], \"optional_value\": [2, \"b\"], "
+ "\"absl_optional_value\": [3, \"c\"], \"unique_ptr_value\": [4, \"d\"]}");
+ ASSERT_TRUE(test_struct.ok()) << test_struct.status();
+ EXPECT_EQ(Json{test_struct->value}.Dump(), "[1,\"a\"]");
+ EXPECT_EQ(Json{test_struct->optional_value}.Dump(), "[2,\"b\"]");
+ ASSERT_TRUE(test_struct->absl_optional_value.has_value());
+ EXPECT_EQ(Json{*test_struct->absl_optional_value}.Dump(), "[3,\"c\"]");
+ ASSERT_NE(test_struct->unique_ptr_value, nullptr);
+ EXPECT_EQ(Json{*test_struct->unique_ptr_value}.Dump(), "[4,\"d\"]");
+ // Wrong JSON type.
+ test_struct = Parse(
+ "{\"value\": {}, \"optional_value\": true, "
+ "\"absl_optional_value\": 1, \"unique_ptr_value\": \"foo\"}");
+ EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(test_struct.status().message(),
+ "errors validating JSON: ["
+ "field:absl_optional_value error:is not an array; "
+ "field:optional_value error:is not an array; "
+ "field:unique_ptr_value error:is not an array; "
+ "field:value error:is not an array]")
+ << test_struct.status();
+}
+
//
// map<> tests
//
diff --git a/test/core/xds/BUILD b/test/core/xds/BUILD
index 8bdc344a9e3ff..573d48dd8340d 100644
--- a/test/core/xds/BUILD
+++ b/test/core/xds/BUILD
@@ -308,5 +308,6 @@ grpc_cc_test(
"//src/core:grpc_xds_client",
"//src/proto/grpc/testing/xds/v3:endpoint_proto",
"//test/core/util:grpc_test_util",
+ "//test/core/util:scoped_env_var",
],
)
diff --git a/test/core/xds/xds_cluster_resource_type_test.cc b/test/core/xds/xds_cluster_resource_type_test.cc
index 28705da651faf..8c7c170b13a40 100644
--- a/test/core/xds/xds_cluster_resource_type_test.cc
+++ b/test/core/xds/xds_cluster_resource_type_test.cc
@@ -1287,6 +1287,64 @@ TEST_F(OutlierDetectionTest, InvalidValues) {
<< decode_result.resource.status();
}
+//
+// host override status tests
+//
+
+using HostOverrideStatusTest = XdsClusterTest;
+
+TEST_F(HostOverrideStatusTest, IgnoredWhenNotEnabled) {
+ Cluster cluster;
+ cluster.set_name("foo");
+ cluster.set_type(cluster.EDS);
+ cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
+ auto* status_set =
+ cluster.mutable_common_lb_config()->mutable_override_host_status();
+ status_set->add_statuses(envoy::config::core::v3::UNKNOWN);
+ status_set->add_statuses(envoy::config::core::v3::HEALTHY);
+ status_set->add_statuses(envoy::config::core::v3::DRAINING);
+ status_set->add_statuses(envoy::config::core::v3::UNHEALTHY);
+ std::string serialized_resource;
+ ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsClusterResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource = static_cast(**decode_result.resource);
+ EXPECT_THAT(resource.host_override_statuses, ::testing::ElementsAre());
+}
+
+TEST_F(HostOverrideStatusTest, PassesOnRelevantHealthStatuses) {
+ ScopedExperimentalEnvVar env_var(
+ "GRPC_EXPERIMENTAL_XDS_ENABLE_HOST_OVERRIDE");
+ Cluster cluster;
+ cluster.set_name("foo");
+ cluster.set_type(cluster.EDS);
+ cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
+ auto* status_set =
+ cluster.mutable_common_lb_config()->mutable_override_host_status();
+ status_set->add_statuses(envoy::config::core::v3::UNKNOWN);
+ status_set->add_statuses(envoy::config::core::v3::HEALTHY);
+ status_set->add_statuses(envoy::config::core::v3::DRAINING);
+ status_set->add_statuses(envoy::config::core::v3::UNHEALTHY);
+ std::string serialized_resource;
+ ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsClusterResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource = static_cast(**decode_result.resource);
+ EXPECT_THAT(resource.host_override_statuses,
+ ::testing::UnorderedElementsAre(
+ XdsHealthStatus(XdsHealthStatus::kUnknown),
+ XdsHealthStatus(XdsHealthStatus::kHealthy),
+ XdsHealthStatus(XdsHealthStatus::kDraining)));
+}
+
} // namespace
} // namespace testing
} // namespace grpc_core
diff --git a/test/core/xds/xds_endpoint_resource_type_test.cc b/test/core/xds/xds_endpoint_resource_type_test.cc
index 8786178f1b9a1..22b4f3146453b 100644
--- a/test/core/xds/xds_endpoint_resource_type_test.cc
+++ b/test/core/xds/xds_endpoint_resource_type_test.cc
@@ -39,6 +39,7 @@
#include "src/core/ext/xds/xds_client.h"
#include "src/core/ext/xds/xds_client_stats.h"
#include "src/core/ext/xds/xds_endpoint.h"
+#include "src/core/ext/xds/xds_health_status.h"
#include "src/core/ext/xds/xds_resource_type.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/channel/channel_args.h"
@@ -50,6 +51,7 @@
#include "src/proto/grpc/testing/xds/v3/base.pb.h"
#include "src/proto/grpc/testing/xds/v3/endpoint.pb.h"
#include "src/proto/grpc/testing/xds/v3/percent.pb.h"
+#include "test/core/util/scoped_env_var.h"
#include "test/core/util/test_config.h"
using envoy::config::endpoint::v3::ClusterLoadAssignment;
@@ -911,6 +913,117 @@ TEST_F(XdsEndpointTest, DropPercentageInvalidDenominator) {
<< decode_result.resource.status();
}
+TEST_F(XdsEndpointTest, IgnoresEndpointsInUnsupportedStates) {
+ ClusterLoadAssignment cla;
+ cla.set_cluster_name("foo");
+ auto* locality = cla.add_endpoints();
+ locality->mutable_load_balancing_weight()->set_value(1);
+ auto* locality_name = locality->mutable_locality();
+ locality_name->set_region("myregion");
+ locality_name->set_zone("myzone");
+ locality_name->set_sub_zone("mysubzone");
+ auto* endpoint = locality->add_lb_endpoints();
+ auto* socket_address =
+ endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
+ socket_address->set_address("127.0.0.1");
+ socket_address->set_port_value(443);
+ endpoint = locality->add_lb_endpoints();
+ endpoint->set_health_status(envoy::config::core::v3::HealthStatus::DRAINING);
+ socket_address =
+ endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
+ socket_address->set_address("127.0.0.1");
+ socket_address->set_port_value(444);
+ std::string serialized_resource;
+ ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsEndpointResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource = static_cast(**decode_result.resource);
+ ASSERT_EQ(resource.priorities.size(), 1);
+ const auto& priority = resource.priorities[0];
+ ASSERT_EQ(priority.localities.size(), 1);
+ const auto& p = *priority.localities.begin();
+ ASSERT_EQ(p.first, p.second.name.get());
+ EXPECT_EQ(p.first->region(), "myregion");
+ EXPECT_EQ(p.first->zone(), "myzone");
+ EXPECT_EQ(p.first->sub_zone(), "mysubzone");
+ EXPECT_EQ(p.second.lb_weight, 1);
+ ASSERT_EQ(p.second.endpoints.size(), 1);
+ const auto& address = p.second.endpoints.front();
+ auto addr = grpc_sockaddr_to_string(&address.address(), /*normalize=*/false);
+ ASSERT_TRUE(addr.ok()) << addr.status();
+ EXPECT_EQ(*addr, "127.0.0.1:443");
+}
+
+TEST_F(XdsEndpointTest, EndpointHealthStatus) {
+ ScopedExperimentalEnvVar env_var(
+ "GRPC_EXPERIMENTAL_XDS_ENABLE_HOST_OVERRIDE");
+ ClusterLoadAssignment cla;
+ cla.set_cluster_name("foo");
+ auto* locality = cla.add_endpoints();
+ locality->mutable_load_balancing_weight()->set_value(1);
+ auto* locality_name = locality->mutable_locality();
+ locality_name->set_region("myregion");
+ locality_name->set_zone("myzone");
+ locality_name->set_sub_zone("mysubzone");
+ auto* endpoint = locality->add_lb_endpoints();
+ auto* socket_address =
+ endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
+ socket_address->set_address("127.0.0.1");
+ socket_address->set_port_value(443);
+ endpoint = locality->add_lb_endpoints();
+ endpoint->set_health_status(envoy::config::core::v3::HealthStatus::DRAINING);
+ socket_address =
+ endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
+ socket_address->set_address("127.0.0.2");
+ socket_address->set_port_value(443);
+ endpoint = locality->add_lb_endpoints();
+ endpoint->set_health_status(envoy::config::core::v3::HealthStatus::UNHEALTHY);
+ socket_address =
+ endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
+ socket_address->set_address("127.0.0.3");
+ socket_address->set_port_value(443);
+ std::string serialized_resource;
+ ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
+ auto* resource_type = XdsEndpointResourceType::Get();
+ auto decode_result =
+ resource_type->Decode(decode_context_, serialized_resource);
+ ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
+ ASSERT_TRUE(decode_result.name.has_value());
+ EXPECT_EQ(*decode_result.name, "foo");
+ auto& resource = static_cast(**decode_result.resource);
+ ASSERT_EQ(resource.priorities.size(), 1);
+ const auto& priority = resource.priorities[0];
+ ASSERT_EQ(priority.localities.size(), 1);
+ const auto& p = *priority.localities.begin();
+ ASSERT_EQ(p.first, p.second.name.get());
+ EXPECT_EQ(p.first->region(), "myregion");
+ EXPECT_EQ(p.first->zone(), "myzone");
+ EXPECT_EQ(p.first->sub_zone(), "mysubzone");
+ EXPECT_EQ(p.second.lb_weight, 1);
+ ASSERT_EQ(p.second.endpoints.size(), 2);
+ const auto* address = &p.second.endpoints[0];
+ auto addr = grpc_sockaddr_to_string(&address->address(), /*normalize=*/false);
+ ASSERT_TRUE(addr.ok()) << addr.status();
+ EXPECT_EQ(*addr, "127.0.0.1:443");
+ const auto* health_attribute =
+ static_cast(
+ address->GetAttribute(XdsEndpointHealthStatusAttribute::kKey));
+ ASSERT_NE(health_attribute, nullptr);
+ EXPECT_EQ(health_attribute->status().status(), XdsHealthStatus::kUnknown);
+ address = &p.second.endpoints[1];
+ addr = grpc_sockaddr_to_string(&address->address(), /*normalize=*/false);
+ ASSERT_TRUE(addr.ok()) << addr.status();
+ EXPECT_EQ(*addr, "127.0.0.2:443");
+ health_attribute = static_cast(
+ address->GetAttribute(XdsEndpointHealthStatusAttribute::kKey));
+ ASSERT_NE(health_attribute, nullptr);
+ EXPECT_EQ(health_attribute->status().status(), XdsHealthStatus::kDraining);
+}
+
} // namespace
} // namespace testing
} // namespace grpc_core
diff --git a/test/cpp/end2end/xds/xds_cluster_end2end_test.cc b/test/cpp/end2end/xds/xds_cluster_end2end_test.cc
index 1776453d95b44..016c8b03840f1 100644
--- a/test/cpp/end2end/xds/xds_cluster_end2end_test.cc
+++ b/test/cpp/end2end/xds/xds_cluster_end2end_test.cc
@@ -34,7 +34,7 @@ namespace {
using ::envoy::config::cluster::v3::CircuitBreakers;
using ::envoy::config::cluster::v3::RoutingPriority;
-using ::envoy::config::endpoint::v3::HealthStatus;
+using ::envoy::config::core::v3::HealthStatus;
using ::envoy::type::v3::FractionalPercent;
using ClientStats = LrsServiceImpl::ClientStats;
diff --git a/test/cpp/end2end/xds/xds_end2end_test_lib.cc b/test/cpp/end2end/xds/xds_end2end_test_lib.cc
index a5a5a70c36bdc..7c70693d54a69 100644
--- a/test/cpp/end2end/xds/xds_end2end_test_lib.cc
+++ b/test/cpp/end2end/xds/xds_end2end_test_lib.cc
@@ -51,8 +51,8 @@
namespace grpc {
namespace testing {
+using ::envoy::config::core::v3::HealthStatus;
using ::envoy::config::endpoint::v3::ClusterLoadAssignment;
-using ::envoy::config::endpoint::v3::HealthStatus;
using ::envoy::config::listener::v3::Listener;
using ::envoy::extensions::filters::network::http_connection_manager::v3::
HttpConnectionManager;
diff --git a/test/cpp/end2end/xds/xds_end2end_test_lib.h b/test/cpp/end2end/xds/xds_end2end_test_lib.h
index 401ceb87f8954..ab0ec3858d92d 100644
--- a/test/cpp/end2end/xds/xds_end2end_test_lib.h
+++ b/test/cpp/end2end/xds/xds_end2end_test_lib.h
@@ -542,15 +542,14 @@ class XdsEnd2endTest : public ::testing::TestWithParam {
struct EdsResourceArgs {
// An individual endpoint for a backend running on a specified port.
struct Endpoint {
- explicit Endpoint(
- int port,
- ::envoy::config::endpoint::v3::HealthStatus health_status =
- ::envoy::config::endpoint::v3::HealthStatus::UNKNOWN,
- int lb_weight = 1)
+ explicit Endpoint(int port,
+ ::envoy::config::core::v3::HealthStatus health_status =
+ ::envoy::config::core::v3::HealthStatus::UNKNOWN,
+ int lb_weight = 1)
: port(port), health_status(health_status), lb_weight(lb_weight) {}
int port;
- ::envoy::config::endpoint::v3::HealthStatus health_status;
+ ::envoy::config::core::v3::HealthStatus health_status;
int lb_weight;
};
@@ -584,8 +583,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam {
// constructing an EDS resource.
EdsResourceArgs::Endpoint CreateEndpoint(
size_t backend_idx,
- ::envoy::config::endpoint::v3::HealthStatus health_status =
- ::envoy::config::endpoint::v3::HealthStatus::UNKNOWN,
+ ::envoy::config::core::v3::HealthStatus health_status =
+ ::envoy::config::core::v3::HealthStatus::UNKNOWN,
int lb_weight = 1) {
return EdsResourceArgs::Endpoint(backends_[backend_idx]->port(),
health_status, lb_weight);
@@ -595,8 +594,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam {
// for use in constructing an EDS resource.
std::vector CreateEndpointsForBackends(
size_t start_index = 0, size_t stop_index = 0,
- ::envoy::config::endpoint::v3::HealthStatus health_status =
- ::envoy::config::endpoint::v3::HealthStatus::UNKNOWN,
+ ::envoy::config::core::v3::HealthStatus health_status =
+ ::envoy::config::core::v3::HealthStatus::UNKNOWN,
int lb_weight = 1);
// Returns an endpoint for an unused port, for use in constructing an
diff --git a/test/cpp/end2end/xds/xds_ring_hash_end2end_test.cc b/test/cpp/end2end/xds/xds_ring_hash_end2end_test.cc
index d5c5a32d0596c..42baff5a8f84e 100644
--- a/test/cpp/end2end/xds/xds_ring_hash_end2end_test.cc
+++ b/test/cpp/end2end/xds/xds_ring_hash_end2end_test.cc
@@ -39,7 +39,7 @@ namespace testing {
namespace {
using ::envoy::config::cluster::v3::CustomClusterType;
-using ::envoy::config::endpoint::v3::HealthStatus;
+using ::envoy::config::core::v3::HealthStatus;
using ::envoy::extensions::clusters::aggregate::v3::ClusterConfig;
class RingHashTest : public XdsEnd2endTest {
@@ -504,11 +504,9 @@ TEST_P(RingHashTest, EndpointWeights) {
// Endpoint 2 has weight 2.
EdsResourceArgs args(
{{"locality0",
- {CreateEndpoint(0, ::envoy::config::endpoint::v3::HealthStatus::UNKNOWN,
- 0),
- CreateEndpoint(1, ::envoy::config::endpoint::v3::HealthStatus::UNKNOWN,
- 1),
- CreateEndpoint(2, ::envoy::config::endpoint::v3::HealthStatus::UNKNOWN,
+ {CreateEndpoint(0, ::envoy::config::core::v3::HealthStatus::UNKNOWN, 0),
+ CreateEndpoint(1, ::envoy::config::core::v3::HealthStatus::UNKNOWN, 1),
+ CreateEndpoint(2, ::envoy::config::core::v3::HealthStatus::UNKNOWN,
2)}}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
// TODO(donnadionne): remove extended timeout after ring creation
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 050b619e8cc30..182ffb8e4dfc8 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1902,6 +1902,8 @@ src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_common_types.h \
src/core/ext/xds/xds_endpoint.cc \
src/core/ext/xds/xds_endpoint.h \
+src/core/ext/xds/xds_health_status.cc \
+src/core/ext/xds/xds_health_status.h \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_fault_filter.h \
src/core/ext/xds/xds_http_filters.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index a0fbcc8abdfc5..52280ed23db80 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1675,6 +1675,8 @@ src/core/ext/xds/xds_common_types.cc \
src/core/ext/xds/xds_common_types.h \
src/core/ext/xds/xds_endpoint.cc \
src/core/ext/xds/xds_endpoint.h \
+src/core/ext/xds/xds_health_status.cc \
+src/core/ext/xds/xds_health_status.h \
src/core/ext/xds/xds_http_fault_filter.cc \
src/core/ext/xds/xds_http_fault_filter.h \
src/core/ext/xds/xds_http_filters.cc \