xDS Listener: use ValidationErrors and add unit test (#31351)
Additional changes: - Use absl::variant<> to differentiate between API listeners and TCP listeners. - Use absl::variant<> to differentiate between an RDS reference and an inline RouteConfig. - Use common xDS extension code for transport socket extensions in both Listener and Cluster resources. - Improve xDS HTTP filter registration mechanism. - Use ValidationErrors for HTTP filter config validation.
This commit is contained in:
parent
c7a2fc8e75
commit
7229bea2fd
|
|
@ -1272,9 +1272,11 @@ if(gRPC_BUILD_TESTS)
|
|||
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
|
||||
add_dependencies(buildtests_cxx xds_fault_injection_end2end_test)
|
||||
endif()
|
||||
add_dependencies(buildtests_cxx xds_http_filters_test)
|
||||
add_dependencies(buildtests_cxx xds_interop_client)
|
||||
add_dependencies(buildtests_cxx xds_interop_server)
|
||||
add_dependencies(buildtests_cxx xds_lb_policy_registry_test)
|
||||
add_dependencies(buildtests_cxx xds_listener_resource_type_test)
|
||||
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
|
||||
add_dependencies(buildtests_cxx xds_outlier_detection_end2end_test)
|
||||
endif()
|
||||
|
|
@ -20586,6 +20588,10 @@ add_executable(xds_cluster_resource_type_test
|
|||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.grpc.pb.h
|
||||
test/core/xds/xds_cluster_resource_type_test.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
|
|
@ -21692,6 +21698,116 @@ endif()
|
|||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(xds_http_filters_test
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.cc
|
||||
${_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/fault.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.cc
|
||||
${_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/http_filter_rbac.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.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
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.h
|
||||
test/core/xds/xds_http_filters_test.cc
|
||||
test/cpp/util/cli_call.cc
|
||||
test/cpp/util/cli_credentials.cc
|
||||
test/cpp/util/proto_file_parser.cc
|
||||
test/cpp/util/proto_reflection_descriptor_database.cc
|
||||
test/cpp/util/service_describer.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
||||
target_include_directories(xds_http_filters_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
|
||||
${_gRPC_RE2_INCLUDE_DIR}
|
||||
${_gRPC_SSL_INCLUDE_DIR}
|
||||
${_gRPC_UPB_GENERATED_DIR}
|
||||
${_gRPC_UPB_GRPC_GENERATED_DIR}
|
||||
${_gRPC_UPB_INCLUDE_DIR}
|
||||
${_gRPC_XXHASH_INCLUDE_DIR}
|
||||
${_gRPC_ZLIB_INCLUDE_DIR}
|
||||
third_party/googletest/googletest/include
|
||||
third_party/googletest/googletest
|
||||
third_party/googletest/googlemock/include
|
||||
third_party/googletest/googlemock
|
||||
${_gRPC_PROTO_GENS_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(xds_http_filters_test
|
||||
${_gRPC_PROTOBUF_LIBRARIES}
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
absl::flags
|
||||
grpc++
|
||||
grpc_test_util
|
||||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(xds_interop_client
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
|
||||
|
|
@ -21930,6 +22046,140 @@ target_link_libraries(xds_lb_policy_registry_test
|
|||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(xds_listener_resource_type_test
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.cc
|
||||
${_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/fault.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.cc
|
||||
${_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/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
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.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
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/typed_struct.grpc.pb.h
|
||||
test/core/xds/xds_listener_resource_type_test.cc
|
||||
test/cpp/util/cli_call.cc
|
||||
test/cpp/util/cli_credentials.cc
|
||||
test/cpp/util/proto_file_parser.cc
|
||||
test/cpp/util/proto_reflection_descriptor_database.cc
|
||||
test/cpp/util/service_describer.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
||||
target_include_directories(xds_listener_resource_type_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
|
||||
${_gRPC_RE2_INCLUDE_DIR}
|
||||
${_gRPC_SSL_INCLUDE_DIR}
|
||||
${_gRPC_UPB_GENERATED_DIR}
|
||||
${_gRPC_UPB_GRPC_GENERATED_DIR}
|
||||
${_gRPC_UPB_INCLUDE_DIR}
|
||||
${_gRPC_XXHASH_INCLUDE_DIR}
|
||||
${_gRPC_ZLIB_INCLUDE_DIR}
|
||||
third_party/googletest/googletest/include
|
||||
third_party/googletest/googletest
|
||||
third_party/googletest/googlemock/include
|
||||
third_party/googletest/googlemock
|
||||
${_gRPC_PROTO_GENS_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(xds_listener_resource_type_test
|
||||
${_gRPC_PROTOBUF_LIBRARIES}
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
absl::flags
|
||||
grpc++
|
||||
grpc_test_util
|
||||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
|
||||
|
|
@ -22492,14 +22742,6 @@ 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/fault.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.cc
|
||||
${_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/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
|
||||
|
|
|
|||
|
|
@ -11244,6 +11244,7 @@ targets:
|
|||
- src/proto/grpc/testing/xds/v3/regex.proto
|
||||
- src/proto/grpc/testing/xds/v3/string.proto
|
||||
- src/proto/grpc/testing/xds/v3/tls.proto
|
||||
- src/proto/grpc/testing/xds/v3/typed_struct.proto
|
||||
- test/core/xds/xds_cluster_resource_type_test.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
|
|
@ -11503,7 +11504,6 @@ targets:
|
|||
headers:
|
||||
- test/cpp/end2end/counted_service.h
|
||||
- test/cpp/end2end/test_service_impl.h
|
||||
- test/cpp/end2end/xds/no_op_http_filter.h
|
||||
- test/cpp/end2end/xds/xds_end2end_test_lib.h
|
||||
- test/cpp/end2end/xds/xds_server.h
|
||||
- test/cpp/util/tls_test_utils.h
|
||||
|
|
@ -11623,6 +11623,46 @@ targets:
|
|||
- linux
|
||||
- posix
|
||||
- mac
|
||||
- name: xds_http_filters_test
|
||||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers:
|
||||
- test/cpp/util/cli_call.h
|
||||
- test/cpp/util/cli_credentials.h
|
||||
- test/cpp/util/config_grpc_cli.h
|
||||
- test/cpp/util/proto_file_parser.h
|
||||
- test/cpp/util/proto_reflection_descriptor_database.h
|
||||
- test/cpp/util/service_describer.h
|
||||
src:
|
||||
- src/proto/grpc/reflection/v1alpha/reflection.proto
|
||||
- src/proto/grpc/testing/xds/v3/address.proto
|
||||
- src/proto/grpc/testing/xds/v3/base.proto
|
||||
- src/proto/grpc/testing/xds/v3/expr.proto
|
||||
- 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/http_filter_rbac.proto
|
||||
- src/proto/grpc/testing/xds/v3/metadata.proto
|
||||
- src/proto/grpc/testing/xds/v3/path.proto
|
||||
- src/proto/grpc/testing/xds/v3/percent.proto
|
||||
- src/proto/grpc/testing/xds/v3/range.proto
|
||||
- src/proto/grpc/testing/xds/v3/rbac.proto
|
||||
- src/proto/grpc/testing/xds/v3/regex.proto
|
||||
- src/proto/grpc/testing/xds/v3/route.proto
|
||||
- src/proto/grpc/testing/xds/v3/router.proto
|
||||
- src/proto/grpc/testing/xds/v3/string.proto
|
||||
- test/core/xds/xds_http_filters_test.cc
|
||||
- test/cpp/util/cli_call.cc
|
||||
- test/cpp/util/cli_credentials.cc
|
||||
- test/cpp/util/proto_file_parser.cc
|
||||
- test/cpp/util/proto_reflection_descriptor_database.cc
|
||||
- test/cpp/util/service_describer.cc
|
||||
deps:
|
||||
- absl/flags:flag
|
||||
- grpc++
|
||||
- grpc_test_util
|
||||
uses_polling: false
|
||||
- name: xds_interop_client
|
||||
build: test
|
||||
run: false
|
||||
|
|
@ -11709,6 +11749,52 @@ targets:
|
|||
- grpc++
|
||||
- grpc_test_util
|
||||
uses_polling: false
|
||||
- name: xds_listener_resource_type_test
|
||||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers:
|
||||
- test/cpp/util/cli_call.h
|
||||
- test/cpp/util/cli_credentials.h
|
||||
- test/cpp/util/config_grpc_cli.h
|
||||
- test/cpp/util/proto_file_parser.h
|
||||
- test/cpp/util/proto_reflection_descriptor_database.h
|
||||
- test/cpp/util/service_describer.h
|
||||
src:
|
||||
- src/proto/grpc/reflection/v1alpha/reflection.proto
|
||||
- src/proto/grpc/testing/xds/v3/address.proto
|
||||
- src/proto/grpc/testing/xds/v3/base.proto
|
||||
- src/proto/grpc/testing/xds/v3/config_source.proto
|
||||
- src/proto/grpc/testing/xds/v3/expr.proto
|
||||
- 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/http_connection_manager.proto
|
||||
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
|
||||
- src/proto/grpc/testing/xds/v3/listener.proto
|
||||
- src/proto/grpc/testing/xds/v3/metadata.proto
|
||||
- src/proto/grpc/testing/xds/v3/path.proto
|
||||
- src/proto/grpc/testing/xds/v3/percent.proto
|
||||
- src/proto/grpc/testing/xds/v3/protocol.proto
|
||||
- src/proto/grpc/testing/xds/v3/range.proto
|
||||
- src/proto/grpc/testing/xds/v3/rbac.proto
|
||||
- src/proto/grpc/testing/xds/v3/regex.proto
|
||||
- src/proto/grpc/testing/xds/v3/route.proto
|
||||
- src/proto/grpc/testing/xds/v3/router.proto
|
||||
- src/proto/grpc/testing/xds/v3/string.proto
|
||||
- src/proto/grpc/testing/xds/v3/tls.proto
|
||||
- src/proto/grpc/testing/xds/v3/typed_struct.proto
|
||||
- test/core/xds/xds_listener_resource_type_test.cc
|
||||
- test/cpp/util/cli_call.cc
|
||||
- test/cpp/util/cli_credentials.cc
|
||||
- test/cpp/util/proto_file_parser.cc
|
||||
- test/cpp/util/proto_reflection_descriptor_database.cc
|
||||
- test/cpp/util/service_describer.cc
|
||||
deps:
|
||||
- absl/flags:flag
|
||||
- grpc++
|
||||
- grpc_test_util
|
||||
uses_polling: false
|
||||
- name: xds_outlier_detection_end2end_test
|
||||
gtest: true
|
||||
build: test
|
||||
|
|
@ -11717,7 +11803,6 @@ targets:
|
|||
headers:
|
||||
- test/cpp/end2end/counted_service.h
|
||||
- test/cpp/end2end/test_service_impl.h
|
||||
- test/cpp/end2end/xds/no_op_http_filter.h
|
||||
- test/cpp/end2end/xds/xds_end2end_test_lib.h
|
||||
- test/cpp/end2end/xds/xds_server.h
|
||||
- test/cpp/util/tls_test_utils.h
|
||||
|
|
@ -11886,7 +11971,6 @@ targets:
|
|||
headers:
|
||||
- test/cpp/end2end/counted_service.h
|
||||
- test/cpp/end2end/test_service_impl.h
|
||||
- test/cpp/end2end/xds/no_op_http_filter.h
|
||||
- test/cpp/end2end/xds/xds_end2end_test_lib.h
|
||||
- test/cpp/end2end/xds/xds_server.h
|
||||
- test/cpp/util/tls_test_utils.h
|
||||
|
|
@ -11904,8 +11988,6 @@ 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/fault.proto
|
||||
- src/proto/grpc/testing/xds/v3/fault_common.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
|
||||
|
|
|
|||
|
|
@ -3507,6 +3507,7 @@ grpc_cc_library(
|
|||
"grpc_xds_channel_stack_modifier",
|
||||
"grpc_xds_client",
|
||||
"iomgr_fwd",
|
||||
"match",
|
||||
"resolved_address",
|
||||
"slice_refcount",
|
||||
"status_helper",
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ class XdsResolver : public Resolver {
|
|||
// This will not contain the RouteConfiguration, even if it comes with the
|
||||
// LDS response; instead, the relevant VirtualHost from the
|
||||
// RouteConfiguration will be saved in current_virtual_host_.
|
||||
XdsListenerResource current_listener_;
|
||||
XdsListenerResource::HttpConnectionManager current_listener_;
|
||||
|
||||
std::string route_config_name_;
|
||||
RouteConfigWatcher* route_config_watcher_ = nullptr;
|
||||
|
|
@ -468,8 +468,7 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector(
|
|||
// one.
|
||||
if (!route_action->max_stream_duration.has_value()) {
|
||||
route_action->max_stream_duration =
|
||||
resolver_->current_listener_.http_connection_manager
|
||||
.http_max_stream_duration;
|
||||
resolver_->current_listener_.http_max_stream_duration;
|
||||
}
|
||||
Match(
|
||||
route_action->action,
|
||||
|
|
@ -524,8 +523,7 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector(
|
|||
}
|
||||
}
|
||||
// Populate filter list.
|
||||
for (const auto& http_filter :
|
||||
resolver_->current_listener_.http_connection_manager.http_filters) {
|
||||
for (const auto& http_filter : resolver_->current_listener_.http_filters) {
|
||||
// Find filter. This is guaranteed to succeed, because it's checked
|
||||
// at config validation time in the XdsApi code.
|
||||
const XdsHttpFilterImpl* filter_impl =
|
||||
|
|
@ -602,7 +600,7 @@ XdsResolver::XdsConfigSelector::CreateMethodConfig(
|
|||
}
|
||||
// Handle xDS HTTP filters.
|
||||
auto result = XdsRouting::GeneratePerHTTPFilterConfigs(
|
||||
resolver_->current_listener_.http_connection_manager.http_filters,
|
||||
resolver_->current_listener_.http_filters,
|
||||
resolver_->current_virtual_host_, route, cluster_weight,
|
||||
resolver_->args_);
|
||||
if (!result.ok()) return result.status();
|
||||
|
|
@ -889,39 +887,35 @@ void XdsResolver::OnListenerUpdate(XdsListenerResource listener) {
|
|||
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
|
||||
gpr_log(GPR_INFO, "[xds_resolver %p] received updated listener data", this);
|
||||
}
|
||||
if (xds_client_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (listener.http_connection_manager.route_config_name !=
|
||||
route_config_name_) {
|
||||
if (route_config_watcher_ != nullptr) {
|
||||
XdsRouteConfigResourceType::CancelWatch(
|
||||
xds_client_.get(), route_config_name_, route_config_watcher_,
|
||||
/*delay_unsubscription=*/
|
||||
!listener.http_connection_manager.route_config_name.empty());
|
||||
route_config_watcher_ = nullptr;
|
||||
}
|
||||
route_config_name_ =
|
||||
std::move(listener.http_connection_manager.route_config_name);
|
||||
if (!route_config_name_.empty()) {
|
||||
current_virtual_host_.routes.clear();
|
||||
auto watcher = MakeRefCounted<RouteConfigWatcher>(Ref());
|
||||
route_config_watcher_ = watcher.get();
|
||||
XdsRouteConfigResourceType::StartWatch(
|
||||
xds_client_.get(), route_config_name_, std::move(watcher));
|
||||
}
|
||||
}
|
||||
current_listener_ = std::move(listener);
|
||||
if (route_config_name_.empty()) {
|
||||
GPR_ASSERT(
|
||||
current_listener_.http_connection_manager.rds_update.has_value());
|
||||
OnRouteConfigUpdate(
|
||||
std::move(*current_listener_.http_connection_manager.rds_update));
|
||||
} else {
|
||||
// HCM may contain newer filter config. We need to propagate the update as
|
||||
// config selector to the channel
|
||||
GenerateResult();
|
||||
}
|
||||
if (xds_client_ == nullptr) return;
|
||||
current_listener_ = std::move(
|
||||
absl::get<XdsListenerResource::HttpConnectionManager>(listener.listener));
|
||||
MatchMutable(
|
||||
¤t_listener_.route_config,
|
||||
// RDS resource name
|
||||
[&](std::string* rds_name) {
|
||||
if (route_config_watcher_ != nullptr) {
|
||||
XdsRouteConfigResourceType::CancelWatch(
|
||||
xds_client_.get(), route_config_name_, route_config_watcher_,
|
||||
/*delay_unsubscription=*/!rds_name->empty());
|
||||
route_config_watcher_ = nullptr;
|
||||
}
|
||||
route_config_name_ = std::move(*rds_name);
|
||||
if (!route_config_name_.empty()) {
|
||||
current_virtual_host_.routes.clear();
|
||||
auto watcher = MakeRefCounted<RouteConfigWatcher>(Ref());
|
||||
route_config_watcher_ = watcher.get();
|
||||
XdsRouteConfigResourceType::StartWatch(
|
||||
xds_client_.get(), route_config_name_, std::move(watcher));
|
||||
}
|
||||
// HCM may contain newer filter config. We need to propagate the
|
||||
// update as config selector to the channel.
|
||||
GenerateResult();
|
||||
},
|
||||
// inlined RouteConfig
|
||||
[&](XdsRouteConfigResource* route_config) {
|
||||
OnRouteConfigUpdate(std::move(*route_config));
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@
|
|||
#include "src/core/lib/promise/arena_promise.h"
|
||||
#include "src/core/lib/transport/transport.h"
|
||||
|
||||
// Channel arg key for enabling parsing fault injection via method config.
|
||||
#define GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG \
|
||||
"grpc.parse_fault_injection_method_config"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
// This channel filter is intended to be used by the dynamic filters, instead
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/channel/status_util.h"
|
||||
#include "src/core/lib/gprpp/status_helper.h"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@
|
|||
#include "src/core/lib/json/json.h"
|
||||
#include "src/core/lib/service_config/service_config_parser.h"
|
||||
|
||||
// Channel arg key for enabling parsing fault injection via method config.
|
||||
#define GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG \
|
||||
"grpc.internal.parse_fault_injection_method_config"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
class FaultInjectionMethodParsedConfig
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "absl/types/variant.h"
|
||||
#include "envoy/config/cluster/v3/circuit_breaker.upb.h"
|
||||
#include "envoy/config/cluster/v3/cluster.upb.h"
|
||||
#include "envoy/config/cluster/v3/cluster.upbdefs.h"
|
||||
|
|
@ -53,6 +54,7 @@
|
|||
#include "src/core/lib/gprpp/host_port.h"
|
||||
#include "src/core/lib/gprpp/time.h"
|
||||
#include "src/core/lib/gprpp/validation_errors.h"
|
||||
#include "src/core/lib/matchers/matchers.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
|
|
@ -100,39 +102,34 @@ std::string XdsClusterResource::ToString() const {
|
|||
|
||||
namespace {
|
||||
|
||||
absl::optional<CommonTlsContext> UpstreamTlsContextParse(
|
||||
CommonTlsContext UpstreamTlsContextParse(
|
||||
const XdsResourceType::DecodeContext& context,
|
||||
const envoy_config_core_v3_TransportSocket* transport_socket,
|
||||
ValidationErrors* errors) {
|
||||
ValidationErrors::ScopedField field(errors, ".typed_config");
|
||||
const auto* typed_config =
|
||||
envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
|
||||
if (typed_config == nullptr) {
|
||||
errors->AddError("field not present");
|
||||
return absl::nullopt;
|
||||
}
|
||||
absl::string_view type_url = absl::StripPrefix(
|
||||
UpbStringToAbsl(google_protobuf_Any_type_url(typed_config)),
|
||||
"type.googleapis.com/");
|
||||
if (type_url !=
|
||||
auto extension = ExtractXdsExtension(context, typed_config, errors);
|
||||
if (!extension.has_value()) return {};
|
||||
if (extension->type !=
|
||||
"envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext") {
|
||||
ValidationErrors::ScopedField field(errors, ".type_url");
|
||||
errors->AddError(
|
||||
absl::StrCat("unrecognized transport socket type: ", type_url));
|
||||
return absl::nullopt;
|
||||
errors->AddError("unsupported transport socket type");
|
||||
return {};
|
||||
}
|
||||
absl::string_view* serialized_upstream_tls_context =
|
||||
absl::get_if<absl::string_view>(&extension->value);
|
||||
if (serialized_upstream_tls_context == nullptr) {
|
||||
errors->AddError("can't decode UpstreamTlsContext");
|
||||
return {};
|
||||
}
|
||||
ValidationErrors::ScopedField field2(
|
||||
errors,
|
||||
".value[envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext]");
|
||||
absl::string_view serialized_upstream_tls_context =
|
||||
UpbStringToAbsl(google_protobuf_Any_value(typed_config));
|
||||
const auto* upstream_tls_context =
|
||||
envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
|
||||
serialized_upstream_tls_context.data(),
|
||||
serialized_upstream_tls_context.size(), context.arena);
|
||||
serialized_upstream_tls_context->data(),
|
||||
serialized_upstream_tls_context->size(), context.arena);
|
||||
if (upstream_tls_context == nullptr) {
|
||||
errors->AddError("can't decode UpstreamTlsContext");
|
||||
return absl::nullopt;
|
||||
return {};
|
||||
}
|
||||
ValidationErrors::ScopedField field3(errors, ".common_tls_context");
|
||||
const auto* common_tls_context_proto =
|
||||
|
|
@ -394,11 +391,8 @@ absl::StatusOr<XdsClusterResource> CdsResourceParse(
|
|||
envoy_config_cluster_v3_Cluster_transport_socket(cluster);
|
||||
if (transport_socket != nullptr) {
|
||||
ValidationErrors::ScopedField field(&errors, ".transport_socket");
|
||||
auto common_tls_context =
|
||||
cds_update.common_tls_context =
|
||||
UpstreamTlsContextParse(context, transport_socket, &errors);
|
||||
if (common_tls_context.has_value()) {
|
||||
cds_update.common_tls_context = std::move(*common_tls_context);
|
||||
}
|
||||
}
|
||||
// Record LRS server name (if any).
|
||||
const envoy_config_core_v3_ConfigSource* lrs_server =
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
|
@ -39,6 +38,7 @@
|
|||
#include <grpc/status.h>
|
||||
|
||||
#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
|
||||
#include "src/core/ext/filters/fault_injection/service_config_parser.h"
|
||||
#include "src/core/ext/xds/xds_common_types.h"
|
||||
#include "src/core/ext/xds/xds_http_filters.h"
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
|
|
@ -50,9 +50,6 @@
|
|||
|
||||
namespace grpc_core {
|
||||
|
||||
const char* kXdsHttpFaultFilterConfigName =
|
||||
"envoy.extensions.filters.http.fault.v3.HTTPFault";
|
||||
|
||||
namespace {
|
||||
|
||||
uint32_t GetDenominator(const envoy_type_v3_FractionalPercent* fraction) {
|
||||
|
|
@ -74,13 +71,36 @@ uint32_t GetDenominator(const envoy_type_v3_FractionalPercent* fraction) {
|
|||
return 100;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParseHttpFaultIntoJson(
|
||||
absl::string_view serialized_http_fault, upb_Arena* arena) {
|
||||
} // namespace
|
||||
|
||||
absl::string_view XdsHttpFaultFilter::ConfigProtoName() const {
|
||||
return "envoy.extensions.filters.http.fault.v3.HTTPFault";
|
||||
}
|
||||
|
||||
absl::string_view XdsHttpFaultFilter::OverrideConfigProtoName() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
void XdsHttpFaultFilter::PopulateSymtab(upb_DefPool* symtab) const {
|
||||
envoy_extensions_filters_http_fault_v3_HTTPFault_getmsgdef(symtab);
|
||||
}
|
||||
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpFaultFilter::GenerateFilterConfig(XdsExtension extension,
|
||||
upb_Arena* arena,
|
||||
ValidationErrors* errors) const {
|
||||
absl::string_view* serialized_filter_config =
|
||||
absl::get_if<absl::string_view>(&extension.value);
|
||||
if (serialized_filter_config == nullptr) {
|
||||
errors->AddError("could not parse fault injection filter config");
|
||||
return absl::nullopt;
|
||||
}
|
||||
auto* http_fault = envoy_extensions_filters_http_fault_v3_HTTPFault_parse(
|
||||
serialized_http_fault.data(), serialized_http_fault.size(), arena);
|
||||
serialized_filter_config->data(), serialized_filter_config->size(),
|
||||
arena);
|
||||
if (http_fault == nullptr) {
|
||||
return absl::InvalidArgumentError(
|
||||
"could not parse fault injection filter config");
|
||||
errors->AddError("could not parse fault injection filter config");
|
||||
return absl::nullopt;
|
||||
}
|
||||
// NOTE(lidiz): Here, we are manually translating the upb messages into the
|
||||
// JSON form of the filter config as part of method config, which will be
|
||||
|
|
@ -95,6 +115,7 @@ absl::StatusOr<Json> ParseHttpFaultIntoJson(
|
|||
const auto* fault_abort =
|
||||
envoy_extensions_filters_http_fault_v3_HTTPFault_abort(http_fault);
|
||||
if (fault_abort != nullptr) {
|
||||
ValidationErrors::ScopedField field(errors, ".abort");
|
||||
grpc_status_code abort_grpc_status_code = GRPC_STATUS_OK;
|
||||
// Try if gRPC status code is set first
|
||||
int abort_grpc_status_code_raw =
|
||||
|
|
@ -103,8 +124,9 @@ absl::StatusOr<Json> ParseHttpFaultIntoJson(
|
|||
if (abort_grpc_status_code_raw != 0) {
|
||||
if (!grpc_status_code_from_int(abort_grpc_status_code_raw,
|
||||
&abort_grpc_status_code)) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"invalid gRPC status code: ", abort_grpc_status_code_raw));
|
||||
ValidationErrors::ScopedField field(errors, ".grpc_status");
|
||||
errors->AddError(absl::StrCat("invalid gRPC status code: ",
|
||||
abort_grpc_status_code_raw));
|
||||
}
|
||||
} else {
|
||||
// if gRPC status code is empty, check http status
|
||||
|
|
@ -131,23 +153,25 @@ absl::StatusOr<Json> ParseHttpFaultIntoJson(
|
|||
auto* percent =
|
||||
envoy_extensions_filters_http_fault_v3_FaultAbort_percentage(
|
||||
fault_abort);
|
||||
fault_injection_policy_json["abortPercentageNumerator"] =
|
||||
Json(envoy_type_v3_FractionalPercent_numerator(percent));
|
||||
fault_injection_policy_json["abortPercentageDenominator"] =
|
||||
Json(GetDenominator(percent));
|
||||
if (percent != nullptr) {
|
||||
fault_injection_policy_json["abortPercentageNumerator"] =
|
||||
envoy_type_v3_FractionalPercent_numerator(percent);
|
||||
fault_injection_policy_json["abortPercentageDenominator"] =
|
||||
GetDenominator(percent);
|
||||
}
|
||||
}
|
||||
// Section 2: Parse the delay injection config
|
||||
const auto* fault_delay =
|
||||
envoy_extensions_filters_http_fault_v3_HTTPFault_delay(http_fault);
|
||||
if (fault_delay != nullptr) {
|
||||
ValidationErrors::ScopedField field(errors, ".delay");
|
||||
// Parse the delay duration
|
||||
const auto* delay_duration =
|
||||
envoy_extensions_filters_common_fault_v3_FaultDelay_fixed_delay(
|
||||
fault_delay);
|
||||
if (delay_duration != nullptr) {
|
||||
ValidationErrors errors;
|
||||
Duration duration = ParseDuration(delay_duration, &errors);
|
||||
if (!errors.ok()) return errors.status("fixed_delay");
|
||||
ValidationErrors::ScopedField field(errors, ".fixed_delay");
|
||||
Duration duration = ParseDuration(delay_duration, errors);
|
||||
fault_injection_policy_json["delay"] = duration.ToJsonString();
|
||||
}
|
||||
// Set the headers if we enabled header delay injection control
|
||||
|
|
@ -162,10 +186,12 @@ absl::StatusOr<Json> ParseHttpFaultIntoJson(
|
|||
auto* percent =
|
||||
envoy_extensions_filters_common_fault_v3_FaultDelay_percentage(
|
||||
fault_delay);
|
||||
fault_injection_policy_json["delayPercentageNumerator"] =
|
||||
Json(envoy_type_v3_FractionalPercent_numerator(percent));
|
||||
fault_injection_policy_json["delayPercentageDenominator"] =
|
||||
Json(GetDenominator(percent));
|
||||
if (percent != nullptr) {
|
||||
fault_injection_policy_json["delayPercentageNumerator"] =
|
||||
envoy_type_v3_FractionalPercent_numerator(percent);
|
||||
fault_injection_policy_json["delayPercentageDenominator"] =
|
||||
GetDenominator(percent);
|
||||
}
|
||||
}
|
||||
// Section 3: Parse the maximum active faults
|
||||
const auto* max_fault_wrapper =
|
||||
|
|
@ -175,38 +201,16 @@ absl::StatusOr<Json> ParseHttpFaultIntoJson(
|
|||
fault_injection_policy_json["maxFaults"] =
|
||||
google_protobuf_UInt32Value_value(max_fault_wrapper);
|
||||
}
|
||||
return fault_injection_policy_json;
|
||||
return FilterConfig{ConfigProtoName(),
|
||||
std::move(fault_injection_policy_json)};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void XdsHttpFaultFilter::PopulateSymtab(upb_DefPool* symtab) const {
|
||||
envoy_extensions_filters_http_fault_v3_HTTPFault_getmsgdef(symtab);
|
||||
}
|
||||
|
||||
absl::StatusOr<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpFaultFilter::GenerateFilterConfig(XdsExtension extension,
|
||||
upb_Arena* arena) const {
|
||||
absl::string_view* serialized_filter_config =
|
||||
absl::get_if<absl::string_view>(&extension.value);
|
||||
if (serialized_filter_config == nullptr) {
|
||||
return absl::InvalidArgumentError(
|
||||
"could not parse fault injection filter config");
|
||||
}
|
||||
absl::StatusOr<Json> parse_result =
|
||||
ParseHttpFaultIntoJson(*serialized_filter_config, arena);
|
||||
if (!parse_result.ok()) {
|
||||
return parse_result.status();
|
||||
}
|
||||
return FilterConfig{kXdsHttpFaultFilterConfigName, std::move(*parse_result)};
|
||||
}
|
||||
|
||||
absl::StatusOr<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpFaultFilter::GenerateFilterConfigOverride(XdsExtension extension,
|
||||
upb_Arena* arena) const {
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpFaultFilter::GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena, ValidationErrors* errors) const {
|
||||
// HTTPFault filter has the same message type in HTTP connection manager's
|
||||
// filter config and in overriding filter config field.
|
||||
return GenerateFilterConfig(std::move(extension), arena);
|
||||
return GenerateFilterConfig(std::move(extension), arena, errors);
|
||||
}
|
||||
|
||||
const grpc_channel_filter* XdsHttpFaultFilter::channel_filter() const {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "upb/arena.h"
|
||||
#include "upb/def.h"
|
||||
|
||||
|
|
@ -27,40 +29,30 @@
|
|||
#include "src/core/ext/xds/xds_http_filters.h"
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/channel/channel_fwd.h"
|
||||
#include "src/core/lib/gprpp/validation_errors.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
extern const char* kXdsHttpFaultFilterConfigName;
|
||||
|
||||
class XdsHttpFaultFilter : public XdsHttpFilterImpl {
|
||||
public:
|
||||
// Overrides the PopulateSymtab method
|
||||
absl::string_view ConfigProtoName() const override;
|
||||
absl::string_view OverrideConfigProtoName() const override;
|
||||
void PopulateSymtab(upb_DefPool* symtab) const override;
|
||||
|
||||
// Overrides the GenerateFilterConfig method
|
||||
absl::StatusOr<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena) const override;
|
||||
|
||||
// Overrides the GenerateFilterConfigOverride method
|
||||
absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena) const override;
|
||||
|
||||
// Overrides the channel_filter method
|
||||
absl::optional<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const override;
|
||||
absl::optional<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const override;
|
||||
const grpc_channel_filter* channel_filter() const override;
|
||||
|
||||
// Overrides the ModifyChannelArgs method
|
||||
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
|
||||
|
||||
// Overrides the GenerateServiceConfig method
|
||||
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
|
||||
const FilterConfig& hcm_filter_config,
|
||||
const FilterConfig* filter_config_override) const override;
|
||||
|
||||
bool IsSupportedOnClients() const override { return true; }
|
||||
|
||||
bool IsSupportedOnServers() const override { return false; }
|
||||
};
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_XDS_XDS_HTTP_FAULT_FILTER_H */
|
||||
#endif // GRPC_CORE_EXT_XDS_XDS_HTTP_FAULT_FILTER_H
|
||||
|
|
|
|||
|
|
@ -23,64 +23,66 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/types/variant.h"
|
||||
#include "envoy/extensions/filters/http/router/v3/router.upb.h"
|
||||
#include "envoy/extensions/filters/http/router/v3/router.upbdefs.h"
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
|
||||
#include "src/core/ext/xds/xds_http_fault_filter.h"
|
||||
#include "src/core/ext/xds/xds_http_rbac_filter.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
const char* kXdsHttpRouterFilterConfigName =
|
||||
"envoy.extensions.filters.http.router.v3.Router";
|
||||
//
|
||||
// XdsHttpRouterFilter
|
||||
//
|
||||
|
||||
absl::string_view XdsHttpRouterFilter::ConfigProtoName() const {
|
||||
return "envoy.extensions.filters.http.router.v3.Router";
|
||||
}
|
||||
|
||||
absl::string_view XdsHttpRouterFilter::OverrideConfigProtoName() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
void XdsHttpRouterFilter::PopulateSymtab(upb_DefPool* symtab) const {
|
||||
envoy_extensions_filters_http_router_v3_Router_getmsgdef(symtab);
|
||||
}
|
||||
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpRouterFilter::GenerateFilterConfig(XdsExtension extension,
|
||||
upb_Arena* arena,
|
||||
ValidationErrors* errors) const {
|
||||
absl::string_view* serialized_filter_config =
|
||||
absl::get_if<absl::string_view>(&extension.value);
|
||||
if (serialized_filter_config == nullptr) {
|
||||
errors->AddError("could not parse router filter config");
|
||||
return absl::nullopt;
|
||||
}
|
||||
if (envoy_extensions_filters_http_router_v3_Router_parse(
|
||||
serialized_filter_config->data(), serialized_filter_config->size(),
|
||||
arena) == nullptr) {
|
||||
errors->AddError("could not parse router filter config");
|
||||
return absl::nullopt;
|
||||
}
|
||||
return FilterConfig{ConfigProtoName(), Json()};
|
||||
}
|
||||
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpRouterFilter::GenerateFilterConfigOverride(
|
||||
XdsExtension /*extension*/, upb_Arena* /*arena*/,
|
||||
ValidationErrors* errors) const {
|
||||
errors->AddError("router filter does not support config override");
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
//
|
||||
// XdsHttpFilterRegistry
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
class XdsHttpRouterFilter : public XdsHttpFilterImpl {
|
||||
public:
|
||||
void PopulateSymtab(upb_DefPool* symtab) const override {
|
||||
envoy_extensions_filters_http_router_v3_Router_getmsgdef(symtab);
|
||||
}
|
||||
|
||||
absl::StatusOr<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena) const override {
|
||||
absl::string_view* serialized_filter_config =
|
||||
absl::get_if<absl::string_view>(&extension.value);
|
||||
if (serialized_filter_config == nullptr) {
|
||||
return absl::InvalidArgumentError("could not parse router filter config");
|
||||
}
|
||||
if (envoy_extensions_filters_http_router_v3_Router_parse(
|
||||
serialized_filter_config->data(), serialized_filter_config->size(),
|
||||
arena) == nullptr) {
|
||||
return absl::InvalidArgumentError("could not parse router filter config");
|
||||
}
|
||||
return FilterConfig{kXdsHttpRouterFilterConfigName, Json()};
|
||||
}
|
||||
|
||||
absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension /*extension*/, upb_Arena* /*arena*/) const override {
|
||||
return absl::InvalidArgumentError(
|
||||
"router filter does not support config override");
|
||||
}
|
||||
|
||||
const grpc_channel_filter* channel_filter() const override { return nullptr; }
|
||||
|
||||
// No-op. This will never be called, since channel_filter() returns null.
|
||||
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
|
||||
const FilterConfig& /*hcm_filter_config*/,
|
||||
const FilterConfig* /*filter_config_override*/) const override {
|
||||
return absl::UnimplementedError("router filter should never be called");
|
||||
}
|
||||
|
||||
bool IsSupportedOnClients() const override { return true; }
|
||||
|
||||
bool IsSupportedOnServers() const override { return true; }
|
||||
|
||||
bool IsTerminalFilter() const override { return true; }
|
||||
};
|
||||
|
||||
using FilterOwnerList = std::vector<std::unique_ptr<XdsHttpFilterImpl>>;
|
||||
using FilterRegistryMap = std::map<absl::string_view, XdsHttpFilterImpl*>;
|
||||
|
||||
|
|
@ -90,10 +92,13 @@ FilterRegistryMap* g_filter_registry = nullptr;
|
|||
} // namespace
|
||||
|
||||
void XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::unique_ptr<XdsHttpFilterImpl> filter,
|
||||
const std::set<absl::string_view>& config_proto_type_names) {
|
||||
for (auto config_proto_type_name : config_proto_type_names) {
|
||||
(*g_filter_registry)[config_proto_type_name] = filter.get();
|
||||
std::unique_ptr<XdsHttpFilterImpl> filter) {
|
||||
GPR_ASSERT(g_filter_registry->emplace(filter->ConfigProtoName(), filter.get())
|
||||
.second);
|
||||
auto override_proto_name = filter->OverrideConfigProtoName();
|
||||
if (!override_proto_name.empty()) {
|
||||
GPR_ASSERT(
|
||||
g_filter_registry->emplace(override_proto_name, filter.get()).second);
|
||||
}
|
||||
g_filters->push_back(std::move(filter));
|
||||
}
|
||||
|
|
@ -111,17 +116,14 @@ void XdsHttpFilterRegistry::PopulateSymtab(upb_DefPool* symtab) {
|
|||
}
|
||||
}
|
||||
|
||||
void XdsHttpFilterRegistry::Init() {
|
||||
void XdsHttpFilterRegistry::Init(bool register_builtins) {
|
||||
g_filters = new FilterOwnerList;
|
||||
g_filter_registry = new FilterRegistryMap;
|
||||
RegisterFilter(std::make_unique<XdsHttpRouterFilter>(),
|
||||
{kXdsHttpRouterFilterConfigName});
|
||||
RegisterFilter(std::make_unique<XdsHttpFaultFilter>(),
|
||||
{kXdsHttpFaultFilterConfigName});
|
||||
RegisterFilter(std::make_unique<XdsHttpRbacFilter>(),
|
||||
{kXdsHttpRbacFilterConfigName});
|
||||
RegisterFilter(std::make_unique<XdsHttpRbacFilter>(),
|
||||
{kXdsHttpRbacFilterConfigOverrideName});
|
||||
if (register_builtins) {
|
||||
RegisterFilter(std::make_unique<XdsHttpRouterFilter>());
|
||||
RegisterFilter(std::make_unique<XdsHttpFaultFilter>());
|
||||
RegisterFilter(std::make_unique<XdsHttpRbacFilter>());
|
||||
}
|
||||
}
|
||||
|
||||
void XdsHttpFilterRegistry::Shutdown() {
|
||||
|
|
|
|||
|
|
@ -20,24 +20,24 @@
|
|||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "upb/arena.h"
|
||||
#include "upb/def.h"
|
||||
|
||||
#include "src/core/ext/xds/xds_common_types.h"
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/channel/channel_fwd.h"
|
||||
#include "src/core/lib/gprpp/validation_errors.h"
|
||||
#include "src/core/lib/json/json.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
extern const char* kXdsHttpRouterFilterConfigName;
|
||||
|
||||
class XdsHttpFilterImpl {
|
||||
public:
|
||||
struct FilterConfig {
|
||||
|
|
@ -69,25 +69,33 @@ class XdsHttpFilterImpl {
|
|||
|
||||
virtual ~XdsHttpFilterImpl() = default;
|
||||
|
||||
// Returns the top-level filter config proto message name.
|
||||
virtual absl::string_view ConfigProtoName() const = 0;
|
||||
|
||||
// Returns the override filter config proto message name.
|
||||
// If empty, no override type is supported.
|
||||
virtual absl::string_view OverrideConfigProtoName() const = 0;
|
||||
|
||||
// Loads the proto message into the upb symtab.
|
||||
virtual void PopulateSymtab(upb_DefPool* symtab) const = 0;
|
||||
|
||||
// Generates a Config from the xDS filter config proto.
|
||||
// Used for the top-level config in the HCM HTTP filter list.
|
||||
virtual absl::StatusOr<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena) const = 0;
|
||||
virtual absl::optional<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const = 0;
|
||||
|
||||
// Generates a Config from the xDS filter config proto.
|
||||
// Used for the typed_per_filter_config override in VirtualHost and Route.
|
||||
virtual absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena) const = 0;
|
||||
virtual absl::optional<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const = 0;
|
||||
|
||||
// C-core channel filter implementation.
|
||||
virtual const grpc_channel_filter* channel_filter() const = 0;
|
||||
|
||||
// Modifies channel args that may affect service config parsing (not
|
||||
// visible to the channel as a whole).
|
||||
// Takes ownership of args. Caller takes ownership of return value.
|
||||
virtual ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const {
|
||||
return args;
|
||||
}
|
||||
|
|
@ -112,11 +120,32 @@ class XdsHttpFilterImpl {
|
|||
virtual bool IsTerminalFilter() const { return false; }
|
||||
};
|
||||
|
||||
class XdsHttpRouterFilter : public XdsHttpFilterImpl {
|
||||
public:
|
||||
absl::string_view ConfigProtoName() const override;
|
||||
absl::string_view OverrideConfigProtoName() const override;
|
||||
void PopulateSymtab(upb_DefPool* symtab) const override;
|
||||
absl::optional<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const override;
|
||||
absl::optional<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const override;
|
||||
const grpc_channel_filter* channel_filter() const override { return nullptr; }
|
||||
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
|
||||
const FilterConfig& /*hcm_filter_config*/,
|
||||
const FilterConfig* /*filter_config_override*/) const override {
|
||||
// This will never be called, since channel_filter() returns null.
|
||||
return absl::UnimplementedError("router filter should never be called");
|
||||
}
|
||||
bool IsSupportedOnClients() const override { return true; }
|
||||
bool IsSupportedOnServers() const override { return true; }
|
||||
bool IsTerminalFilter() const override { return true; }
|
||||
};
|
||||
|
||||
class XdsHttpFilterRegistry {
|
||||
public:
|
||||
static void RegisterFilter(
|
||||
std::unique_ptr<XdsHttpFilterImpl> filter,
|
||||
const std::set<absl::string_view>& config_proto_type_names);
|
||||
static void RegisterFilter(std::unique_ptr<XdsHttpFilterImpl> filter);
|
||||
|
||||
static const XdsHttpFilterImpl* GetFilterForType(
|
||||
absl::string_view proto_type_name);
|
||||
|
|
@ -124,10 +153,10 @@ class XdsHttpFilterRegistry {
|
|||
static void PopulateSymtab(upb_DefPool* symtab);
|
||||
|
||||
// Global init and shutdown.
|
||||
static void Init();
|
||||
static void Init(bool register_builtins = true);
|
||||
static void Shutdown();
|
||||
};
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_XDS_XDS_HTTP_FILTERS_H */
|
||||
#endif // GRPC_CORE_EXT_XDS_XDS_HTTP_FILTERS_H
|
||||
|
|
|
|||
|
|
@ -25,12 +25,9 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/variant.h"
|
||||
#include "envoy/config/core/v3/address.upb.h"
|
||||
|
|
@ -54,12 +51,6 @@
|
|||
|
||||
namespace grpc_core {
|
||||
|
||||
const char* kXdsHttpRbacFilterConfigName =
|
||||
"envoy.extensions.filters.http.rbac.v3.RBAC";
|
||||
|
||||
const char* kXdsHttpRbacFilterConfigOverrideName =
|
||||
"envoy.extensions.filters.http.rbac.v3.RBACPerRoute";
|
||||
|
||||
namespace {
|
||||
|
||||
Json ParseRegexMatcherToJson(
|
||||
|
|
@ -74,18 +65,20 @@ Json ParseInt64RangeToJson(const envoy_type_v3_Int64Range* range) {
|
|||
{"end", envoy_type_v3_Int64Range_end(range)}};
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParseHeaderMatcherToJson(
|
||||
const envoy_config_route_v3_HeaderMatcher* header) {
|
||||
Json ParseHeaderMatcherToJson(const envoy_config_route_v3_HeaderMatcher* header,
|
||||
ValidationErrors* errors) {
|
||||
Json::Object header_json;
|
||||
std::vector<std::string> errors;
|
||||
std::string name =
|
||||
UpbStringToStdString(envoy_config_route_v3_HeaderMatcher_name(header));
|
||||
if (name == ":scheme") {
|
||||
errors.emplace_back("':scheme' not allowed in header");
|
||||
} else if (absl::StartsWith(name, "grpc-")) {
|
||||
errors.emplace_back("'grpc-' prefixes not allowed in header");
|
||||
{
|
||||
ValidationErrors::ScopedField field(errors, ".name");
|
||||
std::string name =
|
||||
UpbStringToStdString(envoy_config_route_v3_HeaderMatcher_name(header));
|
||||
if (name == ":scheme") {
|
||||
errors->AddError("':scheme' not allowed in header");
|
||||
} else if (absl::StartsWith(name, "grpc-")) {
|
||||
errors->AddError("'grpc-' prefixes not allowed in header");
|
||||
}
|
||||
header_json.emplace("name", std::move(name));
|
||||
}
|
||||
header_json.emplace("name", std::move(name));
|
||||
if (envoy_config_route_v3_HeaderMatcher_has_exact_match(header)) {
|
||||
header_json.emplace(
|
||||
"exactMatch",
|
||||
|
|
@ -121,19 +114,16 @@ absl::StatusOr<Json> ParseHeaderMatcherToJson(
|
|||
UpbStringToStdString(
|
||||
envoy_config_route_v3_HeaderMatcher_contains_match(header)));
|
||||
} else {
|
||||
errors.emplace_back("Invalid route header matcher specified.");
|
||||
}
|
||||
if (!errors.empty()) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"errors parsing HeaderMatcher: [", absl::StrJoin(errors, "; "), "]"));
|
||||
errors->AddError("invalid route header matcher specified");
|
||||
}
|
||||
header_json.emplace("invertMatch",
|
||||
envoy_config_route_v3_HeaderMatcher_invert_match(header));
|
||||
return header_json;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParseStringMatcherToJson(
|
||||
const envoy_type_matcher_v3_StringMatcher* matcher) {
|
||||
Json ParseStringMatcherToJson(
|
||||
const envoy_type_matcher_v3_StringMatcher* matcher,
|
||||
ValidationErrors* errors) {
|
||||
Json::Object json;
|
||||
if (envoy_type_matcher_v3_StringMatcher_has_exact(matcher)) {
|
||||
json.emplace("exact",
|
||||
|
|
@ -156,26 +146,23 @@ absl::StatusOr<Json> ParseStringMatcherToJson(
|
|||
UpbStringToStdString(
|
||||
envoy_type_matcher_v3_StringMatcher_contains(matcher)));
|
||||
} else {
|
||||
return absl::InvalidArgumentError("StringMatcher: Invalid match pattern");
|
||||
errors->AddError("invalid match pattern");
|
||||
}
|
||||
json.emplace("ignoreCase",
|
||||
envoy_type_matcher_v3_StringMatcher_ignore_case(matcher));
|
||||
return json;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParsePathMatcherToJson(
|
||||
const envoy_type_matcher_v3_PathMatcher* matcher) {
|
||||
Json ParsePathMatcherToJson(const envoy_type_matcher_v3_PathMatcher* matcher,
|
||||
ValidationErrors* errors) {
|
||||
ValidationErrors::ScopedField field(errors, ".path");
|
||||
const auto* path = envoy_type_matcher_v3_PathMatcher_path(matcher);
|
||||
if (path == nullptr) {
|
||||
return absl::InvalidArgumentError("PathMatcher has empty path");
|
||||
errors->AddError("field not present");
|
||||
return Json();
|
||||
}
|
||||
Json::Object json;
|
||||
auto path_json = ParseStringMatcherToJson(path);
|
||||
if (!path_json.ok()) {
|
||||
return path_json;
|
||||
}
|
||||
json.emplace("path", std::move(*path_json));
|
||||
return json;
|
||||
Json path_json = ParseStringMatcherToJson(path, errors);
|
||||
return Json::Object{{"path", std::move(path_json)}};
|
||||
}
|
||||
|
||||
Json ParseUInt32ValueToJson(const google_protobuf_UInt32Value* value) {
|
||||
|
|
@ -205,65 +192,49 @@ Json ParseMetadataMatcherToJson(
|
|||
return json;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParsePermissionToJson(
|
||||
const envoy_config_rbac_v3_Permission* permission) {
|
||||
Json ParsePermissionToJson(const envoy_config_rbac_v3_Permission* permission,
|
||||
ValidationErrors* errors) {
|
||||
Json::Object permission_json;
|
||||
// Helper function to parse Permission::Set to JSON. Used by `and_rules` and
|
||||
// `or_rules`.
|
||||
auto parse_permission_set_to_json =
|
||||
[](const envoy_config_rbac_v3_Permission_Set* set)
|
||||
-> absl::StatusOr<Json> {
|
||||
std::vector<std::string> errors;
|
||||
[errors](const envoy_config_rbac_v3_Permission_Set* set) -> Json {
|
||||
Json::Array rules_json;
|
||||
size_t size;
|
||||
const envoy_config_rbac_v3_Permission* const* rules =
|
||||
envoy_config_rbac_v3_Permission_Set_rules(set, &size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
auto permission_json = ParsePermissionToJson(rules[i]);
|
||||
if (!permission_json.ok()) {
|
||||
errors.emplace_back(permission_json.status().message());
|
||||
} else {
|
||||
rules_json.emplace_back(std::move(*permission_json));
|
||||
}
|
||||
}
|
||||
if (!errors.empty()) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"errors parsing Set: [", absl::StrJoin(errors, "; "), "]"));
|
||||
ValidationErrors::ScopedField field(errors,
|
||||
absl::StrCat(".rules[", i, "]"));
|
||||
Json permission_json = ParsePermissionToJson(rules[i], errors);
|
||||
rules_json.emplace_back(std::move(permission_json));
|
||||
}
|
||||
return Json::Object({{"rules", std::move(rules_json)}});
|
||||
};
|
||||
if (envoy_config_rbac_v3_Permission_has_and_rules(permission)) {
|
||||
ValidationErrors::ScopedField field(errors, ".and_permission");
|
||||
const auto* and_rules =
|
||||
envoy_config_rbac_v3_Permission_and_rules(permission);
|
||||
auto permission_set_json = parse_permission_set_to_json(and_rules);
|
||||
if (!permission_set_json.ok()) {
|
||||
return permission_set_json;
|
||||
}
|
||||
permission_json.emplace("andRules", std::move(*permission_set_json));
|
||||
Json permission_set_json = parse_permission_set_to_json(and_rules);
|
||||
permission_json.emplace("andRules", std::move(permission_set_json));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_or_rules(permission)) {
|
||||
ValidationErrors::ScopedField field(errors, ".or_permission");
|
||||
const auto* or_rules = envoy_config_rbac_v3_Permission_or_rules(permission);
|
||||
auto permission_set_json = parse_permission_set_to_json(or_rules);
|
||||
if (!permission_set_json.ok()) {
|
||||
return permission_set_json;
|
||||
}
|
||||
permission_json.emplace("orRules", std::move(*permission_set_json));
|
||||
Json permission_set_json = parse_permission_set_to_json(or_rules);
|
||||
permission_json.emplace("orRules", std::move(permission_set_json));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_any(permission)) {
|
||||
permission_json.emplace("any",
|
||||
envoy_config_rbac_v3_Permission_any(permission));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_header(permission)) {
|
||||
auto header_json = ParseHeaderMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_header(permission));
|
||||
if (!header_json.ok()) {
|
||||
return header_json;
|
||||
}
|
||||
permission_json.emplace("header", std::move(*header_json));
|
||||
ValidationErrors::ScopedField field(errors, ".header");
|
||||
Json header_json = ParseHeaderMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_header(permission), errors);
|
||||
permission_json.emplace("header", std::move(header_json));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_url_path(permission)) {
|
||||
auto url_path_json = ParsePathMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_url_path(permission));
|
||||
if (!url_path_json.ok()) {
|
||||
return url_path_json;
|
||||
}
|
||||
permission_json.emplace("urlPath", std::move(*url_path_json));
|
||||
ValidationErrors::ScopedField field(errors, ".url_path");
|
||||
Json url_path_json = ParsePathMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_url_path(permission), errors);
|
||||
permission_json.emplace("urlPath", std::move(url_path_json));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_destination_ip(permission)) {
|
||||
permission_json.emplace(
|
||||
"destinationIp",
|
||||
|
|
@ -278,69 +249,53 @@ absl::StatusOr<Json> ParsePermissionToJson(
|
|||
"metadata", ParseMetadataMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_metadata(permission)));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_not_rule(permission)) {
|
||||
auto not_rule_json = ParsePermissionToJson(
|
||||
envoy_config_rbac_v3_Permission_not_rule(permission));
|
||||
if (!not_rule_json.ok()) {
|
||||
return not_rule_json;
|
||||
}
|
||||
permission_json.emplace("notRule", std::move(*not_rule_json));
|
||||
ValidationErrors::ScopedField field(errors, ".not_rule");
|
||||
Json not_rule_json = ParsePermissionToJson(
|
||||
envoy_config_rbac_v3_Permission_not_rule(permission), errors);
|
||||
permission_json.emplace("notRule", std::move(not_rule_json));
|
||||
} else if (envoy_config_rbac_v3_Permission_has_requested_server_name(
|
||||
permission)) {
|
||||
auto requested_server_name_json = ParseStringMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_requested_server_name(permission));
|
||||
if (!requested_server_name_json.ok()) {
|
||||
return requested_server_name_json;
|
||||
}
|
||||
ValidationErrors::ScopedField field(errors, ".requested_server_name");
|
||||
Json requested_server_name_json = ParseStringMatcherToJson(
|
||||
envoy_config_rbac_v3_Permission_requested_server_name(permission),
|
||||
errors);
|
||||
permission_json.emplace("requestedServerName",
|
||||
std::move(*requested_server_name_json));
|
||||
std::move(requested_server_name_json));
|
||||
} else {
|
||||
return absl::InvalidArgumentError("Permission: Invalid rule");
|
||||
errors->AddError("invalid rule");
|
||||
}
|
||||
return permission_json;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParsePrincipalToJson(
|
||||
const envoy_config_rbac_v3_Principal* principal) {
|
||||
Json ParsePrincipalToJson(const envoy_config_rbac_v3_Principal* principal,
|
||||
ValidationErrors* errors) {
|
||||
Json::Object principal_json;
|
||||
// Helper function to parse Principal::Set to JSON. Used by `and_ids` and
|
||||
// `or_ids`.
|
||||
auto parse_principal_set_to_json =
|
||||
[](const envoy_config_rbac_v3_Principal_Set* set)
|
||||
-> absl::StatusOr<Json> {
|
||||
Json::Object json;
|
||||
std::vector<std::string> errors;
|
||||
[errors](const envoy_config_rbac_v3_Principal_Set* set) -> Json {
|
||||
Json::Array ids_json;
|
||||
size_t size;
|
||||
const envoy_config_rbac_v3_Principal* const* ids =
|
||||
envoy_config_rbac_v3_Principal_Set_ids(set, &size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
auto principal_json = ParsePrincipalToJson(ids[i]);
|
||||
if (!principal_json.ok()) {
|
||||
errors.emplace_back(principal_json.status().message());
|
||||
} else {
|
||||
ids_json.emplace_back(std::move(*principal_json));
|
||||
}
|
||||
}
|
||||
if (!errors.empty()) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"errors parsing Set: [", absl::StrJoin(errors, "; "), "]"));
|
||||
ValidationErrors::ScopedField field(errors,
|
||||
absl::StrCat(".ids[", i, "]"));
|
||||
Json principal_json = ParsePrincipalToJson(ids[i], errors);
|
||||
ids_json.emplace_back(std::move(principal_json));
|
||||
}
|
||||
return Json::Object({{"ids", std::move(ids_json)}});
|
||||
};
|
||||
if (envoy_config_rbac_v3_Principal_has_and_ids(principal)) {
|
||||
ValidationErrors::ScopedField field(errors, ".and_ids");
|
||||
const auto* and_rules = envoy_config_rbac_v3_Principal_and_ids(principal);
|
||||
auto principal_set_json = parse_principal_set_to_json(and_rules);
|
||||
if (!principal_set_json.ok()) {
|
||||
return principal_set_json;
|
||||
}
|
||||
principal_json.emplace("andIds", std::move(*principal_set_json));
|
||||
Json principal_set_json = parse_principal_set_to_json(and_rules);
|
||||
principal_json.emplace("andIds", std::move(principal_set_json));
|
||||
} else if (envoy_config_rbac_v3_Principal_has_or_ids(principal)) {
|
||||
ValidationErrors::ScopedField field(errors, ".or_ids");
|
||||
const auto* or_rules = envoy_config_rbac_v3_Principal_or_ids(principal);
|
||||
auto principal_set_json = parse_principal_set_to_json(or_rules);
|
||||
if (!principal_set_json.ok()) {
|
||||
return principal_set_json;
|
||||
}
|
||||
principal_json.emplace("orIds", std::move(*principal_set_json));
|
||||
Json principal_set_json = parse_principal_set_to_json(or_rules);
|
||||
principal_json.emplace("orIds", std::move(principal_set_json));
|
||||
} else if (envoy_config_rbac_v3_Principal_has_any(principal)) {
|
||||
principal_json.emplace("any",
|
||||
envoy_config_rbac_v3_Principal_any(principal));
|
||||
|
|
@ -352,12 +307,12 @@ absl::StatusOr<Json> ParsePrincipalToJson(
|
|||
envoy_config_rbac_v3_Principal_Authenticated_principal_name(
|
||||
envoy_config_rbac_v3_Principal_authenticated(principal));
|
||||
if (principal_name != nullptr) {
|
||||
auto principal_name_json = ParseStringMatcherToJson(principal_name);
|
||||
if (!principal_name_json.ok()) {
|
||||
return principal_name_json;
|
||||
}
|
||||
ValidationErrors::ScopedField field(errors,
|
||||
".authenticated.principal_name");
|
||||
Json principal_name_json =
|
||||
ParseStringMatcherToJson(principal_name, errors);
|
||||
authenticated_json->emplace("principalName",
|
||||
std::move(*principal_name_json));
|
||||
std::move(principal_name_json));
|
||||
}
|
||||
} else if (envoy_config_rbac_v3_Principal_has_source_ip(principal)) {
|
||||
principal_json.emplace(
|
||||
|
|
@ -373,84 +328,71 @@ absl::StatusOr<Json> ParsePrincipalToJson(
|
|||
"remoteIp", ParseCidrRangeToJson(
|
||||
envoy_config_rbac_v3_Principal_remote_ip(principal)));
|
||||
} else if (envoy_config_rbac_v3_Principal_has_header(principal)) {
|
||||
auto header_json = ParseHeaderMatcherToJson(
|
||||
envoy_config_rbac_v3_Principal_header(principal));
|
||||
if (!header_json.ok()) {
|
||||
return header_json;
|
||||
}
|
||||
principal_json.emplace("header", std::move(*header_json));
|
||||
ValidationErrors::ScopedField field(errors, ".header");
|
||||
Json header_json = ParseHeaderMatcherToJson(
|
||||
envoy_config_rbac_v3_Principal_header(principal), errors);
|
||||
principal_json.emplace("header", std::move(header_json));
|
||||
} else if (envoy_config_rbac_v3_Principal_has_url_path(principal)) {
|
||||
auto url_path_json = ParsePathMatcherToJson(
|
||||
envoy_config_rbac_v3_Principal_url_path(principal));
|
||||
if (!url_path_json.ok()) {
|
||||
return url_path_json;
|
||||
}
|
||||
principal_json.emplace("urlPath", std::move(*url_path_json));
|
||||
ValidationErrors::ScopedField field(errors, ".url_path");
|
||||
Json url_path_json = ParsePathMatcherToJson(
|
||||
envoy_config_rbac_v3_Principal_url_path(principal), errors);
|
||||
principal_json.emplace("urlPath", std::move(url_path_json));
|
||||
} else if (envoy_config_rbac_v3_Principal_has_metadata(principal)) {
|
||||
principal_json.emplace(
|
||||
"metadata", ParseMetadataMatcherToJson(
|
||||
envoy_config_rbac_v3_Principal_metadata(principal)));
|
||||
} else if (envoy_config_rbac_v3_Principal_has_not_id(principal)) {
|
||||
auto not_id_json =
|
||||
ParsePrincipalToJson(envoy_config_rbac_v3_Principal_not_id(principal));
|
||||
if (!not_id_json.ok()) {
|
||||
return not_id_json;
|
||||
}
|
||||
principal_json.emplace("notId", std::move(*not_id_json));
|
||||
ValidationErrors::ScopedField field(errors, ".not_id");
|
||||
Json not_id_json = ParsePrincipalToJson(
|
||||
envoy_config_rbac_v3_Principal_not_id(principal), errors);
|
||||
principal_json.emplace("notId", std::move(not_id_json));
|
||||
} else {
|
||||
return absl::InvalidArgumentError("Principal: Invalid rule");
|
||||
errors->AddError("invalid rule");
|
||||
}
|
||||
return principal_json;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParsePolicyToJson(
|
||||
const envoy_config_rbac_v3_Policy* policy) {
|
||||
Json ParsePolicyToJson(const envoy_config_rbac_v3_Policy* policy,
|
||||
ValidationErrors* errors) {
|
||||
Json::Object policy_json;
|
||||
std::vector<std::string> errors;
|
||||
size_t size;
|
||||
Json::Array permissions_json;
|
||||
const envoy_config_rbac_v3_Permission* const* permissions =
|
||||
envoy_config_rbac_v3_Policy_permissions(policy, &size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
auto permission_json = ParsePermissionToJson(permissions[i]);
|
||||
if (!permission_json.ok()) {
|
||||
errors.emplace_back(permission_json.status().message());
|
||||
} else {
|
||||
permissions_json.emplace_back(std::move(*permission_json));
|
||||
}
|
||||
ValidationErrors::ScopedField field(errors,
|
||||
absl::StrCat(".permissions[", i, "]"));
|
||||
Json permission_json = ParsePermissionToJson(permissions[i], errors);
|
||||
permissions_json.emplace_back(std::move(permission_json));
|
||||
}
|
||||
policy_json.emplace("permissions", std::move(permissions_json));
|
||||
Json::Array principals_json;
|
||||
const envoy_config_rbac_v3_Principal* const* principals =
|
||||
envoy_config_rbac_v3_Policy_principals(policy, &size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
auto principal_json = ParsePrincipalToJson(principals[i]);
|
||||
if (!principal_json.ok()) {
|
||||
errors.emplace_back(principal_json.status().message());
|
||||
} else {
|
||||
principals_json.emplace_back(std::move(*principal_json));
|
||||
}
|
||||
ValidationErrors::ScopedField field(errors,
|
||||
absl::StrCat(".principals[", i, "]"));
|
||||
Json principal_json = ParsePrincipalToJson(principals[i], errors);
|
||||
principals_json.emplace_back(std::move(principal_json));
|
||||
}
|
||||
policy_json.emplace("principals", std::move(principals_json));
|
||||
if (envoy_config_rbac_v3_Policy_has_condition(policy)) {
|
||||
errors.emplace_back("Policy: condition not supported");
|
||||
ValidationErrors::ScopedField field(errors, ".condition");
|
||||
errors->AddError("condition not supported");
|
||||
}
|
||||
if (envoy_config_rbac_v3_Policy_has_checked_condition(policy)) {
|
||||
errors.emplace_back("Policy: checked condition not supported");
|
||||
}
|
||||
if (!errors.empty()) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"errors parsing Policy: [", absl::StrJoin(errors, "; "), "]"));
|
||||
ValidationErrors::ScopedField field(errors, ".checked_condition");
|
||||
errors->AddError("checked condition not supported");
|
||||
}
|
||||
return policy_json;
|
||||
}
|
||||
|
||||
absl::StatusOr<Json> ParseHttpRbacToJson(
|
||||
const envoy_extensions_filters_http_rbac_v3_RBAC* rbac) {
|
||||
Json ParseHttpRbacToJson(const envoy_extensions_filters_http_rbac_v3_RBAC* rbac,
|
||||
ValidationErrors* errors) {
|
||||
Json::Object rbac_json;
|
||||
std::vector<std::string> errors;
|
||||
const auto* rules = envoy_extensions_filters_http_rbac_v3_RBAC_rules(rbac);
|
||||
if (rules != nullptr) {
|
||||
ValidationErrors::ScopedField field(errors, ".rules");
|
||||
int action = envoy_config_rbac_v3_RBAC_action(rules);
|
||||
// Treat Log action as RBAC being absent
|
||||
if (action == envoy_config_rbac_v3_RBAC_LOG) {
|
||||
|
|
@ -466,89 +408,82 @@ absl::StatusOr<Json> ParseHttpRbacToJson(
|
|||
if (entry == nullptr) {
|
||||
break;
|
||||
}
|
||||
auto policy = ParsePolicyToJson(
|
||||
envoy_config_rbac_v3_RBAC_PoliciesEntry_value(entry));
|
||||
if (!policy.ok()) {
|
||||
errors.emplace_back(absl::StrCat(
|
||||
"RBAC PoliciesEntry key:",
|
||||
UpbStringToStdString(
|
||||
envoy_config_rbac_v3_RBAC_PoliciesEntry_key(entry)),
|
||||
" error:", policy.status().message()));
|
||||
} else {
|
||||
policies_object.emplace(
|
||||
UpbStringToStdString(
|
||||
envoy_config_rbac_v3_RBAC_PoliciesEntry_key(entry)),
|
||||
std::move(*policy));
|
||||
}
|
||||
absl::string_view key =
|
||||
UpbStringToAbsl(envoy_config_rbac_v3_RBAC_PoliciesEntry_key(entry));
|
||||
ValidationErrors::ScopedField field(
|
||||
errors, absl::StrCat(".policies[", key, "]"));
|
||||
Json policy = ParsePolicyToJson(
|
||||
envoy_config_rbac_v3_RBAC_PoliciesEntry_value(entry), errors);
|
||||
policies_object.emplace(std::string(key), std::move(policy));
|
||||
}
|
||||
inner_rbac_json.emplace("policies", std::move(policies_object));
|
||||
}
|
||||
rbac_json.emplace("rules", std::move(inner_rbac_json));
|
||||
}
|
||||
if (!errors.empty()) {
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"errors parsing RBAC: [", absl::StrJoin(errors, "; "), "]"));
|
||||
}
|
||||
return rbac_json;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
absl::string_view XdsHttpRbacFilter::ConfigProtoName() const {
|
||||
return "envoy.extensions.filters.http.rbac.v3.RBAC";
|
||||
}
|
||||
|
||||
absl::string_view XdsHttpRbacFilter::OverrideConfigProtoName() const {
|
||||
return "envoy.extensions.filters.http.rbac.v3.RBACPerRoute";
|
||||
}
|
||||
|
||||
void XdsHttpRbacFilter::PopulateSymtab(upb_DefPool* symtab) const {
|
||||
envoy_extensions_filters_http_rbac_v3_RBAC_getmsgdef(symtab);
|
||||
}
|
||||
|
||||
absl::StatusOr<XdsHttpFilterImpl::FilterConfig>
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpRbacFilter::GenerateFilterConfig(XdsExtension extension,
|
||||
upb_Arena* arena) const {
|
||||
upb_Arena* arena,
|
||||
ValidationErrors* errors) const {
|
||||
absl::string_view* serialized_filter_config =
|
||||
absl::get_if<absl::string_view>(&extension.value);
|
||||
if (serialized_filter_config == nullptr) {
|
||||
return absl::InvalidArgumentError(
|
||||
"could not parse HTTP RBAC filter config");
|
||||
errors->AddError("could not parse HTTP RBAC filter config");
|
||||
return absl::nullopt;
|
||||
}
|
||||
auto* rbac = envoy_extensions_filters_http_rbac_v3_RBAC_parse(
|
||||
serialized_filter_config->data(), serialized_filter_config->size(),
|
||||
arena);
|
||||
if (rbac == nullptr) {
|
||||
return absl::InvalidArgumentError(
|
||||
"could not parse HTTP RBAC filter config");
|
||||
errors->AddError("could not parse HTTP RBAC filter config");
|
||||
return absl::nullopt;
|
||||
}
|
||||
absl::StatusOr<Json> rbac_json = ParseHttpRbacToJson(rbac);
|
||||
if (!rbac_json.ok()) {
|
||||
return rbac_json.status();
|
||||
}
|
||||
return FilterConfig{kXdsHttpRbacFilterConfigName, std::move(*rbac_json)};
|
||||
return FilterConfig{ConfigProtoName(), ParseHttpRbacToJson(rbac, errors)};
|
||||
}
|
||||
|
||||
absl::StatusOr<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpRbacFilter::GenerateFilterConfigOverride(XdsExtension extension,
|
||||
upb_Arena* arena) const {
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig>
|
||||
XdsHttpRbacFilter::GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena, ValidationErrors* errors) const {
|
||||
absl::string_view* serialized_filter_config =
|
||||
absl::get_if<absl::string_view>(&extension.value);
|
||||
if (serialized_filter_config == nullptr) {
|
||||
return absl::InvalidArgumentError("could not parse RBACPerRoute");
|
||||
errors->AddError("could not parse RBACPerRoute");
|
||||
return absl::nullopt;
|
||||
}
|
||||
auto* rbac_per_route =
|
||||
envoy_extensions_filters_http_rbac_v3_RBACPerRoute_parse(
|
||||
serialized_filter_config->data(), serialized_filter_config->size(),
|
||||
arena);
|
||||
if (rbac_per_route == nullptr) {
|
||||
return absl::InvalidArgumentError("could not parse RBACPerRoute");
|
||||
errors->AddError("could not parse RBACPerRoute");
|
||||
return absl::nullopt;
|
||||
}
|
||||
absl::StatusOr<Json> rbac_json;
|
||||
Json rbac_json;
|
||||
const auto* rbac =
|
||||
envoy_extensions_filters_http_rbac_v3_RBACPerRoute_rbac(rbac_per_route);
|
||||
if (rbac == nullptr) {
|
||||
rbac_json = Json::Object();
|
||||
} else {
|
||||
rbac_json = ParseHttpRbacToJson(rbac);
|
||||
if (!rbac_json.ok()) {
|
||||
return rbac_json.status();
|
||||
}
|
||||
ValidationErrors::ScopedField field(errors, ".rbac");
|
||||
rbac_json = ParseHttpRbacToJson(rbac, errors);
|
||||
}
|
||||
return FilterConfig{kXdsHttpRbacFilterConfigOverrideName,
|
||||
std::move(*rbac_json)};
|
||||
return FilterConfig{OverrideConfigProtoName(), std::move(rbac_json)};
|
||||
}
|
||||
|
||||
const grpc_channel_filter* XdsHttpRbacFilter::channel_filter() const {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "upb/arena.h"
|
||||
#include "upb/def.h"
|
||||
|
||||
|
|
@ -27,32 +29,27 @@
|
|||
#include "src/core/ext/xds/xds_http_filters.h"
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/channel/channel_fwd.h"
|
||||
#include "src/core/lib/gprpp/validation_errors.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
extern const char* kXdsHttpRbacFilterConfigName;
|
||||
extern const char* kXdsHttpRbacFilterConfigOverrideName;
|
||||
|
||||
class XdsHttpRbacFilter : public XdsHttpFilterImpl {
|
||||
public:
|
||||
absl::string_view ConfigProtoName() const override;
|
||||
absl::string_view OverrideConfigProtoName() const override;
|
||||
void PopulateSymtab(upb_DefPool* symtab) const override;
|
||||
|
||||
absl::StatusOr<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena) const override;
|
||||
|
||||
absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena) const override;
|
||||
|
||||
absl::optional<FilterConfig> GenerateFilterConfig(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const override;
|
||||
absl::optional<FilterConfig> GenerateFilterConfigOverride(
|
||||
XdsExtension extension, upb_Arena* arena,
|
||||
ValidationErrors* errors) const override;
|
||||
const grpc_channel_filter* channel_filter() const override;
|
||||
|
||||
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
|
||||
|
||||
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
|
||||
const FilterConfig& hcm_filter_config,
|
||||
const FilterConfig* filter_config_override) const override;
|
||||
|
||||
bool IsSupportedOnClients() const override { return false; }
|
||||
|
||||
bool IsSupportedOnServers() const override { return true; }
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "absl/types/variant.h"
|
||||
#include "envoy/config/listener/v3/listener.upbdefs.h"
|
||||
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h"
|
||||
#include "upb/def.h"
|
||||
|
|
@ -46,36 +47,14 @@
|
|||
|
||||
namespace grpc_core {
|
||||
|
||||
// TODO(roth): When we can use absl::variant<>, consider using that
|
||||
// here, to enforce the fact that only one of the two fields can be set.
|
||||
struct XdsListenerResource : public XdsResourceType::ResourceData {
|
||||
struct DownstreamTlsContext {
|
||||
CommonTlsContext common_tls_context;
|
||||
bool require_client_certificate = false;
|
||||
|
||||
bool operator==(const DownstreamTlsContext& other) const {
|
||||
return common_tls_context == other.common_tls_context &&
|
||||
require_client_certificate == other.require_client_certificate;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
bool Empty() const;
|
||||
};
|
||||
|
||||
enum class ListenerType {
|
||||
kTcpListener = 0,
|
||||
kHttpApiListener,
|
||||
} type;
|
||||
|
||||
struct HttpConnectionManager {
|
||||
// The name to use in the RDS request.
|
||||
std::string route_config_name;
|
||||
// The RDS resource name or inline RouteConfiguration.
|
||||
absl::variant<std::string, XdsRouteConfigResource> route_config;
|
||||
|
||||
// Storing the Http Connection Manager Common Http Protocol Option
|
||||
// max_stream_duration
|
||||
Duration http_max_stream_duration;
|
||||
// The RouteConfiguration to use for this listener.
|
||||
// Present only if it is inlined in the LDS response.
|
||||
absl::optional<XdsRouteConfigResource> rds_update;
|
||||
|
||||
struct HttpFilter {
|
||||
std::string name;
|
||||
|
|
@ -90,21 +69,26 @@ struct XdsListenerResource : public XdsResourceType::ResourceData {
|
|||
std::vector<HttpFilter> http_filters;
|
||||
|
||||
bool operator==(const HttpConnectionManager& other) const {
|
||||
return route_config_name == other.route_config_name &&
|
||||
return route_config == other.route_config &&
|
||||
http_max_stream_duration == other.http_max_stream_duration &&
|
||||
rds_update == other.rds_update &&
|
||||
http_filters == other.http_filters;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
// Populated for type=kHttpApiListener.
|
||||
HttpConnectionManager http_connection_manager;
|
||||
struct DownstreamTlsContext {
|
||||
CommonTlsContext common_tls_context;
|
||||
bool require_client_certificate = false;
|
||||
|
||||
// Populated for type=kTcpListener.
|
||||
// host:port listening_address set when type is kTcpListener
|
||||
std::string address;
|
||||
bool operator==(const DownstreamTlsContext& other) const {
|
||||
return common_tls_context == other.common_tls_context &&
|
||||
require_client_certificate == other.require_client_certificate;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
bool Empty() const;
|
||||
};
|
||||
|
||||
struct FilterChainData {
|
||||
DownstreamTlsContext downstream_tls_context;
|
||||
|
|
@ -185,15 +169,26 @@ struct XdsListenerResource : public XdsResourceType::ResourceData {
|
|||
}
|
||||
|
||||
std::string ToString() const;
|
||||
} filter_chain_map;
|
||||
};
|
||||
|
||||
absl::optional<FilterChainData> default_filter_chain;
|
||||
struct TcpListener {
|
||||
std::string address; // host:port listening address
|
||||
FilterChainMap filter_chain_map;
|
||||
absl::optional<FilterChainData> default_filter_chain;
|
||||
|
||||
bool operator==(const TcpListener& other) const {
|
||||
return address == other.address &&
|
||||
filter_chain_map == other.filter_chain_map &&
|
||||
default_filter_chain == other.default_filter_chain;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
absl::variant<HttpConnectionManager, TcpListener> listener;
|
||||
|
||||
bool operator==(const XdsListenerResource& other) const {
|
||||
return http_connection_manager == other.http_connection_manager &&
|
||||
address == other.address &&
|
||||
filter_chain_map == other.filter_chain_map &&
|
||||
default_filter_chain == other.default_filter_chain;
|
||||
return listener == other.listener;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
|
|
|
|||
|
|
@ -638,14 +638,13 @@ ParseTypedPerFilterConfig(
|
|||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"no filter registered for config type ", extension->type));
|
||||
}
|
||||
absl::StatusOr<XdsHttpFilterImpl::FilterConfig> filter_config =
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig> filter_config =
|
||||
filter_impl->GenerateFilterConfigOverride(std::move(*extension),
|
||||
context.arena);
|
||||
if (!filter_config.ok()) {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrCat("filter config for type ", extension->type,
|
||||
" failed to parse: ", filter_config.status().message()));
|
||||
context.arena, &errors);
|
||||
if (!errors.ok()) {
|
||||
return errors.status("errors validation extension");
|
||||
}
|
||||
GPR_ASSERT(filter_config.has_value());
|
||||
typed_per_filter_config[std::string(key)] = std::move(*filter_config);
|
||||
}
|
||||
return typed_per_filter_config;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
#include "src/core/lib/debug/trace.h"
|
||||
#include "src/core/lib/gprpp/debug_location.h"
|
||||
#include "src/core/lib/gprpp/host_port.h"
|
||||
#include "src/core/lib/gprpp/match.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/gprpp/status_helper.h"
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
|
|
@ -550,7 +551,9 @@ void XdsServerConfigFetcher::ListenerWatcher::OnResourceChanged(
|
|||
"[ListenerWatcher %p] Received LDS update from xds client %p: %s",
|
||||
this, xds_client_.get(), listener.ToString().c_str());
|
||||
}
|
||||
if (listener.address != listening_address_) {
|
||||
auto& tcp_listener =
|
||||
absl::get<XdsListenerResource::TcpListener>(listener.listener);
|
||||
if (tcp_listener.address != listening_address_) {
|
||||
MutexLock lock(&mu_);
|
||||
OnFatalError(absl::FailedPreconditionError(
|
||||
"Address in LDS update does not match listening address"));
|
||||
|
|
@ -558,8 +561,8 @@ void XdsServerConfigFetcher::ListenerWatcher::OnResourceChanged(
|
|||
}
|
||||
auto new_filter_chain_match_manager = MakeRefCounted<FilterChainMatchManager>(
|
||||
xds_client_->Ref(DEBUG_LOCATION, "FilterChainMatchManager"),
|
||||
std::move(listener.filter_chain_map),
|
||||
std::move(listener.default_filter_chain));
|
||||
std::move(tcp_listener.filter_chain_map),
|
||||
std::move(tcp_listener.default_filter_chain));
|
||||
MutexLock lock(&mu_);
|
||||
if (filter_chain_match_manager_ == nullptr ||
|
||||
!(new_filter_chain_match_manager->filter_chain_map() ==
|
||||
|
|
@ -675,32 +678,25 @@ void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
|
|||
for (const auto& source_type : destination_ip.source_types_array) {
|
||||
for (const auto& source_ip : source_type) {
|
||||
for (const auto& source_port_pair : source_ip.ports_map) {
|
||||
if (!source_port_pair.second.data->http_connection_manager
|
||||
.route_config_name.empty()) {
|
||||
resource_names.insert(
|
||||
source_port_pair.second.data->http_connection_manager
|
||||
.route_config_name);
|
||||
}
|
||||
filter_chain_data_set.insert(source_port_pair.second.data.get());
|
||||
auto* filter_chain_data = source_port_pair.second.data.get();
|
||||
const auto* rds_name = absl::get_if<std::string>(
|
||||
&filter_chain_data->http_connection_manager.route_config);
|
||||
if (rds_name != nullptr) resource_names.insert(*rds_name);
|
||||
filter_chain_data_set.insert(filter_chain_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (default_filter_chain_.has_value()) {
|
||||
if (!default_filter_chain_->http_connection_manager.route_config_name
|
||||
.empty()) {
|
||||
resource_names.insert(
|
||||
default_filter_chain_->http_connection_manager.route_config_name);
|
||||
}
|
||||
std::reverse(
|
||||
default_filter_chain_->http_connection_manager.http_filters.begin(),
|
||||
default_filter_chain_->http_connection_manager.http_filters.end());
|
||||
auto& hcm = default_filter_chain_->http_connection_manager;
|
||||
const auto* rds_name = absl::get_if<std::string>(&hcm.route_config);
|
||||
if (rds_name != nullptr) resource_names.insert(*rds_name);
|
||||
std::reverse(hcm.http_filters.begin(), hcm.http_filters.end());
|
||||
}
|
||||
// Reverse the lists of HTTP filters in all the filter chains
|
||||
for (auto* filter_chain_data : filter_chain_data_set) {
|
||||
std::reverse(
|
||||
filter_chain_data->http_connection_manager.http_filters.begin(),
|
||||
filter_chain_data->http_connection_manager.http_filters.end());
|
||||
auto& hcm = filter_chain_data->http_connection_manager;
|
||||
std::reverse(hcm.http_filters.begin(), hcm.http_filters.end());
|
||||
}
|
||||
// Start watching on referenced RDS resources
|
||||
struct WatcherToStart {
|
||||
|
|
@ -1076,27 +1072,29 @@ absl::StatusOr<ChannelArgs> XdsServerConfigFetcher::ListenerWatcher::
|
|||
filters.push_back(&kServerConfigSelectorFilter);
|
||||
channel_stack_modifier =
|
||||
MakeRefCounted<XdsChannelStackModifier>(std::move(filters));
|
||||
if (filter_chain->http_connection_manager.rds_update.has_value()) {
|
||||
server_config_selector_provider =
|
||||
MakeRefCounted<StaticXdsServerConfigSelectorProvider>(
|
||||
filter_chain->http_connection_manager.rds_update.value(),
|
||||
filter_chain->http_connection_manager.http_filters);
|
||||
} else {
|
||||
absl::StatusOr<XdsRouteConfigResource> initial_resource;
|
||||
{
|
||||
MutexLock lock(&mu_);
|
||||
initial_resource =
|
||||
rds_map_[filter_chain->http_connection_manager.route_config_name]
|
||||
.rds_update.value();
|
||||
}
|
||||
server_config_selector_provider =
|
||||
MakeRefCounted<DynamicXdsServerConfigSelectorProvider>(
|
||||
xds_client_->Ref(DEBUG_LOCATION,
|
||||
"DynamicXdsServerConfigSelectorProvider"),
|
||||
filter_chain->http_connection_manager.route_config_name,
|
||||
std::move(initial_resource),
|
||||
filter_chain->http_connection_manager.http_filters);
|
||||
}
|
||||
Match(
|
||||
filter_chain->http_connection_manager.route_config,
|
||||
// RDS resource name
|
||||
[&](const std::string& rds_name) {
|
||||
absl::StatusOr<XdsRouteConfigResource> initial_resource;
|
||||
{
|
||||
MutexLock lock(&mu_);
|
||||
initial_resource = rds_map_[rds_name].rds_update.value();
|
||||
}
|
||||
server_config_selector_provider =
|
||||
MakeRefCounted<DynamicXdsServerConfigSelectorProvider>(
|
||||
xds_client_->Ref(DEBUG_LOCATION,
|
||||
"DynamicXdsServerConfigSelectorProvider"),
|
||||
rds_name, std::move(initial_resource),
|
||||
filter_chain->http_connection_manager.http_filters);
|
||||
},
|
||||
// inline RouteConfig
|
||||
[&](const XdsRouteConfigResource& route_config) {
|
||||
server_config_selector_provider =
|
||||
MakeRefCounted<StaticXdsServerConfigSelectorProvider>(
|
||||
route_config,
|
||||
filter_chain->http_connection_manager.http_filters);
|
||||
});
|
||||
args = args.SetObject(server_config_selector_provider)
|
||||
.SetObject(channel_stack_modifier);
|
||||
// Add XdsCertificateProvider if credentials are xDS.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ import "google/protobuf/wrappers.proto";
|
|||
|
||||
// [#next-free-field: 7]
|
||||
message SocketAddress {
|
||||
enum Protocol {
|
||||
TCP = 0;
|
||||
UDP = 1;
|
||||
}
|
||||
Protocol protocol = 1;
|
||||
|
||||
// The address for this socket. :ref:`Listeners <config_listeners>` will bind
|
||||
// to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::``
|
||||
// to bind to any address. [#comment:TODO(zuercher) reinstate when implemented:
|
||||
|
|
|
|||
|
|
@ -426,6 +426,8 @@ message HeaderMatcher {
|
|||
//
|
||||
// * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*.
|
||||
string suffix_match = 10;
|
||||
|
||||
string contains_match = 12;
|
||||
}
|
||||
|
||||
// If specified, the match result will be inverted before checking. Defaults to false.
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ grpc_cc_test(
|
|||
srcs = ["xds_lb_policy_registry_test.cc"],
|
||||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
uses_event_engine = False,
|
||||
uses_polling = False,
|
||||
deps = [
|
||||
"//:gpr",
|
||||
|
|
@ -174,6 +175,47 @@ grpc_cc_test(
|
|||
],
|
||||
)
|
||||
|
||||
grpc_cc_test(
|
||||
name = "xds_http_filters_test",
|
||||
srcs = ["xds_http_filters_test.cc"],
|
||||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
uses_event_engine = False,
|
||||
uses_polling = False,
|
||||
deps = [
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
"//src/proto/grpc/testing/xds/v3:fault_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:http_filter_rbac_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:router_proto",
|
||||
"//test/core/util:grpc_test_util",
|
||||
"//test/cpp/util:grpc_cli_utils",
|
||||
],
|
||||
)
|
||||
|
||||
grpc_cc_test(
|
||||
name = "xds_listener_resource_type_test",
|
||||
srcs = ["xds_listener_resource_type_test.cc"],
|
||||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
uses_event_engine = False,
|
||||
uses_polling = False,
|
||||
deps = [
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
"//src/core:grpc_xds_client",
|
||||
"//src/proto/grpc/testing/xds/v3:fault_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",
|
||||
"//src/proto/grpc/testing/xds/v3:router_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:tls_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:typed_struct_proto",
|
||||
"//test/core/util:grpc_test_util",
|
||||
"//test/cpp/util:grpc_cli_utils",
|
||||
],
|
||||
)
|
||||
|
||||
grpc_cc_test(
|
||||
name = "xds_cluster_resource_type_test",
|
||||
srcs = ["xds_cluster_resource_type_test.cc"],
|
||||
|
|
@ -188,6 +230,7 @@ grpc_cc_test(
|
|||
"//src/proto/grpc/testing/xds/v3:aggregate_cluster_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:cluster_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:tls_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:typed_struct_proto",
|
||||
"//test/core/util:grpc_test_util",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include "src/proto/grpc/testing/xds/v3/endpoint.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/outlier_detection.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/tls.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/typed_struct.pb.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
using envoy::config::cluster::v3::Cluster;
|
||||
|
|
@ -809,7 +810,7 @@ TEST_F(TlsConfigTest, UnknownCertificateProviderInstance) {
|
|||
<< decode_result.resource.status();
|
||||
}
|
||||
|
||||
TEST_F(TlsConfigTest, TransportSocketTypedConfigUnset) {
|
||||
TEST_F(TlsConfigTest, UnknownTransportSocketType) {
|
||||
Cluster cluster;
|
||||
cluster.set_name("foo");
|
||||
cluster.set_type(cluster.EDS);
|
||||
|
|
@ -827,13 +828,13 @@ TEST_F(TlsConfigTest, TransportSocketTypedConfigUnset) {
|
|||
absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(decode_result.resource.status().message(),
|
||||
"errors validating Cluster resource: ["
|
||||
"field:transport_socket.typed_config.type_url "
|
||||
"error:unrecognized transport socket type: "
|
||||
"envoy.config.cluster.v3.Cluster]")
|
||||
"field:transport_socket.typed_config.value["
|
||||
"envoy.config.cluster.v3.Cluster].type_url "
|
||||
"error:unsupported transport socket type]")
|
||||
<< decode_result.resource.status();
|
||||
}
|
||||
|
||||
TEST_F(TlsConfigTest, UnknownTransportSocketType) {
|
||||
TEST_F(TlsConfigTest, UnparseableUpstreamTlsContext) {
|
||||
Cluster cluster;
|
||||
cluster.set_name("foo");
|
||||
cluster.set_type(cluster.EDS);
|
||||
|
|
@ -859,6 +860,35 @@ TEST_F(TlsConfigTest, UnknownTransportSocketType) {
|
|||
<< decode_result.resource.status();
|
||||
}
|
||||
|
||||
TEST_F(TlsConfigTest, UpstreamTlsContextInTypedStruct) {
|
||||
Cluster cluster;
|
||||
cluster.set_name("foo");
|
||||
cluster.set_type(cluster.EDS);
|
||||
cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
|
||||
auto* transport_socket = cluster.mutable_transport_socket();
|
||||
xds::type::v3::TypedStruct typed_struct;
|
||||
typed_struct.set_type_url(
|
||||
"types.googleapis.com/"
|
||||
"envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext");
|
||||
transport_socket->mutable_typed_config()->PackFrom(typed_struct);
|
||||
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.name.has_value());
|
||||
EXPECT_EQ(*decode_result.name, "foo");
|
||||
EXPECT_EQ(decode_result.resource.status().code(),
|
||||
absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(decode_result.resource.status().message(),
|
||||
"errors validating Cluster resource: ["
|
||||
"field:transport_socket.typed_config.value["
|
||||
"xds.type.v3.TypedStruct].value["
|
||||
"envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext] "
|
||||
"error:can't decode UpstreamTlsContext]")
|
||||
<< decode_result.resource.status();
|
||||
}
|
||||
|
||||
TEST_F(TlsConfigTest, CaCertProviderUnset) {
|
||||
Cluster cluster;
|
||||
cluster.set_name("foo");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,924 @@
|
|||
//
|
||||
// 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 "src/core/ext/xds/xds_http_filters.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/any.pb.h>
|
||||
#include <google/protobuf/duration.pb.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/wrappers.pb.h>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "absl/types/variant.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "upb/upb.hpp"
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpc/support/log.h>
|
||||
|
||||
#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
|
||||
#include "src/core/ext/filters/fault_injection/service_config_parser.h"
|
||||
#include "src/core/ext/filters/rbac/rbac_filter.h"
|
||||
#include "src/core/ext/filters/rbac/rbac_service_config_parser.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/address.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/fault.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/fault_common.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/metadata.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/path.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/percent.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/range.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/rbac.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/regex.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/route.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/router.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/string.pb.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
namespace grpc_core {
|
||||
namespace testing {
|
||||
namespace {
|
||||
|
||||
using ::envoy::extensions::filters::http::fault::v3::HTTPFault;
|
||||
using ::envoy::extensions::filters::http::rbac::v3::RBAC;
|
||||
using ::envoy::extensions::filters::http::rbac::v3::RBACPerRoute;
|
||||
using ::envoy::extensions::filters::http::router::v3::Router;
|
||||
|
||||
//
|
||||
// base class for filter tests
|
||||
//
|
||||
|
||||
class XdsHttpFilterTest : public ::testing::Test {
|
||||
protected:
|
||||
XdsHttpFilterTest() {
|
||||
// Start with a clean registry for each test.
|
||||
XdsHttpFilterRegistry::Shutdown();
|
||||
XdsHttpFilterRegistry::Init();
|
||||
}
|
||||
|
||||
XdsExtension MakeXdsExtension(const google::protobuf::Message& message) {
|
||||
any_storage_.PackFrom(message);
|
||||
absl::string_view type =
|
||||
absl::StripPrefix(any_storage_.type_url(), "type.googleapis.com/");
|
||||
ValidationErrors::ScopedField field(
|
||||
&errors_, absl::StrCat("http_filter.value[", type, "]"));
|
||||
XdsExtension extension;
|
||||
extension.type = type;
|
||||
extension.value = absl::string_view(any_storage_.value());
|
||||
extension.validation_fields.push_back(std::move(field));
|
||||
return extension;
|
||||
}
|
||||
|
||||
static const XdsHttpFilterImpl* GetFilter(absl::string_view type) {
|
||||
return XdsHttpFilterRegistry::GetFilterForType(
|
||||
absl::StripPrefix(type, "type.googleapis.com/"));
|
||||
}
|
||||
|
||||
ValidationErrors errors_;
|
||||
upb::Arena arena_;
|
||||
google::protobuf::Any any_storage_;
|
||||
};
|
||||
|
||||
//
|
||||
// XdsHttpFilterRegistry tests
|
||||
//
|
||||
|
||||
using XdsHttpFilterRegistryTest = XdsHttpFilterTest;
|
||||
|
||||
TEST_F(XdsHttpFilterRegistryTest, Basic) {
|
||||
// Start with an empty registry.
|
||||
XdsHttpFilterRegistry::Shutdown();
|
||||
XdsHttpFilterRegistry::Init(/*register_builtins=*/false);
|
||||
// Returns null when a filter has not yet been registered.
|
||||
XdsExtension extension = MakeXdsExtension(Router());
|
||||
EXPECT_EQ(GetFilter(extension.type), nullptr);
|
||||
// Now register the filter.
|
||||
auto filter = std::make_unique<XdsHttpRouterFilter>();
|
||||
auto* filter_ptr = filter.get();
|
||||
XdsHttpFilterRegistry::RegisterFilter(std::move(filter));
|
||||
// And check that it is now present.
|
||||
EXPECT_EQ(GetFilter(extension.type), filter_ptr);
|
||||
}
|
||||
|
||||
using XdsHttpFilterRegistryDeathTest = XdsHttpFilterTest;
|
||||
|
||||
TEST_F(XdsHttpFilterRegistryDeathTest, DuplicateRegistryFails) {
|
||||
GTEST_FLAG_SET(death_test_style, "threadsafe");
|
||||
ASSERT_DEATH(
|
||||
// The router filter is already in the registry.
|
||||
XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<XdsHttpRouterFilter>()),
|
||||
"");
|
||||
}
|
||||
|
||||
//
|
||||
// Router filter tests
|
||||
//
|
||||
|
||||
class XdsRouterFilterTest : public XdsHttpFilterTest {
|
||||
protected:
|
||||
XdsRouterFilterTest() {
|
||||
XdsExtension extension = MakeXdsExtension(Router());
|
||||
filter_ = GetFilter(extension.type);
|
||||
GPR_ASSERT(filter_ != nullptr);
|
||||
}
|
||||
|
||||
const XdsHttpFilterImpl* filter_;
|
||||
};
|
||||
|
||||
TEST_F(XdsRouterFilterTest, Accessors) {
|
||||
EXPECT_EQ(filter_->ConfigProtoName(),
|
||||
"envoy.extensions.filters.http.router.v3.Router");
|
||||
EXPECT_EQ(filter_->OverrideConfigProtoName(), "");
|
||||
EXPECT_EQ(filter_->channel_filter(), nullptr);
|
||||
EXPECT_TRUE(filter_->IsSupportedOnClients());
|
||||
EXPECT_TRUE(filter_->IsSupportedOnServers());
|
||||
EXPECT_TRUE(filter_->IsTerminalFilter());
|
||||
}
|
||||
|
||||
TEST_F(XdsRouterFilterTest, GenerateFilterConfig) {
|
||||
XdsExtension extension = MakeXdsExtension(Router());
|
||||
auto config = filter_->GenerateFilterConfig(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config, Json()) << config->config.Dump();
|
||||
}
|
||||
|
||||
TEST_F(XdsRouterFilterTest, GenerateFilterConfigTypedStruct) {
|
||||
XdsExtension extension = MakeXdsExtension(Router());
|
||||
extension.value = Json();
|
||||
auto config = filter_->GenerateFilterConfig(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.router.v3.Router] "
|
||||
"error:could not parse router filter config]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_F(XdsRouterFilterTest, GenerateFilterConfigUnparseable) {
|
||||
XdsExtension extension = MakeXdsExtension(Router());
|
||||
std::string serialized_resource("\0", 1);
|
||||
extension.value = absl::string_view(serialized_resource);
|
||||
auto config = filter_->GenerateFilterConfig(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.router.v3.Router] "
|
||||
"error:could not parse router filter config]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_F(XdsRouterFilterTest, GenerateFilterConfigOverride) {
|
||||
XdsExtension extension = MakeXdsExtension(Router());
|
||||
auto config = filter_->GenerateFilterConfigOverride(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.router.v3.Router] "
|
||||
"error:router filter does not support config override]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
//
|
||||
// Fault injection filter tests
|
||||
//
|
||||
|
||||
class XdsFaultInjectionFilterTest : public XdsHttpFilterTest {
|
||||
protected:
|
||||
XdsFaultInjectionFilterTest() {
|
||||
XdsExtension extension = MakeXdsExtension(HTTPFault());
|
||||
filter_ = GetFilter(extension.type);
|
||||
GPR_ASSERT(filter_ != nullptr);
|
||||
}
|
||||
|
||||
const XdsHttpFilterImpl* filter_;
|
||||
};
|
||||
|
||||
TEST_F(XdsFaultInjectionFilterTest, Accessors) {
|
||||
EXPECT_EQ(filter_->ConfigProtoName(),
|
||||
"envoy.extensions.filters.http.fault.v3.HTTPFault");
|
||||
EXPECT_EQ(filter_->OverrideConfigProtoName(), "");
|
||||
EXPECT_EQ(filter_->channel_filter(), &FaultInjectionFilter::kFilter);
|
||||
EXPECT_TRUE(filter_->IsSupportedOnClients());
|
||||
EXPECT_FALSE(filter_->IsSupportedOnServers());
|
||||
EXPECT_FALSE(filter_->IsTerminalFilter());
|
||||
}
|
||||
|
||||
TEST_F(XdsFaultInjectionFilterTest, ModifyChannelArgs) {
|
||||
ChannelArgs args = filter_->ModifyChannelArgs(ChannelArgs());
|
||||
auto value = args.GetInt(GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(*value, 1);
|
||||
}
|
||||
|
||||
TEST_F(XdsFaultInjectionFilterTest, GenerateServiceConfigTopLevelConfig) {
|
||||
XdsHttpFilterImpl::FilterConfig config;
|
||||
config.config = Json::Object{{"foo", "bar"}};
|
||||
auto service_config = filter_->GenerateServiceConfig(config, nullptr);
|
||||
ASSERT_TRUE(service_config.ok()) << service_config.status();
|
||||
EXPECT_EQ(service_config->service_config_field_name, "faultInjectionPolicy");
|
||||
EXPECT_EQ(service_config->element, "{\"foo\":\"bar\"}");
|
||||
}
|
||||
|
||||
TEST_F(XdsFaultInjectionFilterTest, GenerateServiceConfigOverrideConfig) {
|
||||
XdsHttpFilterImpl::FilterConfig top_config;
|
||||
top_config.config = Json::Object{{"foo", "bar"}};
|
||||
XdsHttpFilterImpl::FilterConfig override_config;
|
||||
override_config.config = Json::Object{{"baz", "quux"}};
|
||||
auto service_config =
|
||||
filter_->GenerateServiceConfig(top_config, &override_config);
|
||||
ASSERT_TRUE(service_config.ok()) << service_config.status();
|
||||
EXPECT_EQ(service_config->service_config_field_name, "faultInjectionPolicy");
|
||||
EXPECT_EQ(service_config->element, "{\"baz\":\"quux\"}");
|
||||
}
|
||||
|
||||
// For the fault injection filter, GenerateFilterConfig() and
|
||||
// GenerateFilterConfigOverride() accept the same input, so we want to
|
||||
// run all tests for both.
|
||||
class XdsFaultInjectionFilterConfigTest
|
||||
: public XdsFaultInjectionFilterTest,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig> GenerateConfig(
|
||||
XdsExtension extension) {
|
||||
if (GetParam()) {
|
||||
return filter_->GenerateFilterConfigOverride(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
}
|
||||
return filter_->GenerateFilterConfig(std::move(extension), arena_.ptr(),
|
||||
&errors_);
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(XdsFaultFilter, XdsFaultInjectionFilterConfigTest,
|
||||
::testing::Bool());
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, EmptyConfig) {
|
||||
XdsExtension extension = MakeXdsExtension(HTTPFault());
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config, Json(Json::Object())) << config->config.Dump();
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, BasicConfig) {
|
||||
HTTPFault fault;
|
||||
auto* abort = fault.mutable_abort();
|
||||
abort->set_grpc_status(GRPC_STATUS_UNAVAILABLE);
|
||||
abort->mutable_percentage()->set_numerator(75);
|
||||
auto* delay = fault.mutable_delay();
|
||||
auto* fixed_delay = delay->mutable_fixed_delay();
|
||||
fixed_delay->set_seconds(1);
|
||||
fixed_delay->set_nanos(500000000);
|
||||
delay->mutable_percentage()->set_numerator(25);
|
||||
fault.mutable_max_active_faults()->set_value(10);
|
||||
XdsExtension extension = MakeXdsExtension(fault);
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config.Dump(),
|
||||
"{\"abortCode\":\"UNAVAILABLE\","
|
||||
"\"abortPercentageDenominator\":100,"
|
||||
"\"abortPercentageNumerator\":75,"
|
||||
"\"delay\":\"1.500000000s\","
|
||||
"\"delayPercentageDenominator\":100,"
|
||||
"\"delayPercentageNumerator\":25,"
|
||||
"\"maxFaults\":10}");
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, HttpAbortCode) {
|
||||
HTTPFault fault;
|
||||
auto* abort = fault.mutable_abort();
|
||||
abort->set_http_status(404);
|
||||
XdsExtension extension = MakeXdsExtension(fault);
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config.Dump(), "{\"abortCode\":\"UNIMPLEMENTED\"}");
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, HeaderAbortAndDelay) {
|
||||
HTTPFault fault;
|
||||
fault.mutable_abort()->mutable_header_abort();
|
||||
fault.mutable_delay()->mutable_header_delay();
|
||||
XdsExtension extension = MakeXdsExtension(fault);
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
|
||||
EXPECT_EQ(
|
||||
config->config.Dump(),
|
||||
"{\"abortCode\":\"OK\","
|
||||
"\"abortCodeHeader\":\"x-envoy-fault-abort-grpc-request\","
|
||||
"\"abortPercentageHeader\":\"x-envoy-fault-abort-percentage\","
|
||||
"\"delayHeader\":\"x-envoy-fault-delay-request\","
|
||||
"\"delayPercentageHeader\":\"x-envoy-fault-delay-request-percentage\"}");
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, InvalidGrpcStatusCode) {
|
||||
HTTPFault fault;
|
||||
fault.mutable_abort()->set_grpc_status(17);
|
||||
XdsExtension extension = MakeXdsExtension(fault);
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.fault.v3"
|
||||
".HTTPFault].abort.grpc_status "
|
||||
"error:invalid gRPC status code: 17]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, InvalidDuration) {
|
||||
HTTPFault fault;
|
||||
fault.mutable_delay()->mutable_fixed_delay()->set_seconds(315576000001);
|
||||
XdsExtension extension = MakeXdsExtension(fault);
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.fault.v3"
|
||||
".HTTPFault].delay.fixed_delay.seconds "
|
||||
"error:value must be in the range [0, 315576000000]]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, TypedStruct) {
|
||||
XdsExtension extension = MakeXdsExtension(HTTPFault());
|
||||
extension.value = Json();
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.fault.v3"
|
||||
".HTTPFault] error:could not parse fault injection filter config]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_P(XdsFaultInjectionFilterConfigTest, Unparseable) {
|
||||
XdsExtension extension = MakeXdsExtension(HTTPFault());
|
||||
std::string serialized_resource("\0", 1);
|
||||
extension.value = absl::string_view(serialized_resource);
|
||||
auto config = GenerateConfig(std::move(extension));
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.fault.v3"
|
||||
".HTTPFault] error:could not parse fault injection filter config]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
//
|
||||
// RBAC filter tests
|
||||
//
|
||||
|
||||
class XdsRbacFilterTest : public XdsHttpFilterTest {
|
||||
protected:
|
||||
XdsRbacFilterTest() {
|
||||
XdsExtension extension = MakeXdsExtension(RBAC());
|
||||
filter_ = GetFilter(extension.type);
|
||||
GPR_ASSERT(filter_ != nullptr);
|
||||
}
|
||||
|
||||
const XdsHttpFilterImpl* filter_;
|
||||
};
|
||||
|
||||
TEST_F(XdsRbacFilterTest, Accessors) {
|
||||
EXPECT_EQ(filter_->ConfigProtoName(),
|
||||
"envoy.extensions.filters.http.rbac.v3.RBAC");
|
||||
EXPECT_EQ(filter_->OverrideConfigProtoName(),
|
||||
"envoy.extensions.filters.http.rbac.v3.RBACPerRoute");
|
||||
EXPECT_EQ(filter_->channel_filter(), &RbacFilter::kFilterVtable);
|
||||
EXPECT_FALSE(filter_->IsSupportedOnClients());
|
||||
EXPECT_TRUE(filter_->IsSupportedOnServers());
|
||||
EXPECT_FALSE(filter_->IsTerminalFilter());
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, ModifyChannelArgs) {
|
||||
ChannelArgs args = filter_->ModifyChannelArgs(ChannelArgs());
|
||||
auto value = args.GetInt(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
EXPECT_EQ(*value, 1);
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, GenerateFilterConfig) {
|
||||
XdsExtension extension = MakeXdsExtension(RBAC());
|
||||
auto config = filter_->GenerateFilterConfig(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config, Json(Json::Object())) << config->config.Dump();
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, GenerateFilterConfigTypedStruct) {
|
||||
XdsExtension extension = MakeXdsExtension(RBAC());
|
||||
extension.value = Json();
|
||||
auto config = filter_->GenerateFilterConfig(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.rbac.v3.RBAC] "
|
||||
"error:could not parse HTTP RBAC filter config]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, GenerateFilterConfigUnparseable) {
|
||||
XdsExtension extension = MakeXdsExtension(RBAC());
|
||||
std::string serialized_resource("\0", 1);
|
||||
extension.value = absl::string_view(serialized_resource);
|
||||
auto config = filter_->GenerateFilterConfig(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.rbac.v3.RBAC] "
|
||||
"error:could not parse HTTP RBAC filter config]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverride) {
|
||||
XdsExtension extension = MakeXdsExtension(RBACPerRoute());
|
||||
auto config = filter_->GenerateFilterConfigOverride(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name, filter_->OverrideConfigProtoName());
|
||||
EXPECT_EQ(config->config, Json(Json::Object())) << config->config.Dump();
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverrideTypedStruct) {
|
||||
XdsExtension extension = MakeXdsExtension(RBACPerRoute());
|
||||
extension.value = Json();
|
||||
auto config = filter_->GenerateFilterConfigOverride(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.rbac.v3"
|
||||
".RBACPerRoute] error:could not parse RBACPerRoute]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverrideUnparseable) {
|
||||
XdsExtension extension = MakeXdsExtension(RBACPerRoute());
|
||||
std::string serialized_resource("\0", 1);
|
||||
extension.value = absl::string_view(serialized_resource);
|
||||
auto config = filter_->GenerateFilterConfigOverride(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
"errors validating filter config: ["
|
||||
"field:http_filter.value[envoy.extensions.filters.http.rbac.v3"
|
||||
".RBACPerRoute] error:could not parse RBACPerRoute]")
|
||||
<< status;
|
||||
}
|
||||
|
||||
// For the RBAC filter, the override config is a superset of the
|
||||
// top-level config, so we test all of the common fields as input for
|
||||
// both GenerateFilterConfig() and GenerateFilterConfigOverride().
|
||||
class XdsRbacFilterConfigTest : public XdsRbacFilterTest,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
absl::optional<XdsHttpFilterImpl::FilterConfig> GenerateConfig(RBAC rbac) {
|
||||
if (GetParam()) {
|
||||
RBACPerRoute rbac_per_route;
|
||||
*rbac_per_route.mutable_rbac() = rbac;
|
||||
XdsExtension extension = MakeXdsExtension(rbac_per_route);
|
||||
return filter_->GenerateFilterConfigOverride(std::move(extension),
|
||||
arena_.ptr(), &errors_);
|
||||
}
|
||||
XdsExtension extension = MakeXdsExtension(rbac);
|
||||
return filter_->GenerateFilterConfig(std::move(extension), arena_.ptr(),
|
||||
&errors_);
|
||||
}
|
||||
|
||||
std::string FieldPrefix() {
|
||||
return absl::StrCat("http_filter.value[",
|
||||
(GetParam() ? filter_->OverrideConfigProtoName()
|
||||
: filter_->ConfigProtoName()),
|
||||
"]", (GetParam() ? ".rbac" : ""));
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(XdsRbacFilter, XdsRbacFilterConfigTest,
|
||||
::testing::Bool());
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, EmptyConfig) {
|
||||
auto config = GenerateConfig(RBAC());
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name,
|
||||
GetParam() ? filter_->OverrideConfigProtoName()
|
||||
: filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config, Json(Json::Object())) << config->config.Dump();
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, AllPermissionTypes) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(rules->ALLOW);
|
||||
auto& policy = (*rules->mutable_policies())["policy_name"];
|
||||
// any
|
||||
policy.add_permissions()->set_any(true);
|
||||
// header exact match with invert
|
||||
auto* header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name1");
|
||||
header->set_exact_match("exact_match");
|
||||
header->set_invert_match(true);
|
||||
// header regex match
|
||||
header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name2");
|
||||
header->mutable_safe_regex_match()->set_regex("regex_match");
|
||||
// header range match
|
||||
header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name3");
|
||||
auto* range = header->mutable_range_match();
|
||||
range->set_start(1);
|
||||
range->set_end(3);
|
||||
// header present match
|
||||
header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name4");
|
||||
header->set_present_match(true);
|
||||
// header prefix match
|
||||
header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name5");
|
||||
header->set_prefix_match("prefix_match");
|
||||
// header suffix match
|
||||
header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name6");
|
||||
header->set_suffix_match("suffix_match");
|
||||
// header contains match
|
||||
header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("header_name7");
|
||||
header->set_contains_match("contains_match");
|
||||
// path exact match with ignore_case
|
||||
auto* string_matcher =
|
||||
policy.add_permissions()->mutable_url_path()->mutable_path();
|
||||
string_matcher->set_exact("exact_match");
|
||||
string_matcher->set_ignore_case(true);
|
||||
// path prefix match
|
||||
string_matcher = policy.add_permissions()->mutable_url_path()->mutable_path();
|
||||
string_matcher->set_prefix("prefix_match");
|
||||
// path suffix match
|
||||
string_matcher = policy.add_permissions()->mutable_url_path()->mutable_path();
|
||||
string_matcher->set_suffix("suffix_match");
|
||||
// path contains match
|
||||
string_matcher = policy.add_permissions()->mutable_url_path()->mutable_path();
|
||||
string_matcher->set_contains("contains_match");
|
||||
// path regex match
|
||||
string_matcher = policy.add_permissions()->mutable_url_path()->mutable_path();
|
||||
string_matcher->mutable_safe_regex()->set_regex("regex_match");
|
||||
// destination IP match with prefix len
|
||||
auto* cidr_range = policy.add_permissions()->mutable_destination_ip();
|
||||
cidr_range->set_address_prefix("127.0.0");
|
||||
cidr_range->mutable_prefix_len()->set_value(24);
|
||||
// destination IP match
|
||||
cidr_range = policy.add_permissions()->mutable_destination_ip();
|
||||
cidr_range->set_address_prefix("10.0.0");
|
||||
// destination port match
|
||||
policy.add_permissions()->set_destination_port(1234);
|
||||
// metadata match
|
||||
policy.add_permissions()->mutable_metadata();
|
||||
// metadata match with invert
|
||||
policy.add_permissions()->mutable_metadata()->set_invert(true);
|
||||
// requested server name
|
||||
string_matcher = policy.add_permissions()->mutable_requested_server_name();
|
||||
string_matcher->set_exact("exact_match");
|
||||
// not
|
||||
policy.add_permissions()->mutable_not_rule()->set_any(true);
|
||||
// and
|
||||
policy.add_permissions()->mutable_and_rules()->add_rules()->set_any(true);
|
||||
// or
|
||||
policy.add_permissions()->mutable_or_rules()->add_rules()->set_any(true);
|
||||
auto config = GenerateConfig(rbac);
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name,
|
||||
GetParam() ? filter_->OverrideConfigProtoName()
|
||||
: filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config.Dump(),
|
||||
"{\"rules\":{"
|
||||
"\"action\":0,"
|
||||
"\"policies\":{"
|
||||
"\"policy_name\":{"
|
||||
"\"permissions\":["
|
||||
// any
|
||||
"{\"any\":true},"
|
||||
// header exact match with invert
|
||||
"{\"header\":"
|
||||
"{\"exactMatch\":\"exact_match\",\"invertMatch\":true,"
|
||||
"\"name\":\"header_name1\"}},"
|
||||
// header regex match
|
||||
"{\"header\":"
|
||||
"{\"invertMatch\":false,\"name\":\"header_name2\","
|
||||
"\"safeRegexMatch\":{\"regex\":\"regex_match\"}}},"
|
||||
// header range match
|
||||
"{\"header\":"
|
||||
"{\"invertMatch\":false,\"name\":\"header_name3\","
|
||||
"\"rangeMatch\":{\"end\":3,\"start\":1}}},"
|
||||
// header present match
|
||||
"{\"header\":"
|
||||
"{\"invertMatch\":false,\"name\":\"header_name4\","
|
||||
"\"presentMatch\":true}},"
|
||||
// header prefix match
|
||||
"{\"header\":"
|
||||
"{\"invertMatch\":false,\"name\":\"header_name5\","
|
||||
"\"prefixMatch\":\"prefix_match\"}},"
|
||||
// header suffix match
|
||||
"{\"header\":"
|
||||
"{\"invertMatch\":false,\"name\":\"header_name6\","
|
||||
"\"suffixMatch\":\"suffix_match\"}},"
|
||||
// header contains match
|
||||
"{\"header\":"
|
||||
"{\"containsMatch\":\"contains_match\",\"invertMatch\":false,"
|
||||
"\"name\":\"header_name7\"}},"
|
||||
// path exact match with ignore_case
|
||||
"{\"urlPath\":{\"path\":{"
|
||||
"\"exact\":\"exact_match\",\"ignoreCase\":true}}},"
|
||||
// path prefix match
|
||||
"{\"urlPath\":{\"path\":{"
|
||||
"\"ignoreCase\":false,\"prefix\":\"prefix_match\"}}},"
|
||||
// path suffix match
|
||||
"{\"urlPath\":{\"path\":{"
|
||||
"\"ignoreCase\":false,\"suffix\":\"suffix_match\"}}},"
|
||||
// path contains match
|
||||
"{\"urlPath\":{\"path\":{"
|
||||
"\"contains\":\"contains_match\",\"ignoreCase\":false}}},"
|
||||
// path regex match
|
||||
"{\"urlPath\":{\"path\":{"
|
||||
"\"ignoreCase\":false,\"safeRegex\":{\"regex\":\"regex_match\"}}}},"
|
||||
// destination IP match with prefix len
|
||||
"{\"destinationIp\":{"
|
||||
"\"addressPrefix\":\"127.0.0\",\"prefixLen\":{\"value\":24}}},"
|
||||
// destination IP match
|
||||
"{\"destinationIp\":{\"addressPrefix\":\"10.0.0\"}},"
|
||||
// destination port match
|
||||
"{\"destinationPort\":1234},"
|
||||
// metadata match
|
||||
"{\"metadata\":{\"invert\":false}},"
|
||||
// metadata match with invert
|
||||
"{\"metadata\":{\"invert\":true}},"
|
||||
// requested server name
|
||||
"{\"requestedServerName\":{"
|
||||
"\"exact\":\"exact_match\",\"ignoreCase\":false}},"
|
||||
// not
|
||||
"{\"notRule\":{\"any\":true}},"
|
||||
// and
|
||||
"{\"andRules\":{\"rules\":[{\"any\":true}]}},"
|
||||
// or
|
||||
"{\"orRules\":{\"rules\":[{\"any\":true}]}}"
|
||||
"],"
|
||||
"\"principals\":[]"
|
||||
"}}}}");
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, AllPrincipalTypes) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(rules->ALLOW);
|
||||
auto& policy = (*rules->mutable_policies())["policy_name"];
|
||||
// any
|
||||
policy.add_principals()->set_any(true);
|
||||
// authenticated principal name
|
||||
// (not testing all possible string matchers here, since they're
|
||||
// covered in the AllPermissionTypes test above)
|
||||
auto* string_matcher = policy.add_principals()
|
||||
->mutable_authenticated()
|
||||
->mutable_principal_name();
|
||||
string_matcher->set_exact("exact_match");
|
||||
// source IP
|
||||
auto* cidr_range = policy.add_principals()->mutable_source_ip();
|
||||
cidr_range->set_address_prefix("127.0.0");
|
||||
// direct remote IP
|
||||
cidr_range = policy.add_principals()->mutable_direct_remote_ip();
|
||||
cidr_range->set_address_prefix("127.0.1");
|
||||
// remote IP
|
||||
cidr_range = policy.add_principals()->mutable_remote_ip();
|
||||
cidr_range->set_address_prefix("127.0.2");
|
||||
// header match
|
||||
// (not testing all possible header matchers here, since they're
|
||||
// covered in the AllPermissionTypes test above)
|
||||
auto* header = policy.add_principals()->mutable_header();
|
||||
header->set_name("header_name1");
|
||||
header->set_exact_match("exact_match");
|
||||
// path match
|
||||
// (not testing all possible string matchers here, since they're
|
||||
// covered in the AllPermissionTypes test above)
|
||||
string_matcher = policy.add_principals()->mutable_url_path()->mutable_path();
|
||||
string_matcher->set_exact("exact_match");
|
||||
// metadata match
|
||||
// (not testing invert here, since it's covered in the AllPermissionTypes
|
||||
// test above)
|
||||
policy.add_principals()->mutable_metadata();
|
||||
// not
|
||||
policy.add_principals()->mutable_not_id()->set_any(true);
|
||||
// and
|
||||
policy.add_principals()->mutable_and_ids()->add_ids()->set_any(true);
|
||||
// or
|
||||
policy.add_principals()->mutable_or_ids()->add_ids()->set_any(true);
|
||||
auto config = GenerateConfig(rbac);
|
||||
ASSERT_TRUE(errors_.ok()) << errors_.status("unexpected errors");
|
||||
ASSERT_TRUE(config.has_value());
|
||||
EXPECT_EQ(config->config_proto_type_name,
|
||||
GetParam() ? filter_->OverrideConfigProtoName()
|
||||
: filter_->ConfigProtoName());
|
||||
EXPECT_EQ(config->config.Dump(),
|
||||
"{\"rules\":{"
|
||||
"\"action\":0,"
|
||||
"\"policies\":{"
|
||||
"\"policy_name\":{"
|
||||
"\"permissions\":[],"
|
||||
"\"principals\":["
|
||||
// any
|
||||
"{\"any\":true},"
|
||||
// authenticated principal name
|
||||
"{\"authenticated\":{\"principalName\":{"
|
||||
"\"exact\":\"exact_match\",\"ignoreCase\":false}}},"
|
||||
// source IP
|
||||
"{\"sourceIp\":{\"addressPrefix\":\"127.0.0\"}},"
|
||||
// direct remote IP
|
||||
"{\"directRemoteIp\":{\"addressPrefix\":\"127.0.1\"}},"
|
||||
// remote IP
|
||||
"{\"remoteIp\":{\"addressPrefix\":\"127.0.2\"}},"
|
||||
// header exact match with invert
|
||||
"{\"header\":"
|
||||
"{\"exactMatch\":\"exact_match\",\"invertMatch\":false,"
|
||||
"\"name\":\"header_name1\"}},"
|
||||
// path exact match
|
||||
"{\"urlPath\":{\"path\":{"
|
||||
"\"exact\":\"exact_match\",\"ignoreCase\":false}}},"
|
||||
// metadata match
|
||||
"{\"metadata\":{\"invert\":false}},"
|
||||
// not
|
||||
"{\"notId\":{\"any\":true}},"
|
||||
// and
|
||||
"{\"andIds\":{\"ids\":[{\"any\":true}]}},"
|
||||
// or
|
||||
"{\"orIds\":{\"ids\":[{\"any\":true}]}}"
|
||||
"]"
|
||||
"}}}}");
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, InvalidFieldsInPolicy) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(rules->ALLOW);
|
||||
auto& policy = (*rules->mutable_policies())["policy_name"];
|
||||
policy.mutable_condition();
|
||||
policy.mutable_checked_condition();
|
||||
auto config = GenerateConfig(rbac);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
absl::StrCat("errors validating filter config: ["
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].checked_condition "
|
||||
"error:checked condition not supported; "
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].condition "
|
||||
"error:condition not supported]"))
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, InvalidHeaderMatchers) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(rules->ALLOW);
|
||||
auto& policy = (*rules->mutable_policies())["policy_name"];
|
||||
auto* header = policy.add_permissions()->mutable_header();
|
||||
header->set_name(":scheme");
|
||||
header->set_exact_match("exact_match");
|
||||
header = policy.add_principals()->mutable_header();
|
||||
header->set_name("grpc-foo");
|
||||
header->set_exact_match("exact_match");
|
||||
header = policy.add_principals()->mutable_header();
|
||||
header->set_name("header_name");
|
||||
auto config = GenerateConfig(rbac);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
absl::StrCat("errors validating filter config: ["
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].permissions[0].header.name "
|
||||
"error:':scheme' not allowed in header; "
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].principals[0].header.name "
|
||||
"error:'grpc-' prefixes not allowed in header; "
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].principals[1].header "
|
||||
"error:invalid route header matcher specified]"))
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, InvalidStringMatchers) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(rules->ALLOW);
|
||||
auto& policy = (*rules->mutable_policies())["policy_name"];
|
||||
policy.add_permissions()->mutable_url_path()->mutable_path();
|
||||
policy.add_principals()->mutable_url_path();
|
||||
auto config = GenerateConfig(rbac);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(
|
||||
status.message(),
|
||||
absl::StrCat("errors validating filter config: ["
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].permissions[0].url_path.path "
|
||||
"error:invalid match pattern; "
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].principals[0].url_path.path "
|
||||
"error:field not present]"))
|
||||
<< status;
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacFilterConfigTest, InvalidPermissionAndPrincipal) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(rules->ALLOW);
|
||||
auto& policy = (*rules->mutable_policies())["policy_name"];
|
||||
policy.add_permissions();
|
||||
policy.add_principals();
|
||||
auto config = GenerateConfig(rbac);
|
||||
absl::Status status = errors_.status("errors validating filter config");
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
|
||||
EXPECT_EQ(status.message(),
|
||||
absl::StrCat("errors validating filter config: ["
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].permissions[0] "
|
||||
"error:invalid rule; "
|
||||
"field:",
|
||||
FieldPrefix(),
|
||||
".rules.policies[policy_name].principals[0] "
|
||||
"error:invalid rule]"))
|
||||
<< status;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
grpc::testing::TestEnvironment env(&argc, argv);
|
||||
grpc_init();
|
||||
auto result = RUN_ALL_TESTS();
|
||||
grpc_shutdown();
|
||||
return result;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -45,15 +45,6 @@ grpc_cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "no_op_http_filter",
|
||||
testonly = True,
|
||||
hdrs = ["no_op_http_filter.h"],
|
||||
deps = [
|
||||
"//:grpc",
|
||||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "xds_end2end_test_lib",
|
||||
testonly = True,
|
||||
|
|
@ -112,7 +103,6 @@ grpc_cc_test(
|
|||
"no_windows",
|
||||
], # TODO(jtattermusch): fix test on windows
|
||||
deps = [
|
||||
":no_op_http_filter",
|
||||
":xds_end2end_test_lib",
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
|
|
@ -279,7 +269,6 @@ grpc_cc_test(
|
|||
"no_windows",
|
||||
], # TODO(jtattermusch): fix test on windows
|
||||
deps = [
|
||||
":no_op_http_filter",
|
||||
":xds_end2end_test_lib",
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
|
|
@ -360,12 +349,10 @@ grpc_cc_test(
|
|||
"no_windows",
|
||||
], # TODO(jtattermusch): fix test on windows
|
||||
deps = [
|
||||
":no_op_http_filter",
|
||||
":xds_end2end_test_lib",
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
"//:grpc++",
|
||||
"//src/proto/grpc/testing/xds/v3:fault_proto",
|
||||
"//src/proto/grpc/testing/xds/v3:router_proto",
|
||||
"//test/core/util:grpc_test_util",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2017 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 <string>
|
||||
|
||||
#include "src/core/ext/xds/xds_http_filters.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace testing {
|
||||
|
||||
// A No-op HTTP filter used for verifying parsing logic.
|
||||
class NoOpHttpFilter : public grpc_core::XdsHttpFilterImpl {
|
||||
public:
|
||||
NoOpHttpFilter(std::string name, bool supported_on_clients,
|
||||
bool supported_on_servers, bool is_terminal_filter)
|
||||
: name_(std::move(name)),
|
||||
supported_on_clients_(supported_on_clients),
|
||||
supported_on_servers_(supported_on_servers),
|
||||
is_terminal_filter_(is_terminal_filter) {}
|
||||
|
||||
void PopulateSymtab(upb_DefPool* /*symtab*/) const override {}
|
||||
|
||||
absl::StatusOr<grpc_core::XdsHttpFilterImpl::FilterConfig>
|
||||
GenerateFilterConfig(grpc_core::XdsExtension /*extension*/,
|
||||
upb_Arena* /*arena*/) const override {
|
||||
return grpc_core::XdsHttpFilterImpl::FilterConfig{name_, grpc_core::Json()};
|
||||
}
|
||||
|
||||
absl::StatusOr<grpc_core::XdsHttpFilterImpl::FilterConfig>
|
||||
GenerateFilterConfigOverride(
|
||||
grpc_core::XdsExtension /*serialized_filter_config*/,
|
||||
upb_Arena* /*arena*/) const override {
|
||||
return grpc_core::XdsHttpFilterImpl::FilterConfig{name_, grpc_core::Json()};
|
||||
}
|
||||
|
||||
const grpc_channel_filter* channel_filter() const override { return nullptr; }
|
||||
|
||||
absl::StatusOr<grpc_core::XdsHttpFilterImpl::ServiceConfigJsonEntry>
|
||||
GenerateServiceConfig(
|
||||
const FilterConfig& /*hcm_filter_config*/,
|
||||
const FilterConfig* /*filter_config_override*/) const override {
|
||||
return grpc_core::XdsHttpFilterImpl::ServiceConfigJsonEntry{name_, ""};
|
||||
}
|
||||
|
||||
bool IsSupportedOnClients() const override { return supported_on_clients_; }
|
||||
|
||||
bool IsSupportedOnServers() const override { return supported_on_servers_; }
|
||||
|
||||
bool IsTerminalFilter() const override { return is_terminal_filter_; }
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
const bool supported_on_clients_;
|
||||
const bool supported_on_servers_;
|
||||
const bool is_terminal_filter_;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
|
@ -101,7 +101,6 @@
|
|||
#include "src/proto/grpc/testing/xds/v3/tls.grpc.pb.h"
|
||||
#include "test/core/util/port.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
#include "test/cpp/end2end/xds/no_op_http_filter.h"
|
||||
#include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
|
||||
#include "test/cpp/util/test_config.h"
|
||||
#include "test/cpp/util/tls_test_utils.h"
|
||||
|
|
@ -767,183 +766,24 @@ TEST_P(XdsEnabledServerTest, ListenerDeletionIgnored) {
|
|||
CheckRpcSendOk(DEBUG_LOCATION);
|
||||
}
|
||||
|
||||
// Testing just one example of an invalid resource here.
|
||||
// Unit tests for XdsListenerResourceType have exhaustive tests for all
|
||||
// of the invalid cases.
|
||||
TEST_P(XdsEnabledServerTest, BadLdsUpdateNoApiListenerNorAddress) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
listener.clear_address();
|
||||
listener.set_name(
|
||||
absl::StrCat("grpc/server?xds.resource.listening_address=",
|
||||
ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()));
|
||||
listener.set_name(GetServerListenerName(backends_[0]->port()));
|
||||
balancer_->ads_service()->SetLdsResource(listener);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
EXPECT_EQ(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Listener has neither address nor ApiListener"));
|
||||
}
|
||||
|
||||
// TODO(roth): Re-enable the following test once
|
||||
// github.com/istio/istio/issues/38914 is resolved.
|
||||
TEST_P(XdsEnabledServerTest, DISABLED_BadLdsUpdateBothApiListenerAndAddress) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
listener.mutable_api_listener();
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Listener has both address and ApiListener"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, NacksNonZeroXffNumTrusterHops) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
HttpConnectionManager http_connection_manager =
|
||||
ServerHcmAccessor().Unpack(listener);
|
||||
http_connection_manager.set_xff_num_trusted_hops(1);
|
||||
ServerHcmAccessor().Pack(http_connection_manager, &listener);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("'xff_num_trusted_hops' must be zero"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, NacksNonEmptyOriginalIpDetectionExtensions) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
HttpConnectionManager http_connection_manager =
|
||||
ServerHcmAccessor().Unpack(listener);
|
||||
http_connection_manager.add_original_ip_detection_extensions();
|
||||
ServerHcmAccessor().Pack(http_connection_manager, &listener);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("'original_ip_detection_extensions' must be empty"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, UnsupportedL4Filter) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
listener.mutable_default_filter_chain()->clear_filters();
|
||||
listener.mutable_default_filter_chain()->add_filters()->mutable_typed_config()->PackFrom(default_listener_ /* any proto object other than HttpConnectionManager */);
|
||||
balancer_->ads_service()->SetLdsResource(
|
||||
PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("Unsupported filter type"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, NacksEmptyHttpFilterList) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
HttpConnectionManager http_connection_manager =
|
||||
ServerHcmAccessor().Unpack(listener);
|
||||
http_connection_manager.clear_http_filters();
|
||||
ServerHcmAccessor().Pack(http_connection_manager, &listener);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("Expected at least one HTTP filter"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, UnsupportedHttpFilter) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
HttpConnectionManager http_connection_manager =
|
||||
ServerHcmAccessor().Unpack(listener);
|
||||
http_connection_manager.clear_http_filters();
|
||||
auto* http_filter = http_connection_manager.add_http_filters();
|
||||
http_filter->set_name("grpc.testing.unsupported_http_filter");
|
||||
http_filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.unsupported_http_filter");
|
||||
http_filter = http_connection_manager.add_http_filters();
|
||||
http_filter->set_name("router");
|
||||
http_filter->mutable_typed_config()->PackFrom(
|
||||
envoy::extensions::filters::http::router::v3::Router());
|
||||
ServerHcmAccessor().Pack(http_connection_manager, &listener);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("no filter registered for config type "
|
||||
"grpc.testing.unsupported_http_filter"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
HttpConnectionManager http_connection_manager =
|
||||
ServerHcmAccessor().Unpack(listener);
|
||||
http_connection_manager.clear_http_filters();
|
||||
auto* http_filter = http_connection_manager.add_http_filters();
|
||||
http_filter->set_name("grpc.testing.client_only_http_filter");
|
||||
http_filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.client_only_http_filter");
|
||||
http_filter = http_connection_manager.add_http_filters();
|
||||
http_filter->set_name("router");
|
||||
http_filter->mutable_typed_config()->PackFrom(
|
||||
envoy::extensions::filters::http::router::v3::Router());
|
||||
ServerHcmAccessor().Pack(http_connection_manager, &listener);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Filter grpc.testing.client_only_http_filter is not "
|
||||
"supported on servers"));
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest,
|
||||
HttpFilterNotSupportedOnServerIgnoredWhenOptional) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
HttpConnectionManager http_connection_manager =
|
||||
ServerHcmAccessor().Unpack(listener);
|
||||
http_connection_manager.clear_http_filters();
|
||||
auto* http_filter = http_connection_manager.add_http_filters();
|
||||
http_filter->set_name("grpc.testing.client_only_http_filter");
|
||||
http_filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.client_only_http_filter");
|
||||
http_filter->set_is_optional(true);
|
||||
http_filter = http_connection_manager.add_http_filters();
|
||||
http_filter->set_name("router");
|
||||
http_filter->mutable_typed_config()->PackFrom(
|
||||
envoy::extensions::filters::http::router::v3::Router());
|
||||
ServerHcmAccessor().Pack(http_connection_manager, &listener);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
WaitForBackend(DEBUG_LOCATION, 0);
|
||||
auto response_state = balancer_->ads_service()->lds_response_state();
|
||||
ASSERT_TRUE(response_state.has_value());
|
||||
EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
|
||||
absl::StrCat(
|
||||
"xDS response validation errors: [resource index 0: ",
|
||||
GetServerListenerName(backends_[0]->port()),
|
||||
": INVALID_ARGUMENT: Listener has neither address nor ApiListener]"));
|
||||
}
|
||||
|
||||
// Verify that a mismatch of listening address results in "not serving"
|
||||
|
|
@ -963,21 +803,6 @@ TEST_P(XdsEnabledServerTest, ListenerAddressMismatch) {
|
|||
grpc::StatusCode::FAILED_PRECONDITION);
|
||||
}
|
||||
|
||||
TEST_P(XdsEnabledServerTest, UseOriginalDstNotSupported) {
|
||||
DoSetUp();
|
||||
Listener listener = default_server_listener_;
|
||||
listener.mutable_use_original_dst()->set_value(true);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Field \'use_original_dst\' is not supported."));
|
||||
}
|
||||
|
||||
class XdsServerSecurityTest : public XdsEnd2endTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
|
|
@ -1202,173 +1027,6 @@ class XdsServerSecurityTest : public XdsEnd2endTest {
|
|||
std::vector<std::string> client_authenticated_identity_;
|
||||
};
|
||||
|
||||
TEST_P(XdsServerSecurityTest, TransportSocketTypedConfigUnset) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
filter_chain->mutable_transport_socket();
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("transport socket typed config unset"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest, UnknownTransportSocket) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
auto* transport_socket = filter_chain->mutable_transport_socket();
|
||||
transport_socket->mutable_typed_config()->PackFrom(Listener());
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("Unrecognized transport socket type: "
|
||||
"envoy.config.listener.v3.Listener"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest, NacksRequireSNI) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
auto* transport_socket = filter_chain->mutable_transport_socket();
|
||||
transport_socket->set_name("envoy.transport_sockets.tls");
|
||||
DownstreamTlsContext downstream_tls_context;
|
||||
downstream_tls_context.mutable_common_tls_context()
|
||||
->mutable_tls_certificate_provider_instance()
|
||||
->set_instance_name("fake_plugin1");
|
||||
downstream_tls_context.mutable_require_sni()->set_value(true);
|
||||
transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("require_sni: unsupported"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest, NacksOcspStaplePolicyOtherThanLenientStapling) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
auto* transport_socket = filter_chain->mutable_transport_socket();
|
||||
transport_socket->set_name("envoy.transport_sockets.tls");
|
||||
DownstreamTlsContext downstream_tls_context;
|
||||
downstream_tls_context.mutable_common_tls_context()
|
||||
->mutable_tls_certificate_provider_instance()
|
||||
->set_instance_name("fake_plugin1");
|
||||
downstream_tls_context.set_ocsp_staple_policy(
|
||||
envoy::extensions::transport_sockets::tls::v3::
|
||||
DownstreamTlsContext_OcspStaplePolicy_STRICT_STAPLING);
|
||||
transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"ocsp_staple_policy: Only LENIENT_STAPLING supported"));
|
||||
}
|
||||
|
||||
TEST_P(
|
||||
XdsServerSecurityTest,
|
||||
NacksRequiringClientCertificateWithoutValidationCertificateProviderInstance) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
auto* transport_socket = filter_chain->mutable_transport_socket();
|
||||
transport_socket->set_name("envoy.transport_sockets.tls");
|
||||
DownstreamTlsContext downstream_tls_context;
|
||||
downstream_tls_context.mutable_common_tls_context()
|
||||
->mutable_tls_certificate_provider_instance()
|
||||
->set_instance_name("fake_plugin1");
|
||||
downstream_tls_context.mutable_require_client_certificate()->set_value(true);
|
||||
transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"TLS configuration requires client certificates but no "
|
||||
"certificate provider instance specified for validation."));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest,
|
||||
NacksTlsConfigurationWithoutIdentityProviderInstance) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
auto* transport_socket = filter_chain->mutable_transport_socket();
|
||||
transport_socket->set_name("envoy.transport_sockets.tls");
|
||||
DownstreamTlsContext downstream_tls_context;
|
||||
transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("TLS configuration provided but no "
|
||||
"tls_certificate_provider_instance found."));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest, NacksMatchSubjectAltNames) {
|
||||
Listener listener = default_server_listener_;
|
||||
auto* filter_chain = listener.mutable_default_filter_chain();
|
||||
auto* transport_socket = filter_chain->mutable_transport_socket();
|
||||
transport_socket->set_name("envoy.transport_sockets.tls");
|
||||
DownstreamTlsContext downstream_tls_context;
|
||||
downstream_tls_context.mutable_common_tls_context()
|
||||
->mutable_tls_certificate_provider_instance()
|
||||
->set_instance_name("fake_plugin1");
|
||||
downstream_tls_context.mutable_common_tls_context()
|
||||
->mutable_validation_context()
|
||||
->add_match_subject_alt_names()
|
||||
->set_exact("*.test.google.fr");
|
||||
transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("match_subject_alt_names not supported on servers"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest, UnknownIdentityCertificateProvider) {
|
||||
SetLdsUpdate("", "", "unknown", "", false);
|
||||
SendRpc([this]() { return CreateTlsChannel(); }, {}, {},
|
||||
true /* test_expects_failure */);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"unrecognized certificate provider instance name: unknown"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest, UnknownRootCertificateProvider) {
|
||||
g_fake1_cert_data_map->Set({{"", {root_cert_, identity_pair_}}});
|
||||
SetLdsUpdate("unknown", "", "fake_plugin1", "", false);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"unrecognized certificate provider instance name: unknown"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerSecurityTest,
|
||||
TestDeprecateTlsCertificateCertificateProviderInstanceField) {
|
||||
g_fake1_cert_data_map->Set({{"", {root_cert_, identity_pair_}}});
|
||||
|
|
@ -2130,232 +1788,6 @@ TEST_P(XdsServerFilterChainMatchTest,
|
|||
SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
// Add a duplicate filter chain
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"Duplicate matching rules detected when adding filter chain: {}"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain with prefix range
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
auto* prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(16);
|
||||
prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(24);
|
||||
// Add a filter chain with a duplicate prefix range entry
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(16);
|
||||
prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(32);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
if (ipv6_only_) {
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"Duplicate matching rules detected when adding filter chain: "
|
||||
"{prefix_ranges={{address_prefix=[::]:0, prefix_len=16}, "
|
||||
"{address_prefix=[::]:0, prefix_len=32}}}"));
|
||||
} else {
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"Duplicate matching rules detected when adding filter chain: "
|
||||
"{prefix_ranges={{address_prefix=127.0.0.0:0, prefix_len=16}, "
|
||||
"{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnTransportProtocolNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain with "raw_buffer" transport protocol
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->set_transport_protocol(
|
||||
"raw_buffer");
|
||||
// Add a duplicate filter chain with the same "raw_buffer" transport
|
||||
// protocol entry
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->set_transport_protocol(
|
||||
"raw_buffer");
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Duplicate matching rules detected when adding "
|
||||
"filter chain: {transport_protocol=raw_buffer}"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnLocalSourceTypeNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain with the local source type
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->set_source_type(
|
||||
FilterChainMatch::SAME_IP_OR_LOOPBACK);
|
||||
// Add a duplicate filter chain with the same local source type entry
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->set_source_type(
|
||||
FilterChainMatch::SAME_IP_OR_LOOPBACK);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Duplicate matching rules detected when adding "
|
||||
"filter chain: {source_type=SAME_IP_OR_LOOPBACK}"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest,
|
||||
DuplicateMatchOnExternalSourceTypeNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain with the external source type
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->set_source_type(
|
||||
FilterChainMatch::EXTERNAL);
|
||||
// Add a duplicate filter chain with the same external source type entry
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->set_source_type(
|
||||
FilterChainMatch::EXTERNAL);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Duplicate matching rules detected when adding "
|
||||
"filter chain: {source_type=EXTERNAL}"));
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest,
|
||||
DuplicateMatchOnSourcePrefixRangesNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain with source prefix range
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
auto* prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(16);
|
||||
prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(24);
|
||||
// Add a filter chain with a duplicate source prefix range entry
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(16);
|
||||
prefix_range =
|
||||
filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
|
||||
prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
|
||||
prefix_range->mutable_prefix_len()->set_value(32);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
if (ipv6_only_) {
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"Duplicate matching rules detected when adding filter chain: "
|
||||
"{source_prefix_ranges={{address_prefix=[::]:0, prefix_len=16}, "
|
||||
"{address_prefix=[::]:0, prefix_len=32}}}"));
|
||||
} else {
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"Duplicate matching rules detected when adding filter chain: "
|
||||
"{source_prefix_ranges={{address_prefix=127.0.0.0:0, "
|
||||
"prefix_len=16}, "
|
||||
"{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePortNacked) {
|
||||
Listener listener = default_server_listener_;
|
||||
// Add filter chain with the external source type
|
||||
auto* filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->add_source_ports(8080);
|
||||
// Add a duplicate filter chain with the same source port entry
|
||||
filter_chain = listener.add_filter_chains();
|
||||
filter_chain->add_filters()->mutable_typed_config()->PackFrom(
|
||||
GetHttpConnectionManager(listener));
|
||||
filter_chain->mutable_filter_chain_match()->add_source_ports(8080);
|
||||
SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
|
||||
backends_[0]->port(),
|
||||
default_server_route_config_);
|
||||
backends_[0]->Start();
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Duplicate matching rules detected when adding "
|
||||
"filter chain: {source_ports={8080}}"));
|
||||
}
|
||||
|
||||
using XdsServerRdsTest = XdsEnabledServerStatusNotificationTest;
|
||||
|
||||
TEST_P(XdsServerRdsTest, Basic) {
|
||||
|
|
@ -2608,116 +2040,6 @@ TEST_P(XdsRbacTest, LogAction) {
|
|||
SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
|
||||
}
|
||||
|
||||
using XdsRbacNackTest = XdsRbacTest;
|
||||
|
||||
TEST_P(XdsRbacNackTest, NacksSchemePrincipalHeader) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
|
||||
Policy policy;
|
||||
auto* header = policy.add_principals()->mutable_header();
|
||||
header->set_name(":scheme");
|
||||
header->set_exact_match("http");
|
||||
policy.add_permissions()->set_any(true);
|
||||
(*rules->mutable_policies())["policy"] = policy;
|
||||
SetServerRbacPolicy(rbac);
|
||||
backends_[0]->Start();
|
||||
if (GetParam().enable_rds_testing() &&
|
||||
GetParam().filter_config_setup() ==
|
||||
XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute) {
|
||||
const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("':scheme' not allowed in header"));
|
||||
} else {
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("':scheme' not allowed in header"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacNackTest, NacksGrpcPrefixedPrincipalHeaders) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
|
||||
Policy policy;
|
||||
auto* header = policy.add_principals()->mutable_header();
|
||||
header->set_name("grpc-status");
|
||||
header->set_exact_match("0");
|
||||
policy.add_permissions()->set_any(true);
|
||||
(*rules->mutable_policies())["policy"] = policy;
|
||||
SetServerRbacPolicy(rbac);
|
||||
backends_[0]->Start();
|
||||
if (GetParam().enable_rds_testing() &&
|
||||
GetParam().filter_config_setup() ==
|
||||
XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute) {
|
||||
const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
|
||||
} else {
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacNackTest, NacksSchemePermissionHeader) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
|
||||
Policy policy;
|
||||
auto* header = policy.add_permissions()->mutable_header();
|
||||
header->set_name(":scheme");
|
||||
header->set_exact_match("http");
|
||||
policy.add_principals()->set_any(true);
|
||||
(*rules->mutable_policies())["policy"] = policy;
|
||||
SetServerRbacPolicy(rbac);
|
||||
backends_[0]->Start();
|
||||
if (GetParam().enable_rds_testing() &&
|
||||
GetParam().filter_config_setup() ==
|
||||
XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute) {
|
||||
const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("':scheme' not allowed in header"));
|
||||
} else {
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("':scheme' not allowed in header"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(XdsRbacNackTest, NacksGrpcPrefixedPermissionHeaders) {
|
||||
RBAC rbac;
|
||||
auto* rules = rbac.mutable_rules();
|
||||
rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
|
||||
Policy policy;
|
||||
auto* header = policy.add_permissions()->mutable_header();
|
||||
header->set_name("grpc-status");
|
||||
header->set_exact_match("0");
|
||||
policy.add_principals()->set_any(true);
|
||||
(*rules->mutable_policies())["policy"] = policy;
|
||||
SetServerRbacPolicy(rbac);
|
||||
backends_[0]->Start();
|
||||
if (GetParam().enable_rds_testing() &&
|
||||
GetParam().filter_config_setup() ==
|
||||
XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute) {
|
||||
const auto response_state = WaitForRdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
|
||||
} else {
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
|
||||
}
|
||||
}
|
||||
|
||||
// Tests RBAC policies where a route override is always present. Action
|
||||
// permutations are not added.
|
||||
using XdsRbacTestWithRouteOverrideAlwaysPresent = XdsRbacTest;
|
||||
|
|
@ -3587,30 +2909,6 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
.set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)),
|
||||
&XdsTestType::Name);
|
||||
|
||||
// We are only testing the server here.
|
||||
// Run with bootstrap from env var, so that we use a global XdsClient
|
||||
// instance. Otherwise, we would need to use a separate fake resolver
|
||||
// result generator on the client and server sides.
|
||||
// Note that we are simply using the default fake credentials instead of xds
|
||||
// credentials for NACK tests to avoid a mismatch between the client and the
|
||||
// server's security settings when using the WaitForNack() infrastructure.
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
XdsTest, XdsRbacNackTest,
|
||||
::testing::Values(
|
||||
XdsTestType().set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar),
|
||||
XdsTestType().set_enable_rds_testing().set_bootstrap_source(
|
||||
XdsTestType::kBootstrapFromEnvVar),
|
||||
XdsTestType()
|
||||
.set_filter_config_setup(
|
||||
XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute)
|
||||
.set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar),
|
||||
XdsTestType()
|
||||
.set_enable_rds_testing()
|
||||
.set_filter_config_setup(
|
||||
XdsTestType::HttpFilterConfigLocation::kHttpFilterConfigInRoute)
|
||||
.set_bootstrap_source(XdsTestType::kBootstrapFromEnvVar)),
|
||||
&XdsTestType::Name);
|
||||
|
||||
// We are only testing the server here.
|
||||
// Run with bootstrap from env var, so that we use a global XdsClient
|
||||
// instance. Otherwise, we would need to use a separate fake resolver
|
||||
|
|
@ -3714,24 +3012,6 @@ int main(int argc, char** argv) {
|
|||
"fake2", grpc::testing::g_fake2_cert_data_map));
|
||||
});
|
||||
grpc_init();
|
||||
grpc_core::XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<grpc::testing::NoOpHttpFilter>(
|
||||
"grpc.testing.client_only_http_filter",
|
||||
/* supported_on_clients = */ true, /* supported_on_servers = */ false,
|
||||
/* is_terminal_filter */ false),
|
||||
{"grpc.testing.client_only_http_filter"});
|
||||
grpc_core::XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<grpc::testing::NoOpHttpFilter>(
|
||||
"grpc.testing.server_only_http_filter",
|
||||
/* supported_on_clients = */ false, /* supported_on_servers = */ true,
|
||||
/* is_terminal_filter */ false),
|
||||
{"grpc.testing.server_only_http_filter"});
|
||||
grpc_core::XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<grpc::testing::NoOpHttpFilter>(
|
||||
"grpc.testing.terminal_http_filter",
|
||||
/* supported_on_clients = */ true, /* supported_on_servers = */ true,
|
||||
/* is_terminal_filter */ true),
|
||||
{"grpc.testing.terminal_http_filter"});
|
||||
const auto result = RUN_ALL_TESTS();
|
||||
grpc_shutdown();
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include "src/proto/grpc/testing/xds/v3/fault.grpc.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/outlier_detection.grpc.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/router.grpc.pb.h"
|
||||
#include "test/cpp/end2end/xds/no_op_http_filter.h"
|
||||
#include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
|
||||
|
||||
namespace grpc {
|
||||
|
|
|
|||
|
|
@ -21,16 +21,13 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "src/core/ext/filters/client_channel/backup_poller.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/fault.grpc.pb.h"
|
||||
#include "src/proto/grpc/testing/xds/v3/router.grpc.pb.h"
|
||||
#include "test/cpp/end2end/xds/no_op_http_filter.h"
|
||||
#include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace testing {
|
||||
namespace {
|
||||
|
||||
using ::envoy::extensions::filters::http::fault::v3::HTTPFault;
|
||||
using std::chrono::system_clock;
|
||||
|
||||
using LdsTest = XdsEnd2endTest;
|
||||
|
|
@ -38,9 +35,10 @@ using LdsTest = XdsEnd2endTest;
|
|||
INSTANTIATE_TEST_SUITE_P(XdsTest, LdsTest, ::testing::Values(XdsTestType()),
|
||||
&XdsTestType::Name);
|
||||
|
||||
// Tests that LDS client should send a NACK if there is no API listener in the
|
||||
// Listener in the LDS response.
|
||||
TEST_P(LdsTest, NoApiListener) {
|
||||
// Testing just one example of an invalid resource here.
|
||||
// Unit tests for XdsListenerResourceType have exhaustive tests for all
|
||||
// of the invalid cases.
|
||||
TEST_P(LdsTest, NacksInvalidListener) {
|
||||
auto listener = default_listener_;
|
||||
listener.clear_api_listener();
|
||||
balancer_->ads_service()->SetLdsResource(listener);
|
||||
|
|
@ -51,382 +49,6 @@ TEST_P(LdsTest, NoApiListener) {
|
|||
::testing::HasSubstr("Listener has neither address nor ApiListener"));
|
||||
}
|
||||
|
||||
// Tests that LDS client should send a NACK if the route_specifier in the
|
||||
// http_connection_manager is neither inlined route_config nor RDS.
|
||||
TEST_P(LdsTest, WrongRouteSpecifier) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
http_connection_manager.mutable_scoped_routes();
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
balancer_->ads_service()->SetLdsResource(listener);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"HttpConnectionManager neither has inlined route_config nor RDS."));
|
||||
}
|
||||
|
||||
// Tests that LDS client should send a NACK if the rds message in the
|
||||
// http_connection_manager is missing the config_source field.
|
||||
TEST_P(LdsTest, RdsMissingConfigSource) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
http_connection_manager.mutable_rds()->set_route_config_name(
|
||||
kDefaultRouteConfigurationName);
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
balancer_->ads_service()->SetLdsResource(listener);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"HttpConnectionManager missing config_source for RDS."));
|
||||
}
|
||||
|
||||
// Tests that LDS client should send a NACK if the rds message in the
|
||||
// http_connection_manager has a config_source field that does not specify
|
||||
// ADS or SELF.
|
||||
TEST_P(LdsTest, RdsConfigSourceDoesNotSpecifyAdsOrSelf) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
auto* rds = http_connection_manager.mutable_rds();
|
||||
rds->set_route_config_name(kDefaultRouteConfigurationName);
|
||||
rds->mutable_config_source()->set_path("/foo/bar");
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
balancer_->ads_service()->SetLdsResource(listener);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("HttpConnectionManager ConfigSource for "
|
||||
"RDS does not specify ADS or SELF."));
|
||||
}
|
||||
|
||||
// Tests that LDS client accepts the rds message in the
|
||||
// http_connection_manager with a config_source field that specifies ADS.
|
||||
TEST_P(LdsTest, AcceptsRdsConfigSourceOfTypeAds) {
|
||||
CreateAndStartBackends(1);
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
auto* rds = http_connection_manager.mutable_rds();
|
||||
rds->set_route_config_name(kDefaultRouteConfigurationName);
|
||||
rds->mutable_config_source()->mutable_ads();
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
|
||||
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
|
||||
WaitForAllBackends(DEBUG_LOCATION);
|
||||
auto response_state = balancer_->ads_service()->lds_response_state();
|
||||
ASSERT_TRUE(response_state.has_value());
|
||||
EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
|
||||
}
|
||||
|
||||
// Tests that we NACK non-terminal filters at the end of the list.
|
||||
TEST_P(LdsTest, NacksNonTerminalHttpFilterAtEndOfList) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->set_name("unknown");
|
||||
filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.client_only_http_filter");
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"non-terminal filter for config type grpc.testing"
|
||||
".client_only_http_filter is the last filter in the chain"));
|
||||
}
|
||||
|
||||
// Test that we NACK terminal filters that are not at the end of the list.
|
||||
TEST_P(LdsTest, NacksTerminalFilterBeforeEndOfList) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
// The default_listener_ has a terminal router filter by default. Add an
|
||||
// additional filter.
|
||||
auto* filter = http_connection_manager.add_http_filters();
|
||||
filter->set_name("grpc.testing.terminal_http_filter");
|
||||
filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.terminal_http_filter");
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"terminal filter for config type envoy.extensions.filters.http"
|
||||
".router.v3.Router must be the last filter in the chain"));
|
||||
}
|
||||
|
||||
// Test that we NACK empty filter names.
|
||||
TEST_P(LdsTest, RejectsEmptyHttpFilterName) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->Clear();
|
||||
filter->mutable_typed_config()->PackFrom(Listener());
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("empty filter name at index 0"));
|
||||
}
|
||||
|
||||
// Test that we NACK duplicate HTTP filter names.
|
||||
TEST_P(LdsTest, RejectsDuplicateHttpFilterName) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
http_connection_manager.mutable_http_filters(0)
|
||||
->mutable_typed_config()
|
||||
->PackFrom(HTTPFault());
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("duplicate HTTP filter name: router"));
|
||||
}
|
||||
|
||||
// Test that we NACK unknown filter types.
|
||||
TEST_P(LdsTest, RejectsUnknownHttpFilterType) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->set_name("unknown");
|
||||
filter->mutable_typed_config()->PackFrom(Listener());
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("no filter registered for config type "
|
||||
"envoy.config.listener.v3.Listener"));
|
||||
}
|
||||
|
||||
// Test that we ignore optional unknown filter types.
|
||||
TEST_P(LdsTest, IgnoresOptionalUnknownHttpFilterType) {
|
||||
CreateAndStartBackends(1);
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->set_name("unknown");
|
||||
filter->mutable_typed_config()->PackFrom(Listener());
|
||||
filter->set_is_optional(true);
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
|
||||
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
|
||||
WaitForAllBackends(DEBUG_LOCATION);
|
||||
auto response_state = balancer_->ads_service()->lds_response_state();
|
||||
ASSERT_TRUE(response_state.has_value());
|
||||
EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
|
||||
}
|
||||
|
||||
// Test that we NACK filters without configs.
|
||||
TEST_P(LdsTest, RejectsHttpFilterWithoutConfig) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->Clear();
|
||||
filter->set_name("unknown");
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"no filter config specified for filter name unknown"));
|
||||
}
|
||||
|
||||
// Test that we ignore optional filters without configs.
|
||||
TEST_P(LdsTest, IgnoresOptionalHttpFilterWithoutConfig) {
|
||||
CreateAndStartBackends(1);
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->Clear();
|
||||
filter->set_name("unknown");
|
||||
filter->set_is_optional(true);
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
|
||||
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
|
||||
WaitForAllBackends(DEBUG_LOCATION);
|
||||
auto response_state = balancer_->ads_service()->lds_response_state();
|
||||
ASSERT_TRUE(response_state.has_value());
|
||||
EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
|
||||
}
|
||||
|
||||
// Test that we NACK unparseable filter configs.
|
||||
TEST_P(LdsTest, RejectsUnparseableHttpFilterType) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->set_name("unknown");
|
||||
filter->mutable_typed_config()->PackFrom(listener);
|
||||
filter->mutable_typed_config()->set_type_url(
|
||||
"type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault");
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr(
|
||||
"filter config for type "
|
||||
"envoy.extensions.filters.http.fault.v3.HTTPFault failed to parse"));
|
||||
}
|
||||
|
||||
// Test that we NACK HTTP filters unsupported on client-side.
|
||||
TEST_P(LdsTest, RejectsHttpFiltersNotSupportedOnClients) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->set_name("grpc.testing.server_only_http_filter");
|
||||
filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.server_only_http_filter");
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("Filter grpc.testing.server_only_http_filter is not "
|
||||
"supported on clients"));
|
||||
}
|
||||
|
||||
// Test that we ignore optional HTTP filters unsupported on client-side.
|
||||
TEST_P(LdsTest, IgnoresOptionalHttpFiltersNotSupportedOnClients) {
|
||||
CreateAndStartBackends(1);
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
*http_connection_manager.add_http_filters() =
|
||||
http_connection_manager.http_filters(0);
|
||||
auto* filter = http_connection_manager.mutable_http_filters(0);
|
||||
filter->set_name("grpc.testing.server_only_http_filter");
|
||||
filter->mutable_typed_config()->set_type_url(
|
||||
"custom/grpc.testing.server_only_http_filter");
|
||||
filter->set_is_optional(true);
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
|
||||
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
|
||||
WaitForAllBackends(DEBUG_LOCATION);
|
||||
auto response_state = balancer_->ads_service()->lds_response_state();
|
||||
ASSERT_TRUE(response_state.has_value());
|
||||
EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
|
||||
}
|
||||
|
||||
// Test that we NACK non-zero xff_num_trusted_hops
|
||||
TEST_P(LdsTest, RejectsNonZeroXffNumTrusterHops) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
http_connection_manager.set_xff_num_trusted_hops(1);
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(response_state->error_message,
|
||||
::testing::HasSubstr("'xff_num_trusted_hops' must be zero"));
|
||||
}
|
||||
|
||||
// Test that we NACK non-empty original_ip_detection_extensions
|
||||
TEST_P(LdsTest, RejectsNonEmptyOriginalIpDetectionExtensions) {
|
||||
auto listener = default_listener_;
|
||||
HttpConnectionManager http_connection_manager;
|
||||
listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
|
||||
&http_connection_manager);
|
||||
http_connection_manager.add_original_ip_detection_extensions();
|
||||
listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
|
||||
http_connection_manager);
|
||||
SetListenerAndRouteConfiguration(balancer_.get(), listener,
|
||||
default_route_config_);
|
||||
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
|
||||
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
|
||||
EXPECT_THAT(
|
||||
response_state->error_message,
|
||||
::testing::HasSubstr("'original_ip_detection_extensions' must be empty"));
|
||||
}
|
||||
|
||||
class LdsDeletionTest : public XdsEnd2endTest {
|
||||
protected:
|
||||
void SetUp() override {} // Individual tests call InitClient().
|
||||
|
|
@ -3126,24 +2748,6 @@ int main(int argc, char** argv) {
|
|||
grpc_core::SetEnv("grpc_cfstream", "0");
|
||||
#endif
|
||||
grpc_init();
|
||||
grpc_core::XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<grpc::testing::NoOpHttpFilter>(
|
||||
"grpc.testing.client_only_http_filter",
|
||||
/* supported_on_clients = */ true, /* supported_on_servers = */ false,
|
||||
/* is_terminal_filter */ false),
|
||||
{"grpc.testing.client_only_http_filter"});
|
||||
grpc_core::XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<grpc::testing::NoOpHttpFilter>(
|
||||
"grpc.testing.server_only_http_filter",
|
||||
/* supported_on_clients = */ false, /* supported_on_servers = */ true,
|
||||
/* is_terminal_filter */ false),
|
||||
{"grpc.testing.server_only_http_filter"});
|
||||
grpc_core::XdsHttpFilterRegistry::RegisterFilter(
|
||||
std::make_unique<grpc::testing::NoOpHttpFilter>(
|
||||
"grpc.testing.terminal_http_filter",
|
||||
/* supported_on_clients = */ true, /* supported_on_servers = */ true,
|
||||
/* is_terminal_filter */ true),
|
||||
{"grpc.testing.terminal_http_filter"});
|
||||
const auto result = RUN_ALL_TESTS();
|
||||
grpc_shutdown();
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -8313,6 +8313,30 @@
|
|||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
"ci_platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"cpu_cost": 1.0,
|
||||
"exclude_configs": [],
|
||||
"exclude_iomgrs": [],
|
||||
"flaky": false,
|
||||
"gtest": true,
|
||||
"language": "c++",
|
||||
"name": "xds_http_filters_test",
|
||||
"platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
|
|
@ -8337,6 +8361,30 @@
|
|||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
"ci_platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"cpu_cost": 1.0,
|
||||
"exclude_configs": [],
|
||||
"exclude_iomgrs": [],
|
||||
"flaky": false,
|
||||
"gtest": true,
|
||||
"language": "c++",
|
||||
"name": "xds_listener_resource_type_test",
|
||||
"platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
|
|
|
|||
Loading…
Reference in New Issue