Merge remote-tracking branch 'upstream/master'

pull/24067/head
walkerdu 4 years ago
commit ef13dcb411
  1. 2
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 2
      .github/ISSUE_TEMPLATE/cleanup_request.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 2
      .github/ISSUE_TEMPLATE/question.md
  5. 2
      .github/pull_request_template.md
  6. 6
      BUILD
  7. 6
      BUILD.gn
  8. 154
      CMakeLists.txt
  9. 4
      Makefile
  10. 59
      build_autogenerated.yaml
  11. 58
      cmake/modules/Findre2.cmake
  12. 6
      cmake/re2.cmake
  13. 2
      config.m4
  14. 2
      config.w32
  15. 2
      doc/PROTOCOL-HTTP2.md
  16. 25
      doc/server-reflection.md
  17. 8
      gRPC-C++.podspec
  18. 10
      gRPC-Core.podspec
  19. 1
      grpc.def
  20. 6
      grpc.gemspec
  21. 2
      grpc.gyp
  22. 5
      include/grpc/grpc.h
  23. 6
      package.xml
  24. 59
      src/core/ext/xds/certificate_provider_factory.h
  25. 103
      src/core/ext/xds/certificate_provider_registry.cc
  26. 57
      src/core/ext/xds/certificate_provider_registry.h
  27. 50
      src/core/ext/xds/certificate_provider_store.h
  28. 18
      src/core/lib/iomgr/exec_ctx.h
  29. 7
      src/core/lib/security/certificate_provider.h
  30. 321
      src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
  31. 214
      src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
  32. 5
      src/core/lib/security/security_connector/ssl_utils.h
  33. 7
      src/core/lib/surface/channel.h
  34. 35
      src/core/lib/surface/init.cc
  35. 4
      src/core/plugin_registry/grpc_plugin_registry.cc
  36. 1
      src/python/grpcio/grpc/_cython/BUILD.bazel
  37. 2
      src/python/grpcio/grpc_core_dependencies.py
  38. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  39. 3
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  40. 1
      templates/CMakeLists.txt.template
  41. 12
      test/core/client_channel/BUILD
  42. 90
      test/core/client_channel/certificate_provider_registry_test.cc
  43. 1
      test/core/end2end/tests/bad_ping.cc
  44. 1
      test/core/end2end/tests/ping.cc
  45. 3
      test/core/iomgr/BUILD
  46. 10
      test/core/iomgr/stranded_event_test.cc
  47. 13
      test/core/security/BUILD
  48. 968
      test/core/security/grpc_tls_certificate_distributor_test.cc
  49. 3
      test/core/surface/BUILD
  50. 102
      test/core/surface/init_test.cc
  51. 1
      test/core/surface/public_headers_must_be_c89.c
  52. 1
      test/core/transport/chttp2/too_many_pings_test.cc
  53. 19
      test/core/util/port.cc
  54. 106
      test/cpp/end2end/xds_end2end_test.cc
  55. 51
      test/cpp/util/BUILD
  56. 588
      test/cpp/util/channelz_sampler.cc
  57. 176
      test/cpp/util/channelz_sampler_test.cc
  58. 6
      tools/buildgen/extract_metadata_from_bazel_xml.py
  59. 3
      tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
  60. 6
      tools/doxygen/Doxyfile.c++.internal
  61. 6
      tools/doxygen/Doxyfile.core.internal
  62. 2
      tools/internal_ci/macos/grpc_build_artifacts.cfg
  63. 2
      tools/interop_matrix/client_matrix.py
  64. 80
      tools/run_tests/generated/tests.json
  65. 2
      tools/run_tests/helper_scripts/prep_xds.sh
  66. 2
      tools/run_tests/python_utils/start_port_server.py
  67. 29
      tools/run_tests/run_xds_tests.py

@ -2,7 +2,7 @@
name: Report a bug
about: Create a report to help us improve
labels: kind/bug, priority/P2
assignees: donnadionne
assignees: markdroth
---

@ -2,7 +2,7 @@
name: Request a cleanup
about: Suggest a cleanup in our repository
labels: kind/internal cleanup, priority/P2
assignees: donnadionne
assignees: markdroth
---

@ -2,7 +2,7 @@
name: Request a feature
about: Suggest an idea for this project
labels: kind/enhancement, priority/P2
assignees: donnadionne
assignees: markdroth
---

@ -2,7 +2,7 @@
name: Ask a question
about: Ask a question
labels: kind/question, priority/P3
assignees: donnadionne
assignees: markdroth
---

@ -8,4 +8,4 @@ If you know who should review your pull request, please remove the mentioning be
-->
@donnadionne
@markdroth

@ -1695,6 +1695,7 @@ grpc_cc_library(
grpc_cc_library(
name = "grpc_secure",
srcs = [
"src/core/ext/xds/certificate_provider_registry.cc",
"src/core/lib/http/httpcli_security_connector.cc",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/credentials/alts/alts_credentials.cc",
@ -1712,6 +1713,7 @@ grpc_cc_library(
"src/core/lib/security/credentials/oauth2/oauth2_credentials.cc",
"src/core/lib/security/credentials/plugin/plugin_credentials.cc",
"src/core/lib/security/credentials/ssl/ssl_credentials.cc",
"src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc",
"src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc",
"src/core/lib/security/credentials/tls/tls_credentials.cc",
"src/core/lib/security/security_connector/alts/alts_security_connector.cc",
@ -1734,6 +1736,9 @@ grpc_cc_library(
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
"src/core/ext/xds/certificate_provider_factory.h",
"src/core/ext/xds/certificate_provider_registry.h",
"src/core/ext/xds/certificate_provider_store.h",
"src/core/ext/xds/xds_channel_args.h",
"src/core/lib/security/certificate_provider.h",
"src/core/lib/security/context/security_context.h",
@ -1750,6 +1755,7 @@ grpc_cc_library(
"src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h",
"src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h",
"src/core/lib/security/credentials/tls/tls_credentials.h",
"src/core/lib/security/security_connector/alts/alts_security_connector.h",

@ -542,6 +542,10 @@ config("grpc_config") {
"src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h",
"src/core/ext/upb-generated/validate/validate.upb.c",
"src/core/ext/upb-generated/validate/validate.upb.h",
"src/core/ext/xds/certificate_provider_factory.h",
"src/core/ext/xds/certificate_provider_registry.cc",
"src/core/ext/xds/certificate_provider_registry.h",
"src/core/ext/xds/certificate_provider_store.h",
"src/core/ext/xds/xds_api.cc",
"src/core/ext/xds/xds_api.h",
"src/core/ext/xds/xds_bootstrap.cc",
@ -837,6 +841,8 @@ config("grpc_config") {
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.cc",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc",
"src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h",
"src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc",
"src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h",
"src/core/lib/security/credentials/tls/tls_credentials.cc",

@ -606,6 +606,7 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c httpscli_test)
endif()
add_dependencies(buildtests_c init_test)
add_dependencies(buildtests_c inproc_callback_test)
add_dependencies(buildtests_c invalid_call_argument_test)
add_dependencies(buildtests_c json_token_test)
@ -784,6 +785,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx byte_buffer_test)
add_dependencies(buildtests_cxx byte_stream_test)
add_dependencies(buildtests_cxx cancel_ares_query_test)
add_dependencies(buildtests_cxx certificate_provider_registry_test)
add_dependencies(buildtests_cxx cfstream_test)
add_dependencies(buildtests_cxx channel_arguments_test)
add_dependencies(buildtests_cxx channel_filter_test)
@ -821,6 +823,7 @@ if(gRPC_BUILD_TESTS)
endif()
add_dependencies(buildtests_cxx global_config_test)
add_dependencies(buildtests_cxx grpc_cli)
add_dependencies(buildtests_cxx grpc_tls_certificate_distributor_test)
add_dependencies(buildtests_cxx grpc_tls_credentials_options_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx grpc_tool_test)
@ -835,7 +838,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx health_service_end2end_test)
add_dependencies(buildtests_cxx http2_client)
add_dependencies(buildtests_cxx hybrid_end2end_test)
add_dependencies(buildtests_cxx init_test)
add_dependencies(buildtests_cxx initial_settings_frame_bad_client_test)
add_dependencies(buildtests_cxx interop_client)
add_dependencies(buildtests_cxx interop_server)
@ -1595,6 +1597,7 @@ add_library(grpc
src/core/ext/upb-generated/udpa/annotations/versioning.upb.c
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
src/core/ext/upb-generated/validate/validate.upb.c
src/core/ext/xds/certificate_provider_registry.cc
src/core/ext/xds/xds_api.cc
src/core/ext/xds/xds_bootstrap.cc
src/core/ext/xds/xds_client.cc
@ -1748,6 +1751,7 @@ add_library(grpc
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
src/core/lib/security/credentials/tls/tls_credentials.cc
src/core/lib/security/security_connector/alts/alts_security_connector.cc
@ -5987,6 +5991,36 @@ endif()
endif()
if(gRPC_BUILD_TESTS)
add_executable(init_test
test/core/surface/init_test.cc
)
target_include_directories(init_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_ZLIB_INCLUDE_DIR}
)
target_link_libraries(init_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
address_sorting
upb
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(inproc_callback_test
test/core/end2end/inproc_callback_test.cc
)
@ -9605,6 +9639,45 @@ target_link_libraries(cancel_ares_query_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(certificate_provider_registry_test
test/core/client_channel/certificate_provider_registry_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(certificate_provider_registry_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_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(certificate_provider_registry_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
address_sorting
upb
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
@ -11361,6 +11434,45 @@ if(gRPC_INSTALL)
)
endif()
endif()
if(gRPC_BUILD_TESTS)
add_executable(grpc_tls_certificate_distributor_test
test/core/security/grpc_tls_certificate_distributor_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(grpc_tls_certificate_distributor_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_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(grpc_tls_certificate_distributor_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
address_sorting
upb
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
@ -11868,45 +11980,6 @@ target_link_libraries(hybrid_end2end_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(init_test
test/core/surface/init_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(init_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_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(init_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
address_sorting
upb
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
@ -15624,6 +15697,7 @@ install(FILES
)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/Findc-ares.cmake
${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/Findre2.cmake
DESTINATION ${gRPC_INSTALL_CMAKEDIR}/modules
)

@ -2002,6 +2002,7 @@ LIBGRPC_SRC = \
src/core/ext/upb-generated/udpa/annotations/versioning.upb.c \
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/xds/certificate_provider_registry.cc \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_client.cc \
@ -2155,6 +2156,7 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc \
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \
src/core/lib/security/credentials/tls/tls_credentials.cc \
src/core/lib/security/security_connector/alts/alts_security_connector.cc \
@ -4586,6 +4588,7 @@ src/core/ext/upb-generated/udpa/annotations/migrate.upb.c: $(OPENSSL_DEP)
src/core/ext/upb-generated/udpa/annotations/sensitive.upb.c: $(OPENSSL_DEP)
src/core/ext/upb-generated/udpa/annotations/status.upb.c: $(OPENSSL_DEP)
src/core/ext/upb-generated/udpa/annotations/versioning.upb.c: $(OPENSSL_DEP)
src/core/ext/xds/certificate_provider_registry.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_api.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_bootstrap.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_client.cc: $(OPENSSL_DEP)
@ -4616,6 +4619,7 @@ src/core/lib/security/credentials/local/local_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/plugin/plugin_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/ssl/ssl_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/tls/tls_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/alts/alts_security_connector.cc: $(OPENSSL_DEP)

@ -534,6 +534,9 @@ libs:
- src/core/ext/upb-generated/udpa/annotations/versioning.upb.h
- src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h
- src/core/ext/upb-generated/validate/validate.upb.h
- src/core/ext/xds/certificate_provider_factory.h
- src/core/ext/xds/certificate_provider_registry.h
- src/core/ext/xds/certificate_provider_store.h
- src/core/ext/xds/xds_api.h
- src/core/ext/xds/xds_bootstrap.h
- src/core/ext/xds/xds_channel_args.h
@ -676,6 +679,7 @@ libs:
- src/core/lib/security/credentials/oauth2/oauth2_credentials.h
- src/core/lib/security/credentials/plugin/plugin_credentials.h
- src/core/lib/security/credentials/ssl/ssl_credentials.h
- src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
- src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
- src/core/lib/security/credentials/tls/tls_credentials.h
- src/core/lib/security/security_connector/alts/alts_security_connector.h
@ -939,6 +943,7 @@ libs:
- src/core/ext/upb-generated/udpa/annotations/versioning.upb.c
- src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
- src/core/ext/upb-generated/validate/validate.upb.c
- src/core/ext/xds/certificate_provider_registry.cc
- src/core/ext/xds/xds_api.cc
- src/core/ext/xds/xds_bootstrap.cc
- src/core/ext/xds/xds_client.cc
@ -1092,6 +1097,7 @@ libs:
- src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
- src/core/lib/security/credentials/plugin/plugin_credentials.cc
- src/core/lib/security/credentials/ssl/ssl_credentials.cc
- src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
- src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
- src/core/lib/security/credentials/tls/tls_credentials.cc
- src/core/lib/security/security_connector/alts/alts_security_connector.cc
@ -3573,6 +3579,19 @@ targets:
- linux
- posix
- mac
- name: init_test
build: test
language: c
headers: []
src:
- test/core/surface/init_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- address_sorting
- upb
uses_polling: false
- name: inproc_callback_test
build: test
language: c
@ -5234,6 +5253,19 @@ targets:
- gpr
- address_sorting
- upb
- name: certificate_provider_registry_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/client_channel/certificate_provider_registry_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- address_sorting
- upb
- name: cfstream_test
gtest: true
build: test
@ -5899,6 +5931,19 @@ targets:
deps:
- grpc_plugin_support
secure: false
- name: grpc_tls_certificate_distributor_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/security/grpc_tls_certificate_distributor_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- address_sorting
- upb
- name: grpc_tls_credentials_options_test
gtest: true
build: test
@ -6155,20 +6200,6 @@ targets:
- gpr
- address_sorting
- upb
- name: init_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/surface/init_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- address_sorting
- upb
uses_polling: false
- name: initial_settings_frame_bad_client_test
gtest: true
build: test

@ -0,0 +1,58 @@
# 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.
find_package(re2 QUIET CONFIG)
if(re2_FOUND)
message(STATUS "Found RE2 via CMake.")
return()
endif()
find_package(PkgConfig REQUIRED)
# TODO(junyer): Use the IMPORTED_TARGET option whenever CMake 3.6 (or newer)
# becomes the minimum required: that will take care of the add_library() and
# set_property() calls; then we can simply alias PkgConfig::RE2 as re2::re2.
# For now, we can only set INTERFACE_* properties that existed in CMake 3.5.
pkg_check_modules(RE2 QUIET re2)
if(RE2_FOUND)
set(re2_FOUND "${RE2_FOUND}")
add_library(re2::re2 INTERFACE IMPORTED)
if(RE2_INCLUDE_DIRS)
set_property(TARGET re2::re2 PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${RE2_INCLUDE_DIRS}")
endif()
if(RE2_CFLAGS_OTHER)
# Filter out the -std flag, which is handled by CMAKE_CXX_STANDARD.
# TODO(junyer): Use the FILTER option whenever CMake 3.6 (or newer)
# becomes the minimum required: that will allow this to be concise.
foreach(flag IN LISTS RE2_CFLAGS_OTHER)
if("${flag}" MATCHES "^-std=")
list(REMOVE_ITEM RE2_CFLAGS_OTHER "${flag}")
endif()
endforeach()
set_property(TARGET re2::re2 PROPERTY
INTERFACE_COMPILE_OPTIONS "${RE2_CFLAGS_OTHER}")
endif()
if(RE2_LDFLAGS)
set_property(TARGET re2::re2 PROPERTY
INTERFACE_LINK_LIBRARIES "${RE2_LDFLAGS}")
endif()
message(STATUS "Found RE2 via pkg-config.")
return()
endif()
if(re2_FIND_REQUIRED)
message(FATAL_ERROR "Failed to find RE2.")
elseif(NOT re2_FIND_QUIETLY)
message(WARNING "Failed to find RE2.")
endif()

@ -45,13 +45,9 @@ if(gRPC_RE2_PROVIDER STREQUAL "module")
set(gRPC_INSTALL FALSE)
endif()
elseif(gRPC_RE2_PROVIDER STREQUAL "package")
find_package(re2 REQUIRED CONFIG)
find_package(re2 REQUIRED)
if(TARGET re2::re2)
set(_gRPC_RE2_LIBRARIES re2::re2)
else()
set(_gRPC_RE2_LIBRARIES ${RE2_LIBRARIES})
endif()
set(_gRPC_RE2_INCLUDE_DIR ${RE2_INCLUDE_DIRS})
set(_gRPC_FIND_RE2 "if(NOT re2_FOUND)\n find_package(re2)\nendif()")
endif()

@ -223,6 +223,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/upb-generated/udpa/annotations/versioning.upb.c \
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/xds/certificate_provider_registry.cc \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_client.cc \
@ -417,6 +418,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc \
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \
src/core/lib/security/credentials/tls/tls_credentials.cc \
src/core/lib/security/security_connector/alts/alts_security_connector.cc \

@ -190,6 +190,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\upb-generated\\udpa\\annotations\\versioning.upb.c " +
"src\\core\\ext\\upb-generated\\udpa\\data\\orca\\v1\\orca_load_report.upb.c " +
"src\\core\\ext\\upb-generated\\validate\\validate.upb.c " +
"src\\core\\ext\\xds\\certificate_provider_registry.cc " +
"src\\core\\ext\\xds\\xds_api.cc " +
"src\\core\\ext\\xds\\xds_bootstrap.cc " +
"src\\core\\ext\\xds\\xds_client.cc " +
@ -384,6 +385,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\oauth2\\oauth2_credentials.cc " +
"src\\core\\lib\\security\\credentials\\plugin\\plugin_credentials.cc " +
"src\\core\\lib\\security\\credentials\\ssl\\ssl_credentials.cc " +
"src\\core\\lib\\security\\credentials\\tls\\grpc_tls_certificate_distributor.cc " +
"src\\core\\lib\\security\\credentials\\tls\\grpc_tls_credentials_options.cc " +
"src\\core\\lib\\security\\credentials\\tls\\tls_credentials.cc " +
"src\\core\\lib\\security\\security_connector\\alts\\alts_security_connector.cc " +

@ -215,7 +215,7 @@ The following mapping from RST_STREAM error codes to GRPC error codes is applied
HTTP2 Code|GRPC Code
----------|-----------
NO_ERROR(0)|INTERNAL - An explicit GRPC status of OK should have been sent but this might be used to aggressively lameduck in some scenarios.
NO_ERROR(0)|INTERNAL - An explicit GRPC status of OK should have been sent but this might be used to aggressively [lameduck](https://landing.google.com/sre/sre-book/chapters/load-balancing-datacenter/#identifying-bad-tasks-flow-control-and-lame-ducks-bEs0uy) in some scenarios.
PROTOCOL_ERROR(1)|INTERNAL
INTERNAL_ERROR(2)|INTERNAL
FLOW_CONTROL_ERROR(3)|INTERNAL

@ -23,29 +23,8 @@ We want to be able to answer the following queries:
Specifically, what are the names of the methods, are those methods unary or
streaming, and what are the types of the argument and result?
```
#TODO(dklempner): link to an actual .proto later.
package grpc.reflection.v1alpha;
message ListApisRequest {
}
message ListApisResponse {
repeated google.protobuf.Api apis = 1;
}
message GetMethodRequest {
string method = 1;
}
message GetMethodResponse {
google.protobuf.Method method = 1;
}
service ServerReflection {
rpc ListApis (ListApisRequest) returns (ListApisResponse);
rpc GetMethod (GetMethodRequest) returns (GetMethodResponse);
}
```
The first proposed version of the protocol is here:
https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto
Note that a server is under no obligation to return a complete list of all
methods it supports. For example, a reverse proxy may support server reflection

@ -367,6 +367,9 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
'src/core/ext/upb-generated/validate/validate.upb.h',
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_channel_args.h',
@ -537,6 +540,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h',
'src/core/lib/security/credentials/tls/tls_credentials.h',
'src/core/lib/security/security_connector/alts/alts_security_connector.h',
@ -866,6 +870,9 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
'src/core/ext/upb-generated/validate/validate.upb.h',
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_channel_args.h',
@ -1036,6 +1043,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h',
'src/core/lib/security/credentials/tls/tls_credentials.h',
'src/core/lib/security/security_connector/alts/alts_security_connector.h',

@ -528,6 +528,10 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
'src/core/ext/upb-generated/validate/validate.upb.c',
'src/core/ext/upb-generated/validate/validate.upb.h',
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.cc',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.cc',
@ -892,6 +896,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h',
'src/core/lib/security/credentials/tls/tls_credentials.cc',
@ -1278,6 +1284,9 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
'src/core/ext/upb-generated/validate/validate.upb.h',
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_channel_args.h',
@ -1448,6 +1457,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h',
'src/core/lib/security/credentials/tls/tls_credentials.h',
'src/core/lib/security/security_connector/alts/alts_security_connector.h',

@ -35,7 +35,6 @@ EXPORTS
grpc_channel_watch_connectivity_state
grpc_channel_support_connectivity_watcher
grpc_channel_create_call
grpc_channel_ping
grpc_channel_register_call
grpc_channel_create_registered_call
grpc_call_arena_alloc

@ -446,6 +446,10 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h )
s.files += %w( src/core/ext/upb-generated/validate/validate.upb.c )
s.files += %w( src/core/ext/upb-generated/validate/validate.upb.h )
s.files += %w( src/core/ext/xds/certificate_provider_factory.h )
s.files += %w( src/core/ext/xds/certificate_provider_registry.cc )
s.files += %w( src/core/ext/xds/certificate_provider_registry.h )
s.files += %w( src/core/ext/xds/certificate_provider_store.h )
s.files += %w( src/core/ext/xds/xds_api.cc )
s.files += %w( src/core/ext/xds/xds_api.h )
s.files += %w( src/core/ext/xds/xds_bootstrap.cc )
@ -810,6 +814,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.cc )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
s.files += %w( src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc )
s.files += %w( src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h )
s.files += %w( src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc )
s.files += %w( src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h )
s.files += %w( src/core/lib/security/credentials/tls/tls_credentials.cc )

@ -628,6 +628,7 @@
'src/core/ext/upb-generated/udpa/annotations/versioning.upb.c',
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
'src/core/ext/upb-generated/validate/validate.upb.c',
'src/core/ext/xds/certificate_provider_registry.cc',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_client.cc',
@ -781,6 +782,7 @@
'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc',
'src/core/lib/security/credentials/tls/tls_credentials.cc',
'src/core/lib/security/security_connector/alts/alts_security_connector.cc',

@ -219,11 +219,6 @@ GRPCAPI grpc_call* grpc_channel_create_call(
grpc_completion_queue* completion_queue, grpc_slice method,
const grpc_slice* host, gpr_timespec deadline, void* reserved);
/** Ping the channels peer (load balanced channels will select one sub-channel
to ping); if the channel is not connected, posts a failed. */
GRPCAPI void grpc_channel_ping(grpc_channel* channel, grpc_completion_queue* cq,
void* tag, void* reserved);
/** Pre-register a method/host pair on a channel.
method and host are not owned and must remain alive while the channel is
alive. */

@ -426,6 +426,10 @@
<file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/validate/validate.upb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/validate/validate.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_store.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_bootstrap.cc" role="src" />
@ -790,6 +794,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/tls/tls_credentials.cc" role="src" />

@ -0,0 +1,59 @@
//
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#ifndef GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_FACTORY_H
#define GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_FACTORY_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/security/certificate_provider.h"
namespace grpc_core {
// Factories for plugins. Each plugin implementation should create its own
// factory implementation and register an instance with the registry.
class CertificateProviderFactory {
public:
// Interface for configs for CertificateProviders.
class Config {
public:
virtual ~Config() = default;
// Name of the type of the CertificateProvider. Unique to each type of
// config.
virtual const char* name() const = 0;
};
virtual ~CertificateProviderFactory() = default;
// Name of the plugin.
virtual const char* name() const = 0;
virtual std::unique_ptr<Config> CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) = 0;
// Create a CertificateProvider instance from config.
virtual RefCountedPtr<grpc_tls_certificate_provider>
CreateCertificateProvider(std::unique_ptr<Config> config) = 0;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_FACTORY_H

@ -0,0 +1,103 @@
//
//
// Copyright 2020 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 <grpc/support/port_platform.h>
#include "absl/container/inlined_vector.h"
#include "src/core/ext/xds/certificate_provider_registry.h"
namespace grpc_core {
namespace {
class RegistryState {
public:
void RegisterCertificateProviderFactory(
std::unique_ptr<CertificateProviderFactory> factory) {
gpr_log(GPR_DEBUG, "registering certificate provider factory for \"%s\"",
factory->name());
for (size_t i = 0; i < factories_.size(); ++i) {
GPR_ASSERT(strcmp(factories_[i]->name(), factory->name()) != 0);
}
factories_.push_back(std::move(factory));
}
CertificateProviderFactory* LookupCertificateProviderFactory(
absl::string_view name) const {
for (size_t i = 0; i < factories_.size(); ++i) {
if (name == factories_[i]->name()) {
return factories_[i].get();
}
}
return nullptr;
}
private:
// We currently support 3 factories without doing additional
// allocation. This number could be raised if there is a case where
// more factories are needed and the additional allocations are
// hurting performance (which is unlikely, since these allocations
// only occur at gRPC initialization time).
absl::InlinedVector<std::unique_ptr<CertificateProviderFactory>, 3>
factories_;
};
static RegistryState* g_state = nullptr;
} // namespace
//
// CertificateProviderRegistry
//
CertificateProviderFactory*
CertificateProviderRegistry::LookupCertificateProviderFactory(
absl::string_view name) {
GPR_ASSERT(g_state != nullptr);
return g_state->LookupCertificateProviderFactory(name);
}
void CertificateProviderRegistry::InitRegistry() {
if (g_state == nullptr) g_state = new RegistryState();
}
void CertificateProviderRegistry::ShutdownRegistry() {
delete g_state;
g_state = nullptr;
}
void CertificateProviderRegistry::RegisterCertificateProviderFactory(
std::unique_ptr<CertificateProviderFactory> factory) {
InitRegistry();
g_state->RegisterCertificateProviderFactory(std::move(factory));
}
} // namespace grpc_core
//
// Plugin registration
//
void grpc_certificate_provider_registry_init() {
grpc_core::CertificateProviderRegistry::InitRegistry();
}
void grpc_certificate_provider_registry_shutdown() {
grpc_core::CertificateProviderRegistry::ShutdownRegistry();
}

@ -0,0 +1,57 @@
//
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#ifndef GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_REGISTRY_H
#define GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_REGISTRY_H
#include <grpc/support/port_platform.h>
#include <string>
#include "src/core/ext/xds/certificate_provider_factory.h"
namespace grpc_core {
// Global registry for all the certificate provider plugins.
class CertificateProviderRegistry {
public:
// Returns the factory for the plugin keyed by name.
static CertificateProviderFactory* LookupCertificateProviderFactory(
absl::string_view name);
// The following methods are used to create and populate the
// CertificateProviderRegistry. NOT THREAD SAFE -- to be used only during
// global gRPC initialization and shutdown.
// Global initialization of the registry.
static void InitRegistry();
// Global shutdown of the registry.
static void ShutdownRegistry();
// Register a provider with the registry. Can only be called after calling
// InitRegistry(). The key of the factory is extracted from factory
// parameter with method CertificateProviderFactory::name. If the same key
// is registered twice, an exception is raised.
static void RegisterCertificateProviderFactory(
std::unique_ptr<CertificateProviderFactory> factory);
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_REGISTRY_H

@ -0,0 +1,50 @@
//
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#ifndef GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_STORE_H
#define GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_STORE_H
#include <grpc/support/port_platform.h>
#include <map>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/security/certificate_provider.h"
namespace grpc_core {
// Map for xDS based grpc_tls_certificate_provider instances.
class CertificateProviderStore {
public:
// If a provider corresponding to the config is found, a raw pointer to the
// grpc_tls_certificate_provider in the map is returned. If no provider is
// found for a key, a new provider is created. The CertificateProviderStore
// maintains a ref to the grpc_tls_certificate_provider for its entire
// lifetime.
RefCountedPtr<grpc_tls_certificate_provider> CreateOrGetCertificateProvider(
absl::string_view key);
private:
// Underlying map for the providers.
std::map<std::string, RefCountedPtr<grpc_tls_certificate_provider>> map_;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_CERTIFICATE_PROVIDER_STORE_H

@ -331,15 +331,9 @@ class ApplicationCallbackExecCtx {
}
}
uintptr_t Flags() { return flags_; }
static ApplicationCallbackExecCtx* Get() {
return reinterpret_cast<ApplicationCallbackExecCtx*>(
gpr_tls_get(&callback_exec_ctx_));
}
static void Set(ApplicationCallbackExecCtx* exec_ctx, uintptr_t flags) {
if (Get() == nullptr) {
if (reinterpret_cast<ApplicationCallbackExecCtx*>(
gpr_tls_get(&callback_exec_ctx_)) == nullptr) {
if (!(GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD & flags)) {
grpc_core::Fork::IncExecCtxCount();
}
@ -352,7 +346,8 @@ class ApplicationCallbackExecCtx {
functor->internal_success = is_success;
functor->internal_next = nullptr;
ApplicationCallbackExecCtx* ctx = Get();
auto* ctx = reinterpret_cast<ApplicationCallbackExecCtx*>(
gpr_tls_get(&callback_exec_ctx_));
if (ctx->head_ == nullptr) {
ctx->head_ = functor;
@ -369,7 +364,10 @@ class ApplicationCallbackExecCtx {
/** Global shutdown for ApplicationCallbackExecCtx. Called by init. */
static void GlobalShutdown(void) { gpr_tls_destroy(&callback_exec_ctx_); }
static bool Available() { return Get() != nullptr; }
static bool Available() {
return reinterpret_cast<ApplicationCallbackExecCtx*>(
gpr_tls_get(&callback_exec_ctx_)) != nullptr;
}
private:
uintptr_t flags_{0u};

@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset_set.h"
@ -38,7 +39,7 @@ struct grpc_tls_certificate_distributor;
// contexts become valid or changed, a grpc_tls_certificate_provider should
// notify its distributor so as to propagate the update to the watchers.
struct grpc_tls_certificate_provider
: public RefCounted<grpc_tls_certificate_provider> {
: public grpc_core::RefCounted<grpc_tls_certificate_provider> {
public:
grpc_tls_certificate_provider()
: interested_parties_(grpc_pollset_set_create()) {}
@ -49,8 +50,8 @@ struct grpc_tls_certificate_provider
grpc_pollset_set* interested_parties() const { return interested_parties_; }
virtual RefCountedPtr<grpc_tls_certificate_distributor> distributor()
const = 0;
virtual grpc_core::RefCountedPtr<grpc_tls_certificate_distributor>
distributor() const = 0;
private:
grpc_pollset_set* interested_parties_;

@ -0,0 +1,321 @@
//
// Copyright 2020 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 <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <stdlib.h>
#include <string.h>
void grpc_tls_certificate_distributor::SetKeyMaterials(
const std::string& cert_name, absl::optional<std::string> pem_root_certs,
absl::optional<PemKeyCertPairList> pem_key_cert_pairs) {
GPR_ASSERT(pem_root_certs.has_value() || pem_key_cert_pairs.has_value());
grpc_core::MutexLock lock(&mu_);
auto& cert_info = certificate_info_map_[cert_name];
if (pem_root_certs.has_value()) {
// Successful credential updates will clear any pre-existing error.
cert_info.SetRootError(GRPC_ERROR_NONE);
for (auto* watcher_ptr : cert_info.root_cert_watchers) {
GPR_ASSERT(watcher_ptr != nullptr);
const auto watcher_it = watchers_.find(watcher_ptr);
GPR_ASSERT(watcher_it != watchers_.end());
GPR_ASSERT(watcher_it->second.root_cert_name.has_value());
absl::optional<PemKeyCertPairList> pem_key_cert_pairs_to_report;
if (pem_key_cert_pairs.has_value() &&
watcher_it->second.identity_cert_name == cert_name) {
pem_key_cert_pairs_to_report = pem_key_cert_pairs;
} else if (watcher_it->second.identity_cert_name.has_value()) {
auto& identity_cert_info =
certificate_info_map_[*watcher_it->second.identity_cert_name];
pem_key_cert_pairs_to_report = identity_cert_info.pem_key_cert_pairs;
}
watcher_ptr->OnCertificatesChanged(
pem_root_certs, std::move(pem_key_cert_pairs_to_report));
}
cert_info.pem_root_certs = std::move(*pem_root_certs);
}
if (pem_key_cert_pairs.has_value()) {
// Successful credential updates will clear any pre-existing error.
cert_info.SetIdentityError(GRPC_ERROR_NONE);
for (const auto watcher_ptr : cert_info.identity_cert_watchers) {
GPR_ASSERT(watcher_ptr != nullptr);
const auto watcher_it = watchers_.find(watcher_ptr);
GPR_ASSERT(watcher_it != watchers_.end());
GPR_ASSERT(watcher_it->second.identity_cert_name.has_value());
absl::optional<absl::string_view> pem_root_certs_to_report;
if (pem_root_certs.has_value() &&
watcher_it->second.root_cert_name == cert_name) {
// In this case, We've already sent the credential updates at the time
// when checking pem_root_certs, so we will skip here.
continue;
} else if (watcher_it->second.root_cert_name.has_value()) {
auto& root_cert_info =
certificate_info_map_[*watcher_it->second.root_cert_name];
pem_root_certs_to_report = root_cert_info.pem_root_certs;
}
watcher_ptr->OnCertificatesChanged(pem_root_certs_to_report,
pem_key_cert_pairs);
}
cert_info.pem_key_cert_pairs = std::move(*pem_key_cert_pairs);
}
}
bool grpc_tls_certificate_distributor::HasRootCerts(
const std::string& root_cert_name) {
grpc_core::MutexLock lock(&mu_);
const auto it = certificate_info_map_.find(root_cert_name);
return it != certificate_info_map_.end() &&
!it->second.pem_root_certs.empty();
};
bool grpc_tls_certificate_distributor::HasKeyCertPairs(
const std::string& identity_cert_name) {
grpc_core::MutexLock lock(&mu_);
const auto it = certificate_info_map_.find(identity_cert_name);
return it != certificate_info_map_.end() &&
!it->second.pem_key_cert_pairs.empty();
};
void grpc_tls_certificate_distributor::SetErrorForCert(
const std::string& cert_name, absl::optional<grpc_error*> root_cert_error,
absl::optional<grpc_error*> identity_cert_error) {
GPR_ASSERT(root_cert_error.has_value() || identity_cert_error.has_value());
grpc_core::MutexLock lock(&mu_);
CertificateInfo& cert_info = certificate_info_map_[cert_name];
if (root_cert_error.has_value()) {
for (auto* watcher_ptr : cert_info.root_cert_watchers) {
GPR_ASSERT(watcher_ptr != nullptr);
const auto watcher_it = watchers_.find(watcher_ptr);
GPR_ASSERT(watcher_it != watchers_.end());
// identity_cert_error_to_report is the error of the identity cert this
// watcher is watching, if there is any.
grpc_error* identity_cert_error_to_report = GRPC_ERROR_NONE;
if (identity_cert_error.has_value() &&
watcher_it->second.identity_cert_name == cert_name) {
identity_cert_error_to_report = *identity_cert_error;
} else if (watcher_it->second.identity_cert_name.has_value()) {
auto& identity_cert_info =
certificate_info_map_[*watcher_it->second.identity_cert_name];
identity_cert_error_to_report = identity_cert_info.identity_cert_error;
}
watcher_ptr->OnError(GRPC_ERROR_REF(*root_cert_error),
GRPC_ERROR_REF(identity_cert_error_to_report));
}
cert_info.SetRootError(*root_cert_error);
}
if (identity_cert_error.has_value()) {
for (auto* watcher_ptr : cert_info.identity_cert_watchers) {
GPR_ASSERT(watcher_ptr != nullptr);
const auto watcher_it = watchers_.find(watcher_ptr);
GPR_ASSERT(watcher_it != watchers_.end());
// root_cert_error_to_report is the error of the root cert this watcher is
// watching, if there is any.
grpc_error* root_cert_error_to_report = GRPC_ERROR_NONE;
if (root_cert_error.has_value() &&
watcher_it->second.root_cert_name == cert_name) {
// In this case, We've already sent the error updates at the time when
// checking root_cert_error, so we will skip here.
continue;
} else if (watcher_it->second.root_cert_name.has_value()) {
auto& root_cert_info =
certificate_info_map_[*watcher_it->second.root_cert_name];
root_cert_error_to_report = root_cert_info.root_cert_error;
}
watcher_ptr->OnError(GRPC_ERROR_REF(root_cert_error_to_report),
GRPC_ERROR_REF(*identity_cert_error));
}
cert_info.SetIdentityError(*identity_cert_error);
}
};
void grpc_tls_certificate_distributor::SetError(grpc_error* error) {
GPR_ASSERT(error != GRPC_ERROR_NONE);
grpc_core::MutexLock lock(&mu_);
for (const auto& watcher : watchers_) {
const auto watcher_ptr = watcher.first;
GPR_ASSERT(watcher_ptr != nullptr);
const auto& watcher_info = watcher.second;
watcher_ptr->OnError(
watcher_info.root_cert_name.has_value() ? GRPC_ERROR_REF(error)
: GRPC_ERROR_NONE,
watcher_info.identity_cert_name.has_value() ? GRPC_ERROR_REF(error)
: GRPC_ERROR_NONE);
}
for (auto& cert_info_entry : certificate_info_map_) {
auto& cert_info = cert_info_entry.second;
cert_info.SetRootError(GRPC_ERROR_REF(error));
cert_info.SetIdentityError(GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
};
void grpc_tls_certificate_distributor::WatchTlsCertificates(
std::unique_ptr<TlsCertificatesWatcherInterface> watcher,
absl::optional<std::string> root_cert_name,
absl::optional<std::string> identity_cert_name) {
bool start_watching_root_cert = false;
bool already_watching_identity_for_root_cert = false;
bool start_watching_identity_cert = false;
bool already_watching_root_for_identity_cert = false;
GPR_ASSERT(root_cert_name.has_value() || identity_cert_name.has_value());
TlsCertificatesWatcherInterface* watcher_ptr = watcher.get();
GPR_ASSERT(watcher_ptr != nullptr);
// Update watchers_ and certificate_info_map_.
{
grpc_core::MutexLock lock(&mu_);
const auto watcher_it = watchers_.find(watcher_ptr);
// The caller needs to cancel the watcher first if it wants to re-register
// the watcher.
GPR_ASSERT(watcher_it == watchers_.end());
watchers_[watcher_ptr] = {std::move(watcher), root_cert_name,
identity_cert_name};
absl::optional<absl::string_view> updated_root_certs;
absl::optional<PemKeyCertPairList> updated_identity_pairs;
grpc_error* root_error = GRPC_ERROR_NONE;
grpc_error* identity_error = GRPC_ERROR_NONE;
if (root_cert_name.has_value()) {
CertificateInfo& cert_info = certificate_info_map_[*root_cert_name];
start_watching_root_cert = cert_info.root_cert_watchers.empty();
already_watching_identity_for_root_cert =
!cert_info.identity_cert_watchers.empty();
cert_info.root_cert_watchers.insert(watcher_ptr);
root_error = GRPC_ERROR_REF(cert_info.root_cert_error);
// Empty credentials will be treated as no updates.
if (!cert_info.pem_root_certs.empty()) {
updated_root_certs = cert_info.pem_root_certs;
}
}
if (identity_cert_name.has_value()) {
CertificateInfo& cert_info = certificate_info_map_[*identity_cert_name];
start_watching_identity_cert = cert_info.identity_cert_watchers.empty();
already_watching_root_for_identity_cert =
!cert_info.root_cert_watchers.empty();
cert_info.identity_cert_watchers.insert(watcher_ptr);
identity_error = GRPC_ERROR_REF(cert_info.identity_cert_error);
// Empty credentials will be treated as no updates.
if (!cert_info.pem_key_cert_pairs.empty()) {
updated_identity_pairs = cert_info.pem_key_cert_pairs;
}
}
// Notify this watcher if the certs it is watching already had some
// contents. Note that an *_cert_error in cert_info only indicates error
// occurred while trying to fetch the latest cert, but the updated_*_certs
// should always be valid. So we will send the updates regardless of
// *_cert_error.
if (updated_root_certs.has_value() || updated_identity_pairs.has_value()) {
watcher_ptr->OnCertificatesChanged(updated_root_certs,
std::move(updated_identity_pairs));
}
// Notify this watcher if the certs it is watching already had some errors.
if (root_error != GRPC_ERROR_NONE || identity_error != GRPC_ERROR_NONE) {
watcher_ptr->OnError(GRPC_ERROR_REF(root_error),
GRPC_ERROR_REF(identity_error));
}
GRPC_ERROR_UNREF(root_error);
GRPC_ERROR_UNREF(identity_error);
}
// Invoke watch status callback if needed.
{
grpc_core::MutexLock lock(&callback_mu_);
if (watch_status_callback_ != nullptr) {
if (root_cert_name == identity_cert_name &&
(start_watching_root_cert || start_watching_identity_cert)) {
watch_status_callback_(*root_cert_name, start_watching_root_cert,
start_watching_identity_cert);
} else {
if (start_watching_root_cert) {
watch_status_callback_(*root_cert_name, true,
already_watching_identity_for_root_cert);
}
if (start_watching_identity_cert) {
watch_status_callback_(*identity_cert_name,
already_watching_root_for_identity_cert, true);
}
}
}
}
};
void grpc_tls_certificate_distributor::CancelTlsCertificatesWatch(
TlsCertificatesWatcherInterface* watcher) {
absl::optional<std::string> root_cert_name;
absl::optional<std::string> identity_cert_name;
bool stop_watching_root_cert = false;
bool already_watching_identity_for_root_cert = false;
bool stop_watching_identity_cert = false;
bool already_watching_root_for_identity_cert = false;
// Update watchers_ and certificate_info_map_.
{
grpc_core::MutexLock lock(&mu_);
auto it = watchers_.find(watcher);
if (it == watchers_.end()) return;
WatcherInfo& watcher_info = it->second;
root_cert_name = std::move(watcher_info.root_cert_name);
identity_cert_name = std::move(watcher_info.identity_cert_name);
watchers_.erase(it);
if (root_cert_name.has_value()) {
auto it = certificate_info_map_.find(*root_cert_name);
GPR_ASSERT(it != certificate_info_map_.end());
CertificateInfo& cert_info = it->second;
cert_info.root_cert_watchers.erase(watcher);
stop_watching_root_cert = cert_info.root_cert_watchers.empty();
already_watching_identity_for_root_cert =
!cert_info.identity_cert_watchers.empty();
if (stop_watching_root_cert && !already_watching_identity_for_root_cert) {
certificate_info_map_.erase(it);
}
}
if (identity_cert_name.has_value()) {
auto it = certificate_info_map_.find(*identity_cert_name);
GPR_ASSERT(it != certificate_info_map_.end());
CertificateInfo& cert_info = it->second;
cert_info.identity_cert_watchers.erase(watcher);
stop_watching_identity_cert = cert_info.identity_cert_watchers.empty();
already_watching_root_for_identity_cert =
!cert_info.root_cert_watchers.empty();
if (stop_watching_identity_cert &&
!already_watching_root_for_identity_cert) {
certificate_info_map_.erase(it);
}
}
}
// Invoke watch status callback if needed.
{
grpc_core::MutexLock lock(&callback_mu_);
if (watch_status_callback_ != nullptr) {
if (root_cert_name == identity_cert_name &&
(stop_watching_root_cert || stop_watching_identity_cert)) {
watch_status_callback_(*root_cert_name, !stop_watching_root_cert,
!stop_watching_identity_cert);
} else {
if (stop_watching_root_cert) {
watch_status_callback_(*root_cert_name, false,
already_watching_identity_for_root_cert);
}
if (stop_watching_identity_cert) {
watch_status_callback_(*identity_cert_name,
already_watching_root_for_identity_cert,
false);
}
}
}
}
};

@ -0,0 +1,214 @@
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CERTIFICATE_DISTRIBUTOR_H
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CERTIFICATE_DISTRIBUTOR_H
#include <grpc/support/port_platform.h>
#include <grpc/grpc_security.h>
#include "absl/container/inlined_vector.h"
#include "absl/types/optional.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
// TLS certificate distributor.
struct grpc_tls_certificate_distributor
: public grpc_core::RefCounted<grpc_tls_certificate_distributor> {
public:
typedef absl::InlinedVector<grpc_core::PemKeyCertPair, 1> PemKeyCertPairList;
// Interface for watching TLS certificates update.
class TlsCertificatesWatcherInterface {
public:
virtual ~TlsCertificatesWatcherInterface() = default;
// Handles the delivery of the updated root and identity certificates.
// An absl::nullopt value indicates no corresponding contents for
// root_certs or key_cert_pairs. Note that we will send updates of the
// latest contents for both root and identity certificates, even when only
// one side of it got updated.
//
// @param root_certs the contents of the reloaded root certs.
// @param key_cert_pairs the contents of the reloaded identity key-cert
// pairs.
virtual void OnCertificatesChanged(
absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList> key_cert_pairs) = 0;
// Handles an error that occurs while attempting to fetch certificate data.
// Note that if a watcher sees an error, it simply means the Provider is
// having problems renewing new data. If the watcher has previously received
// several OnCertificatesChanged, all the data received from that function
// is valid.
// In that case, watcher might simply log the error. If the watcher hasn't
// received any OnCertificatesChanged before the error occurs, no valid
// data is available yet, and the watcher should either fail or "waiting"
// for the valid data in a non-blocking way.
//
// @param root_cert_error the error occurred while reloading root
// certificates.
// @param identity_cert_error the error occurred while reloading identity
// certificates.
virtual void OnError(grpc_error* root_cert_error,
grpc_error* identity_cert_error) = 0;
};
// Sets the key materials based on their certificate name. Note that we are
// not doing any copies for pem_root_certs and pem_key_cert_pairs. For
// pem_root_certs, the original string contents need to outlive the
// distributor; for pem_key_cert_pairs, internally it is taking two
// unique_ptr(s) to the credential string, so the ownership is actually
// transferred.
//
// @param cert_name The name of the certificates being updated.
// @param pem_root_certs The content of root certificates.
// @param pem_key_cert_pairs The content of identity key-cert pairs.
void SetKeyMaterials(const std::string& cert_name,
absl::optional<std::string> pem_root_certs,
absl::optional<PemKeyCertPairList> pem_key_cert_pairs);
bool HasRootCerts(const std::string& root_cert_name);
bool HasKeyCertPairs(const std::string& identity_cert_name);
// Propagates the error that the caller (e.g. Producer) encounters to all the
// watchers watching a particular certificate name.
//
// @param cert_name The watching cert name of the watchers that the caller
// wants to notify when encountering error.
// @param root_cert_error The error that the caller encounters when reloading
// root certs.
// @param identity_cert_error The error that the caller encounters when
// reloading identity certs.
void SetErrorForCert(const std::string& cert_name,
absl::optional<grpc_error*> root_cert_error,
absl::optional<grpc_error*> identity_cert_error);
// Propagates the error that the caller (e.g. Producer) encounters to all
// watchers.
//
// @param error The error that the caller encounters.
void SetError(grpc_error* error);
// Sets the TLS certificate watch status callback function. The
// grpc_tls_certificate_distributor will invoke this callback when a new
// certificate name is watched by a newly registered watcher, or when a
// certificate name is no longer watched by any watchers.
// Note that when the callback shows a cert is no longer being watched, the
// distributor will delete the corresponding certificate data from its cache,
// and clear the corresponding error, if there is any. This means that if the
// callback subsequently says the same cert is now being watched again, the
// provider must re-provide the credentials or re-invoke the errors to the
// distributor, to indicate a successful or failed reloading.
// @param callback The callback function being set by the caller, e.g the
// Producer. Note that this callback will be invoked for each certificate
// name.
//
// For the parameters in the callback function:
// string_value The name of the certificates being watched.
// bool_value_1 If the root certificates with the specific name are being
// watched. bool_value_2 If the identity certificates with the specific name
// are being watched.
void SetWatchStatusCallback(
std::function<void(std::string, bool, bool)> callback) {
grpc_core::MutexLock lock(&mu_);
watch_status_callback_ = callback;
};
// Registers a watcher. The caller may keep a raw pointer to the watcher,
// which may be used only for cancellation. (Because the caller does not own
// the watcher, the pointer must not be used for any other purpose.) At least
// one of root_cert_name and identity_cert_name must be specified.
//
// @param watcher The watcher being registered.
// @param root_cert_name The name of the root certificates that will be
// watched. If set to absl::nullopt, the root certificates won't be watched.
// @param identity_cert_name The name of the identity certificates that will
// be watched. If set to absl::nullopt, the identity certificates won't be
// watched.
void WatchTlsCertificates(
std::unique_ptr<TlsCertificatesWatcherInterface> watcher,
absl::optional<std::string> root_cert_name,
absl::optional<std::string> identity_cert_name);
// Cancels a watcher.
//
// @param watcher The watcher being cancelled.
void CancelTlsCertificatesWatch(TlsCertificatesWatcherInterface* watcher);
private:
// Contains the information about each watcher.
struct WatcherInfo {
std::unique_ptr<TlsCertificatesWatcherInterface> watcher;
absl::optional<std::string> root_cert_name;
absl::optional<std::string> identity_cert_name;
};
// CertificateInfo contains the credential contents and some additional
// watcher information.
// Note that having errors doesn't indicate the corresponding credentials are
// invalid. For example, if root_cert_error != nullptr but pem_root_certs has
// value, it simply means an error occurs while trying to fetch the latest
// root certs, while pem_root_certs still contains the valid old data.
struct CertificateInfo {
// The contents of the root certificates.
std::string pem_root_certs;
// The contents of the identity key-certificate pairs.
PemKeyCertPairList pem_key_cert_pairs;
// The root cert reloading error propagated by the caller.
grpc_error* root_cert_error = GRPC_ERROR_NONE;
// The identity cert reloading error propagated by the caller.
grpc_error* identity_cert_error = GRPC_ERROR_NONE;
// The set of watchers watching root certificates.
// This is mainly used for quickly looking up the affected watchers while
// performing a credential reloading.
std::set<TlsCertificatesWatcherInterface*> root_cert_watchers;
// The set of watchers watching identity certificates. This is mainly used
// for quickly looking up the affected watchers while performing a
// credential reloading.
std::set<TlsCertificatesWatcherInterface*> identity_cert_watchers;
~CertificateInfo() {
GRPC_ERROR_UNREF(root_cert_error);
GRPC_ERROR_UNREF(identity_cert_error);
}
void SetRootError(grpc_error* error) {
GRPC_ERROR_UNREF(root_cert_error);
root_cert_error = error;
}
void SetIdentityError(grpc_error* error) {
GRPC_ERROR_UNREF(identity_cert_error);
identity_cert_error = error;
}
};
grpc_core::Mutex mu_;
// We need a dedicated mutex for watch_status_callback_ for allowing
// callers(e.g. Producer) to directly set key materials in the callback
// functions.
grpc_core::Mutex callback_mu_;
// Stores information about each watcher.
std::map<TlsCertificatesWatcherInterface*, WatcherInfo> watchers_;
// The callback to notify the caller, e.g. the Producer, that the watch status
// is changed.
std::function<void(std::string, bool, bool)> watch_status_callback_;
// Stores the names of each certificate, and their corresponding credential
// contents as well as some additional watcher information.
std::map<std::string, CertificateInfo> certificate_info_map_;
};
#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_GRPC_TLS_CERTIFICATE_DISTRIBUTOR_H

@ -174,6 +174,11 @@ class PemKeyCertPair {
return *this;
}
bool operator==(const PemKeyCertPair& other) const {
return std::strcmp(this->private_key(), other.private_key()) == 0 &&
std::strcmp(this->cert_chain(), other.cert_chain()) == 0;
}
char* private_key() const { return private_key_.get(); }
char* cert_chain() const { return cert_chain_.get(); }

@ -161,8 +161,13 @@ inline void grpc_channel_internal_unref(grpc_channel* channel) {
grpc_channel_internal_unref(channel)
#endif
/** Return the channel's compression options. */
// Return the channel's compression options.
grpc_compression_options grpc_channel_compression_options(
const grpc_channel* channel);
// Ping the channels peer (load balanced channels will select one sub-channel to
// ping); if the channel is not connected, posts a failed.
void grpc_channel_ping(grpc_channel* channel, grpc_completion_queue* cq,
void* tag, void* reserved);
#endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_H */

@ -18,8 +18,6 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/surface/init.h"
#include <limits.h>
#include <memory.h>
@ -28,7 +26,6 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/channel/connected_channel.h"
@ -40,7 +37,6 @@
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/resource_quota.h"
@ -51,6 +47,7 @@
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/init.h"
#include "src/core/lib/surface/lame_client.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/bdp_estimator.h"
@ -214,29 +211,15 @@ void grpc_shutdown_internal(void* /*ignored*/) {
void grpc_shutdown(void) {
GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
grpc_core::MutexLock lock(&g_init_mu);
if (--g_initializations == 0) {
grpc_core::ApplicationCallbackExecCtx* acec =
grpc_core::ApplicationCallbackExecCtx::Get();
if (!grpc_iomgr_is_any_background_poller_thread() &&
(acec == nullptr ||
(acec->Flags() & GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD) ==
0)) {
// just run clean-up when this is called on non-executor thread.
gpr_log(GPR_DEBUG, "grpc_shutdown starts clean-up now");
g_shutting_down = true;
grpc_shutdown_internal_locked();
} else {
// spawn a detached thread to do the actual clean up in case we are
// currently in an executor thread.
gpr_log(GPR_DEBUG, "grpc_shutdown spawns clean-up thread");
g_initializations++;
g_shutting_down = true;
grpc_core::Thread cleanup_thread(
"grpc_shutdown", grpc_shutdown_internal, nullptr, nullptr,
grpc_core::Thread::Options().set_joinable(false).set_tracked(false));
cleanup_thread.Start();
}
g_initializations++;
g_shutting_down = true;
// spawn a detached thread to do the actual clean up in case we are
// currently in an executor thread.
grpc_core::Thread cleanup_thread(
"grpc_shutdown", grpc_shutdown_internal, nullptr, nullptr,
grpc_core::Thread::Options().set_joinable(false).set_tracked(false));
cleanup_thread.Start();
}
}

@ -62,6 +62,8 @@ void grpc_workaround_cronet_compression_filter_init(void);
void grpc_workaround_cronet_compression_filter_shutdown(void);
#ifndef GRPC_NO_XDS
void grpc_certificate_provider_registry_init(void);
void grpc_certificate_provider_registry_shutdown(void);
void grpc_lb_policy_cds_init(void);
void grpc_lb_policy_cds_shutdown(void);
void grpc_lb_policy_eds_init(void);
@ -116,6 +118,8 @@ void grpc_register_built_in_plugins(void) {
grpc_register_plugin(grpc_workaround_cronet_compression_filter_init,
grpc_workaround_cronet_compression_filter_shutdown);
#ifndef GRPC_NO_XDS
grpc_register_plugin(grpc_certificate_provider_registry_init,
grpc_certificate_provider_registry_shutdown);
grpc_register_plugin(grpc_lb_policy_cds_init,
grpc_lb_policy_cds_shutdown);
grpc_register_plugin(grpc_lb_policy_eds_init,

@ -15,6 +15,7 @@ pyx_library(
"**/*.pxi",
"cygrpc.pxd",
"cygrpc.pyx",
"**/__init__.py",
]),
data = [":copy_roots_pem"],
deps = [

@ -199,6 +199,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/upb-generated/udpa/annotations/versioning.upb.c',
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
'src/core/ext/upb-generated/validate/validate.upb.c',
'src/core/ext/xds/certificate_provider_registry.cc',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_client.cc',
@ -393,6 +394,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc',
'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc',
'src/core/lib/security/credentials/tls/tls_credentials.cc',
'src/core/lib/security/security_connector/alts/alts_security_connector.cc',

@ -58,7 +58,6 @@ grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_c
grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
grpc_channel_support_connectivity_watcher_type grpc_channel_support_connectivity_watcher_import;
grpc_channel_create_call_type grpc_channel_create_call_import;
grpc_channel_ping_type grpc_channel_ping_import;
grpc_channel_register_call_type grpc_channel_register_call_import;
grpc_channel_create_registered_call_type grpc_channel_create_registered_call_import;
grpc_call_arena_alloc_type grpc_call_arena_alloc_import;
@ -332,7 +331,6 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_channel_watch_connectivity_state_import = (grpc_channel_watch_connectivity_state_type) GetProcAddress(library, "grpc_channel_watch_connectivity_state");
grpc_channel_support_connectivity_watcher_import = (grpc_channel_support_connectivity_watcher_type) GetProcAddress(library, "grpc_channel_support_connectivity_watcher");
grpc_channel_create_call_import = (grpc_channel_create_call_type) GetProcAddress(library, "grpc_channel_create_call");
grpc_channel_ping_import = (grpc_channel_ping_type) GetProcAddress(library, "grpc_channel_ping");
grpc_channel_register_call_import = (grpc_channel_register_call_type) GetProcAddress(library, "grpc_channel_register_call");
grpc_channel_create_registered_call_import = (grpc_channel_create_registered_call_type) GetProcAddress(library, "grpc_channel_create_registered_call");
grpc_call_arena_alloc_import = (grpc_call_arena_alloc_type) GetProcAddress(library, "grpc_call_arena_alloc");

@ -149,9 +149,6 @@ extern grpc_channel_support_connectivity_watcher_type grpc_channel_support_conne
typedef grpc_call*(*grpc_channel_create_call_type)(grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask, grpc_completion_queue* completion_queue, grpc_slice method, const grpc_slice* host, gpr_timespec deadline, void* reserved);
extern grpc_channel_create_call_type grpc_channel_create_call_import;
#define grpc_channel_create_call grpc_channel_create_call_import
typedef void(*grpc_channel_ping_type)(grpc_channel* channel, grpc_completion_queue* cq, void* tag, void* reserved);
extern grpc_channel_ping_type grpc_channel_ping_import;
#define grpc_channel_ping grpc_channel_ping_import
typedef void*(*grpc_channel_register_call_type)(grpc_channel* channel, const char* method, const char* host, void* reserved);
extern grpc_channel_register_call_type grpc_channel_register_call_import;
#define grpc_channel_register_call grpc_channel_register_call_import

@ -706,6 +706,7 @@
)
install(FILES
<%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/cmake/modules/Findc-ares.cmake
<%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/cmake/modules/Findre2.cmake
DESTINATION <%text>${gRPC_INSTALL_CMAKEDIR}</%text>/modules
)

@ -18,6 +18,18 @@ grpc_package(name = "test/core/client_channel")
licenses(["notice"])
grpc_cc_test(
name = "certificate_provider_registry_test",
srcs = ["certificate_provider_registry_test.cc"],
external_deps = ["gtest"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "retry_throttle_test",
srcs = ["retry_throttle_test.cc"],

@ -0,0 +1,90 @@
//
//
// Copyright 2020 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 <grpc/support/port_platform.h>
#include <gmock/gmock.h>
#include "src/core/ext/xds/certificate_provider_registry.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
namespace {
class FakeCertificateProviderFactory1 : public CertificateProviderFactory {
public:
const char* name() const override { return "fake1"; }
std::unique_ptr<Config> CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) override {
return nullptr;
}
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
std::unique_ptr<Config> config) override {
return nullptr;
}
};
class FakeCertificateProviderFactory2 : public CertificateProviderFactory {
public:
const char* name() const override { return "fake2"; }
std::unique_ptr<Config> CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) override {
return nullptr;
}
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
std::unique_ptr<Config> config) override {
return nullptr;
}
};
TEST(CertificateProviderRegistryTest, Basic) {
CertificateProviderRegistry::InitRegistry();
auto* fake_factory_1 = new FakeCertificateProviderFactory1;
auto* fake_factory_2 = new FakeCertificateProviderFactory2;
CertificateProviderRegistry::RegisterCertificateProviderFactory(
std::unique_ptr<CertificateProviderFactory>(fake_factory_1));
CertificateProviderRegistry::RegisterCertificateProviderFactory(
std::unique_ptr<CertificateProviderFactory>(fake_factory_2));
EXPECT_EQ(
CertificateProviderRegistry::LookupCertificateProviderFactory("fake1"),
fake_factory_1);
EXPECT_EQ(
CertificateProviderRegistry::LookupCertificateProviderFactory("fake2"),
fake_factory_2);
EXPECT_EQ(
CertificateProviderRegistry::LookupCertificateProviderFactory("fake3"),
nullptr);
CertificateProviderRegistry::ShutdownRegistry();
}
} // namespace
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(argc, argv);
auto result = RUN_ALL_TESTS();
return result;
}

@ -26,6 +26,7 @@
#include <grpc/support/time.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/surface/channel.h"
#include "test/core/end2end/cq_verifier.h"
#define MAX_PING_STRIKES 2

@ -23,6 +23,7 @@
#include <grpc/support/time.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/surface/channel.h"
#include "test/core/end2end/cq_verifier.h"
#define PING_NUM 5

@ -377,8 +377,7 @@ grpc_cc_test(
language = "C++",
tags = [
# TODO(apolcyn): This test is failing on Windows at entry, enable once passing.
# See e.g. https://source.cloud.google.com/results/invocations/03e2c2bc-1742-48b4-a33d-b4cdaee5c8f9/targets
# E0717 23:43:56.391000000 5488 src/core/lib/surface/server.cc:1630] assertion failed: server->listeners_destroyed == server->listeners.size()
# See e.g. https://source.cloud.google.com/results/invocations/6716596a-c9e1-4780-85ed-890d8758d582/targets
"no_windows",
],
deps = [

@ -224,8 +224,14 @@ class TestServer {
}
~TestServer() {
grpc_server_shutdown_and_notify(server_, cq_, nullptr);
thread_.join();
void* shutdown_and_notify_tag = this;
grpc_server_shutdown_and_notify(server_, cq_, shutdown_and_notify_tag);
grpc_event event = grpc_completion_queue_next(
cq_, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
GPR_ASSERT(event.type == GRPC_OP_COMPLETE);
GPR_ASSERT(event.tag == shutdown_and_notify_tag);
GPR_ASSERT(event.success);
grpc_server_destroy(server_);
grpc_completion_queue_shutdown(cq_);
while (grpc_completion_queue_next(cq_, gpr_inf_future(GPR_CLOCK_REALTIME),
@ -243,7 +249,7 @@ class TestServer {
grpc_call_details_init(&call_details);
grpc_metadata_array request_metadata_recv;
grpc_metadata_array_init(&request_metadata_recv);
void* tag = this;
void* tag = &call_details;
grpc_call* call;
grpc_call_error error = grpc_server_request_call(
server_, &call, &call_details, &request_metadata_recv, cq_, cq_, tag);

@ -313,3 +313,16 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "grpc_tls_certificate_distributor_test",
srcs = ["grpc_tls_certificate_distributor_test.cc"],
external_deps = ["gtest"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc_secure",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,968 @@
//
// Copyright 2020 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/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
#include <gmock/gmock.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <gtest/gtest.h>
#include <deque>
#include <list>
#include <string>
#include <thread>
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
namespace testing {
constexpr const char* kCertName1 = "cert_1_name";
constexpr const char* kCertName2 = "cert_2_name";
constexpr const char* kRootCert1Name = "root_cert_1_name";
constexpr const char* kRootCert1Contents = "root_cert_1_contents";
constexpr const char* kRootCert2Name = "root_cert_2_name";
constexpr const char* kRootCert2Contents = "root_cert_2_contents";
constexpr const char* kIdentityCert1Name = "identity_cert_1_name";
constexpr const char* kIdentityCert1PrivateKey = "identity_private_key_1";
constexpr const char* kIdentityCert1Contents = "identity_cert_1_contents";
constexpr const char* kIdentityCert2Name = "identity_cert_2_name";
constexpr const char* kIdentityCert2PrivateKey = "identity_private_key_2";
constexpr const char* kIdentityCert2Contents = "identity_cert_2_contents";
constexpr const char* kErrorMessage = "error_message";
constexpr const char* kRootErrorMessage = "root_error_message";
constexpr const char* kIdentityErrorMessage = "identity_error_message";
class GrpcTlsCertificateDistributorTest : public ::testing::Test {
protected:
// Forward declaration.
class TlsCertificatesTestWatcher;
static grpc_tls_certificate_distributor::PemKeyCertPairList MakeCertKeyPairs(
const char* private_key, const char* certs) {
if (strcmp(private_key, "") == 0 && strcmp(certs, "") == 0) {
return {};
}
grpc_ssl_pem_key_cert_pair* ssl_pair =
static_cast<grpc_ssl_pem_key_cert_pair*>(
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
ssl_pair->private_key = gpr_strdup(private_key);
ssl_pair->cert_chain = gpr_strdup(certs);
grpc_tls_certificate_distributor::PemKeyCertPairList pem_key_cert_pairs;
pem_key_cert_pairs.emplace_back(ssl_pair);
return pem_key_cert_pairs;
}
// CredentialInfo contains the parameters when calling OnCertificatesChanged
// of a watcher. When OnCertificatesChanged is invoked, we will push a
// CredentialInfo to the cert_update_queue of state_, and check in each test
// if the status updates are correct.
struct CredentialInfo {
std::string root_certs;
grpc_tls_certificate_distributor::PemKeyCertPairList key_cert_pairs;
CredentialInfo(
std::string root,
grpc_tls_certificate_distributor::PemKeyCertPairList key_cert)
: root_certs(std::move(root)), key_cert_pairs(std::move(key_cert)) {}
bool operator==(const CredentialInfo& other) const {
return root_certs == other.root_certs &&
key_cert_pairs == other.key_cert_pairs;
}
};
// ErrorInfo contains the parameters when calling OnError of a watcher. When
// OnError is invoked, we will push a ErrorInfo to the error_queue of state_,
// and check in each test if the status updates are correct.
struct ErrorInfo {
std::string root_cert_str;
std::string identity_cert_str;
ErrorInfo(std::string root, std::string identity)
: root_cert_str(std::move(root)),
identity_cert_str(std::move(identity)) {}
bool operator==(const ErrorInfo& other) const {
return root_cert_str == other.root_cert_str &&
identity_cert_str == other.identity_cert_str;
}
};
struct WatcherState {
TlsCertificatesTestWatcher* watcher = nullptr;
std::deque<CredentialInfo> cert_update_queue;
std::deque<ErrorInfo> error_queue;
std::deque<CredentialInfo> GetCredentialQueue() {
// We move the data member value so the data member will be re-initiated
// with size 0, and ready for the next check.
return std::move(cert_update_queue);
}
std::deque<ErrorInfo> GetErrorQueue() {
// We move the data member value so the data member will be re-initiated
// with size 0, and ready for the next check.
return std::move(error_queue);
}
};
class TlsCertificatesTestWatcher : public grpc_tls_certificate_distributor::
TlsCertificatesWatcherInterface {
public:
// ctor sets state->watcher to this.
explicit TlsCertificatesTestWatcher(WatcherState* state) : state_(state) {
state_->watcher = this;
}
// dtor sets state->watcher to nullptr.
~TlsCertificatesTestWatcher() { state_->watcher = nullptr; }
void OnCertificatesChanged(
absl::optional<absl::string_view> root_certs,
absl::optional<grpc_tls_certificate_distributor::PemKeyCertPairList>
key_cert_pairs) override {
std::string updated_root;
if (root_certs.has_value()) {
updated_root = std::string(*root_certs);
}
grpc_tls_certificate_distributor::PemKeyCertPairList updated_identity;
if (key_cert_pairs.has_value()) {
updated_identity = std::move(*key_cert_pairs);
}
state_->cert_update_queue.emplace_back(std::move(updated_root),
std::move(updated_identity));
}
void OnError(grpc_error* root_cert_error,
grpc_error* identity_cert_error) override {
GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
identity_cert_error != GRPC_ERROR_NONE);
std::string root_error_str;
std::string identity_error_str;
if (root_cert_error != GRPC_ERROR_NONE) {
grpc_slice root_error_slice;
GPR_ASSERT(grpc_error_get_str(
root_cert_error, GRPC_ERROR_STR_DESCRIPTION, &root_error_slice));
root_error_str =
std::string(grpc_core::StringViewFromSlice(root_error_slice));
}
if (identity_cert_error != GRPC_ERROR_NONE) {
grpc_slice identity_error_slice;
GPR_ASSERT(grpc_error_get_str(identity_cert_error,
GRPC_ERROR_STR_DESCRIPTION,
&identity_error_slice));
identity_error_str =
std::string(grpc_core::StringViewFromSlice(identity_error_slice));
}
state_->error_queue.emplace_back(std::move(root_error_str),
std::move(identity_error_str));
GRPC_ERROR_UNREF(root_cert_error);
GRPC_ERROR_UNREF(identity_cert_error);
}
private:
WatcherState* state_;
};
// CallbackStatus contains the parameters when calling watch_status_callback_
// of the distributor. When a particular callback is invoked, we will push a
// CallbackStatus to a callback_queue_, and check in each test if the status
// updates are correct.
struct CallbackStatus {
std::string cert_name;
bool root_being_watched;
bool identity_being_watched;
CallbackStatus(std::string name, bool root_watched, bool identity_watched)
: cert_name(std::move(name)),
root_being_watched(root_watched),
identity_being_watched(identity_watched) {}
bool operator==(const CallbackStatus& other) const {
return cert_name == other.cert_name &&
root_being_watched == other.root_being_watched &&
identity_being_watched == other.identity_being_watched;
}
};
void SetUp() override {
distributor_.SetWatchStatusCallback([this](std::string cert_name,
bool root_being_watched,
bool identity_being_watched) {
callback_queue_.emplace_back(std::move(cert_name), root_being_watched,
identity_being_watched);
});
}
WatcherState* MakeWatcher(absl::optional<std::string> root_cert_name,
absl::optional<std::string> identity_cert_name) {
grpc_core::MutexLock lock(&mu_);
watchers_.emplace_back();
// TlsCertificatesTestWatcher ctor takes a pointer to the WatcherState.
// It sets WatcherState::watcher to point to itself.
// The TlsCertificatesTestWatcher dtor will set WatcherState::watcher back
// to nullptr to indicate that it's been destroyed.
auto watcher =
absl::make_unique<TlsCertificatesTestWatcher>(&watchers_.back());
distributor_.WatchTlsCertificates(std::move(watcher),
std::move(root_cert_name),
std::move(identity_cert_name));
return &watchers_.back();
}
void CancelWatch(WatcherState* state) {
grpc_core::MutexLock lock(&mu_);
distributor_.CancelTlsCertificatesWatch(state->watcher);
EXPECT_EQ(state->watcher, nullptr);
}
std::deque<CallbackStatus> GetCallbackQueue() {
// We move the data member value so the data member will be re-initiated
// with size 0, and ready for the next check.
return std::move(callback_queue_);
}
grpc_tls_certificate_distributor distributor_;
// Use a std::list<> here to avoid the address invalidation caused by internal
// reallocation of std::vector<>.
std::list<WatcherState> watchers_;
std::deque<CallbackStatus> callback_queue_;
// This is to make watchers_ and callback_queue_ thread-safe.
grpc_core::Mutex mu_;
};
TEST_F(GrpcTlsCertificateDistributorTest, BasicCredentialBehaviors) {
EXPECT_FALSE(distributor_.HasRootCerts(kRootCert1Name));
EXPECT_FALSE(distributor_.HasKeyCertPairs(kIdentityCert1Name));
// After setting the certificates to the corresponding cert names, the
// distributor should possess the corresponding certs.
distributor_.SetKeyMaterials(kRootCert1Name, kRootCert1Contents,
absl::nullopt);
EXPECT_TRUE(distributor_.HasRootCerts(kRootCert1Name));
distributor_.SetKeyMaterials(
kIdentityCert1Name, absl::nullopt,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
EXPECT_TRUE(distributor_.HasKeyCertPairs(kIdentityCert1Name));
// Querying a non-existing cert name should return false.
EXPECT_FALSE(distributor_.HasRootCerts(kRootCert2Name));
EXPECT_FALSE(distributor_.HasKeyCertPairs(kIdentityCert2Name));
}
TEST_F(GrpcTlsCertificateDistributorTest, UpdateCredentialsOnAnySide) {
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
// SetKeyMaterials should trigger watcher's OnCertificatesChanged method.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
// Set root certs should trigger watcher's OnCertificatesChanged again.
distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert2Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
// Set identity certs should trigger watcher's OnCertificatesChanged again.
distributor_.SetKeyMaterials(
kCertName1, absl::nullopt,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert2Contents,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
CancelWatch(watcher_state_1);
}
TEST_F(GrpcTlsCertificateDistributorTest, SameIdentityNameDiffRootName) {
// Register watcher 1.
WatcherState* watcher_state_1 =
MakeWatcher(kRootCert1Name, kIdentityCert1Name);
EXPECT_THAT(
GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
CallbackStatus(kIdentityCert1Name, false, true)));
// Register watcher 2.
WatcherState* watcher_state_2 =
MakeWatcher(kRootCert2Name, kIdentityCert1Name);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
kRootCert2Name, true, false)));
// Push credential updates to kRootCert1Name and check if the status works as
// expected.
distributor_.SetKeyMaterials(kRootCert1Name, kRootCert1Contents,
absl::nullopt);
// Check the updates are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
// Push credential updates to kRootCert2Name.
distributor_.SetKeyMaterials(kRootCert2Name, kRootCert2Contents,
absl::nullopt);
// Check the updates are delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
// Push credential updates to kIdentityCert1Name and check if the status works
// as expected.
distributor_.SetKeyMaterials(
kIdentityCert1Name, absl::nullopt,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Check the updates are delivered to watcher 1 and watcher 2.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
EXPECT_THAT(
watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert2Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
// Cancel watcher 1.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
kRootCert1Name, false, false)));
// Cancel watcher 2.
CancelWatch(watcher_state_2);
EXPECT_THAT(
GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kRootCert2Name, false, false),
CallbackStatus(kIdentityCert1Name, false, false)));
}
TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
// Register watcher 1.
WatcherState* watcher_state_1 =
MakeWatcher(kRootCert1Name, kIdentityCert1Name);
EXPECT_THAT(
GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
CallbackStatus(kIdentityCert1Name, false, true)));
// Register watcher 2.
WatcherState* watcher_state_2 =
MakeWatcher(kRootCert1Name, kIdentityCert2Name);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
kIdentityCert2Name, false, true)));
// Push credential updates to kRootCert1Name and check if the status works as
// expected.
distributor_.SetKeyMaterials(kRootCert1Name, kRootCert1Contents,
absl::nullopt);
// Check the updates are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
// Check the updates are delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
// Push credential updates to SetKeyMaterials.
distributor_.SetKeyMaterials(
kIdentityCert1Name, absl::nullopt,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Check the updates are delivered to watcher 1.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
// Push credential updates to kIdentityCert2Name.
distributor_.SetKeyMaterials(
kIdentityCert2Name, absl::nullopt,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
// Check the updates are delivered to watcher 2.
EXPECT_THAT(
watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
// Cancel watcher 1.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
kIdentityCert1Name, false, false)));
// Cancel watcher 2.
CancelWatch(watcher_state_2);
EXPECT_THAT(
GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kRootCert1Name, false, false),
CallbackStatus(kIdentityCert2Name, false, false)));
}
TEST_F(GrpcTlsCertificateDistributorTest,
AddAndCancelFirstWatcherForSameRootAndIdentityCertName) {
// Register watcher 1 watching kCertName1 for both root and identity certs.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
// Push credential updates to kCertName1 and check if the status works as
// expected.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Check the updates are delivered to watcher 1.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
// Cancel watcher 1.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
}
TEST_F(GrpcTlsCertificateDistributorTest,
AddAndCancelFirstWatcherForIdentityCertNameWithRootBeingWatched) {
// Register watcher 1 watching kCertName1 for root certs.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, absl::nullopt);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
// Register watcher 2 watching kCertName1 for identity certs.
WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
// Push credential updates to kCertName1 and check if the status works as
// expected.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Check the updates are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
// Check the updates are delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
"", MakeCertKeyPairs(kIdentityCert1PrivateKey,
kIdentityCert1Contents))));
// Push root cert updates to kCertName1.
distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
// Check the updates are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
// Check the updates are not delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), testing::ElementsAre());
// Push identity cert updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, absl::nullopt,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
// Check the updates are not delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), testing::ElementsAre());
// Check the updates are delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
"", MakeCertKeyPairs(kIdentityCert2PrivateKey,
kIdentityCert2Contents))));
watcher_state_2->cert_update_queue.clear();
// Cancel watcher 2.
CancelWatch(watcher_state_2);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
// Cancel watcher 1.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
}
TEST_F(GrpcTlsCertificateDistributorTest,
AddAndCancelFirstWatcherForRootCertNameWithIdentityBeingWatched) {
// Register watcher 1 watching kCertName1 for identity certs.
WatcherState* watcher_state_1 = MakeWatcher(absl::nullopt, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
// Register watcher 2 watching kCertName1 for root certs.
WatcherState* watcher_state_2 = MakeWatcher(kCertName1, absl::nullopt);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
// Push credential updates to kCertName1 and check if the status works as
// expected.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Check the updates are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
"", MakeCertKeyPairs(kIdentityCert1PrivateKey,
kIdentityCert1Contents))));
// Check the updates are delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
// Push root cert updates to kCertName1.
distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
// Check the updates are delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
// Check the updates are not delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), testing::ElementsAre());
// Push identity cert updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, absl::nullopt,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
// Check the updates are not delivered to watcher 2.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), testing::ElementsAre());
// Check the updates are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
"", MakeCertKeyPairs(kIdentityCert2PrivateKey,
kIdentityCert2Contents))));
// Cancel watcher 2.
CancelWatch(watcher_state_2);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
// Cancel watcher 1.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
}
TEST_F(GrpcTlsCertificateDistributorTest,
RemoveAllWatchersForCertNameAndAddAgain) {
// Register watcher 1 and watcher 2 watching kCertName1 for root and identity
// certs.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
WatcherState* watcher_state_2 = MakeWatcher(kCertName1, kCertName1);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
// Push credential updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Cancel watcher 2.
CancelWatch(watcher_state_2);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
// Cancel watcher 1.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
// Register watcher 3 watching kCertName for root and identity certs.
WatcherState* watcher_state_3 = MakeWatcher(kCertName1, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
// Push credential updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, kRootCert2Contents,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
// Check the updates are delivered to watcher 3.
EXPECT_THAT(
watcher_state_3->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert2Contents,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
// Cancel watcher 3.
CancelWatch(watcher_state_3);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
}
TEST_F(GrpcTlsCertificateDistributorTest, ResetCallbackToNull) {
// Register watcher 1 watching kCertName1 for root and identity certs.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
EXPECT_THAT(GetCallbackQueue(),
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
// Reset callback to nullptr.
distributor_.SetWatchStatusCallback(nullptr);
// Cancel watcher 1 shouldn't trigger any callback.
CancelWatch(watcher_state_1);
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
}
TEST_F(GrpcTlsCertificateDistributorTest, SetKeyMaterialsInCallback) {
distributor_.SetWatchStatusCallback([this](std::string cert_name,
bool root_being_watched,
bool identity_being_watched) {
distributor_.SetKeyMaterials(
cert_name, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
});
auto verify_function = [this](std::string cert_name) {
WatcherState* watcher_state_1 = MakeWatcher(cert_name, cert_name);
// Check the updates are delivered to watcher 1.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents, MakeCertKeyPairs(kIdentityCert1PrivateKey,
kIdentityCert1Contents))));
CancelWatch(watcher_state_1);
};
// Start 1000 threads that will register a watcher to a new cert name, verify
// the key materials being set, and then cancel the watcher, to make sure the
// lock mechanism in the distributor is safe.
std::vector<std::thread> threads;
threads.reserve(1000);
for (int i = 0; i < 1000; ++i) {
threads.emplace_back(verify_function, std::to_string(i));
}
for (auto& th : threads) {
th.join();
}
}
TEST_F(GrpcTlsCertificateDistributorTest, WatchACertInfoWithValidCredentials) {
// Push credential updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Push root credential updates to kCertName2.
distributor_.SetKeyMaterials(kRootCert2Name, kRootCert2Contents,
absl::nullopt);
// Push identity credential updates to kCertName2.
distributor_.SetKeyMaterials(
kIdentityCert2Name, absl::nullopt,
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
// watcher 1 should receive the credentials right away.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
CancelWatch(watcher_state_1);
// Register watcher 2.
WatcherState* watcher_state_2 = MakeWatcher(kRootCert2Name, absl::nullopt);
// watcher 2 should receive the root credentials right away.
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
// Register watcher 3.
WatcherState* watcher_state_3 =
MakeWatcher(absl::nullopt, kIdentityCert2Name);
// watcher 3 should received the identity credentials right away.
EXPECT_THAT(watcher_state_3->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
"", MakeCertKeyPairs(kIdentityCert2PrivateKey,
kIdentityCert2Contents))));
CancelWatch(watcher_state_2);
CancelWatch(watcher_state_3);
}
TEST_F(GrpcTlsCertificateDistributorTest,
SetErrorForCertForBothRootAndIdentity) {
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
// Calling SetErrorForCert on both cert names should only call one OnError
// on watcher 1.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
// Calling SetErrorForCert on root cert name should call OnError
// on watcher 1 again.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage),
absl::nullopt);
EXPECT_THAT(
watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kErrorMessage, kIdentityErrorMessage)));
// Calling SetErrorForCert on identity cert name should call OnError
// on watcher 1 again.
distributor_.SetErrorForCert(
kCertName1, absl::nullopt,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
distributor_.CancelTlsCertificatesWatch(watcher_state_1->watcher);
EXPECT_EQ(watcher_state_1->watcher, nullptr);
}
TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertForRootOrIdentity) {
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, absl::nullopt);
// Calling SetErrorForCert on root name should only call one OnError
// on watcher 1.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
absl::nullopt);
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
// Calling SetErrorForCert on identity name should do nothing.
distributor_.SetErrorForCert(
kCertName1, absl::nullopt,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
// Calling SetErrorForCert on both names should still get one OnError call.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
CancelWatch(watcher_state_1);
// Register watcher 2.
WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName1);
// Calling SetErrorForCert on identity name should only call one OnError
// on watcher 2.
distributor_.SetErrorForCert(
kCertName1, absl::nullopt,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
// Calling SetErrorForCert on root name should do nothing.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
absl::nullopt);
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
// Calling SetErrorForCert on both names should still get one OnError call.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
CancelWatch(watcher_state_2);
}
TEST_F(GrpcTlsCertificateDistributorTest,
SetErrorForIdentityNameWithPreexistingErrorForRootName) {
// SetErrorForCert for kCertName1.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
// Register watcher 1 for kCertName1 as root and kCertName2 as identity.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName2);
// Should trigger OnError call right away since kCertName1 has error.
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
// Calling SetErrorForCert on kCertName2 should trigger OnError with both
// errors, because kCertName1 also has error.
distributor_.SetErrorForCert(
kCertName2, absl::nullopt,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
CancelWatch(watcher_state_1);
}
TEST_F(GrpcTlsCertificateDistributorTest,
SetErrorForCertForRootNameWithSameNameForIdentityErrored) {
// SetErrorForCert for kCertName1.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
// Register watcher 1 for kCertName2 as root and kCertName1 as identity.
WatcherState* watcher_state_1 = MakeWatcher(kCertName2, kCertName1);
// Should trigger OnError call right away since kCertName2 has error.
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
// Calling SetErrorForCert on kCertName2 should trigger OnError with both
// errors, because kCertName1 also has error.
distributor_.SetErrorForCert(
kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
absl::nullopt);
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
CancelWatch(watcher_state_1);
}
TEST_F(GrpcTlsCertificateDistributorTest,
SetErrorForIdentityNameWithoutErrorForRootName) {
// Register watcher 1 for kCertName1 as root and kCertName2 as identity.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName2);
// Should not trigger OnError.
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
// Calling SetErrorForCert on kCertName2 should trigger OnError.
distributor_.SetErrorForCert(
kCertName2, absl::nullopt,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
CancelWatch(watcher_state_1);
// Register watcher 2 for kCertName2 as identity and a non-existing name
// kRootCert1Name as root.
WatcherState* watcher_state_2 = MakeWatcher(kRootCert1Name, kCertName2);
// Should not trigger OnError.
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
// Calling SetErrorForCert on kCertName2 should trigger OnError.
distributor_.SetErrorForCert(
kCertName2, absl::nullopt,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_2->error_queue,
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
CancelWatch(watcher_state_2);
}
TEST_F(GrpcTlsCertificateDistributorTest,
SetErrorForRootNameWithPreexistingErrorForIdentityName) {
WatcherState* watcher_state_1 = MakeWatcher(kCertName2, kCertName1);
// Should not trigger OnError.
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
// Calling SetErrorForCert on kCertName2 should trigger OnError.
distributor_.SetErrorForCert(
kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
absl::nullopt);
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
CancelWatch(watcher_state_1);
// Register watcher 2 for kCertName2 as root and a non-existing name
// kIdentityCert1Name as identity.
WatcherState* watcher_state_2 = MakeWatcher(kCertName2, kIdentityCert1Name);
// Should not trigger OnError.
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
// Calling SetErrorForCert on kCertName2 should trigger OnError.
distributor_.SetErrorForCert(
kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
absl::nullopt);
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
CancelWatch(watcher_state_2);
}
TEST_F(GrpcTlsCertificateDistributorTest,
CancelTheLastWatcherOnAnErroredCertInfo) {
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
// Calling SetErrorForCert on both cert names should only call one OnError
// on watcher 1.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
// When watcher 1 is removed, the cert info entry should be removed.
CancelWatch(watcher_state_1);
// Register watcher 2 on the same cert name.
WatcherState* watcher_state_2 = MakeWatcher(kCertName1, kCertName1);
// Should not trigger OnError call on watcher 2 right away.
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
CancelWatch(watcher_state_2);
}
TEST_F(GrpcTlsCertificateDistributorTest,
WatchErroredCertInfoWithValidCredentialData) {
// Push credential updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Calling SetErrorForCert on both cert names.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
// watcher 1 should receive both the old credentials and the error right away.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
CancelWatch(watcher_state_1);
}
TEST_F(GrpcTlsCertificateDistributorTest,
SetErrorForCertThenSuccessfulCredentialUpdates) {
// Calling SetErrorForCert on both cert names.
distributor_.SetErrorForCert(
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
// Push credential updates to kCertName1.
distributor_.SetKeyMaterials(
kCertName1, kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
// watcher 1 should only receive credential updates without any error, because
// the previous error is wiped out by a successful update.
EXPECT_THAT(
watcher_state_1->GetCredentialQueue(),
testing::ElementsAre(CredentialInfo(
kRootCert1Contents,
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
CancelWatch(watcher_state_1);
}
TEST_F(GrpcTlsCertificateDistributorTest, WatchCertInfoThenInvokeSetError) {
// Register watcher 1.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
// Register watcher 2.
WatcherState* watcher_state_2 = MakeWatcher(kRootCert1Name, absl::nullopt);
// Register watcher 3.
WatcherState* watcher_state_3 =
MakeWatcher(absl::nullopt, kIdentityCert1Name);
distributor_.SetError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
testing::ElementsAre(ErrorInfo(kErrorMessage, "")));
EXPECT_THAT(watcher_state_3->GetErrorQueue(),
testing::ElementsAre(ErrorInfo("", kErrorMessage)));
CancelWatch(watcher_state_1);
CancelWatch(watcher_state_2);
CancelWatch(watcher_state_3);
}
TEST_F(GrpcTlsCertificateDistributorTest, WatchErroredCertInfoBySetError) {
// Register watcher 1 watching kCertName1 as root.
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, absl::nullopt);
// Register watcher 2 watching kCertName2 as identity.
WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName2);
// Call SetError and then cancel all watchers.
distributor_.SetError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
CancelWatch(watcher_state_1);
CancelWatch(watcher_state_2);
// Register watcher 3 watching kCertName1 as root and kCertName2 as identity
// should not get the error updates.
WatcherState* watcher_state_3 = MakeWatcher(kCertName1, kCertName2);
EXPECT_THAT(watcher_state_3->GetErrorQueue(), testing::ElementsAre());
CancelWatch(watcher_state_3);
// Register watcher 4 watching kCertName2 as root and kCertName1 as identity
// should not get the error updates.
WatcherState* watcher_state_4 = MakeWatcher(kCertName2, kCertName1);
EXPECT_THAT(watcher_state_4->GetErrorQueue(), testing::ElementsAre());
CancelWatch(watcher_state_4);
}
TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertInCallback) {
distributor_.SetWatchStatusCallback([this](std::string cert_name,
bool root_being_watched,
bool identity_being_watched) {
this->distributor_.SetErrorForCert(
cert_name, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
});
auto verify_function = [this](std::string cert_name) {
WatcherState* watcher_state_1 = MakeWatcher(cert_name, cert_name);
// Check the errors are delivered to watcher 1.
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
testing::ElementsAre(
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
CancelWatch(watcher_state_1);
};
// Start 1000 threads that will register a watcher to a new cert name, verify
// the key materials being set, and then cancel the watcher, to make sure the
// lock mechanism in the distributor is safe.
std::vector<std::thread> threads;
threads.reserve(1000);
for (int i = 0; i < 1000; ++i) {
threads.emplace_back(verify_function, std::to_string(i));
}
for (auto& th : threads) {
th.join();
}
}
} // namespace testing
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -79,9 +79,6 @@ grpc_cc_test(
grpc_cc_test(
name = "init_test",
srcs = ["init_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
uses_polling = False,
deps = [

@ -16,22 +16,14 @@
*
*/
#include "src/core/lib/surface/init.h"
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <gtest/gtest.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/surface/init.h"
#include "test/core/util/test_config.h"
static int g_plugin_state;
static void plugin_init(void) { g_plugin_state = 1; }
static void plugin_destroy(void) { g_plugin_state = 2; }
static bool plugin_is_intialized(void) { return g_plugin_state == 1; }
static bool plugin_is_destroyed(void) { return g_plugin_state == 2; }
static int g_flag;
static void test(int rounds) {
int i;
@ -41,13 +33,7 @@ static void test(int rounds) {
for (i = 0; i < rounds; i++) {
grpc_shutdown();
}
EXPECT_FALSE(grpc_is_initialized());
}
TEST(Init, test) {
test(1);
test(2);
test(3);
grpc_maybe_wait_for_async_shutdown();
}
static void test_blocking(int rounds) {
@ -58,87 +44,55 @@ static void test_blocking(int rounds) {
for (i = 0; i < rounds; i++) {
grpc_shutdown_blocking();
}
EXPECT_FALSE(grpc_is_initialized());
}
TEST(Init, blocking) {
test_blocking(1);
test_blocking(2);
test_blocking(3);
}
TEST(Init, shutdown_with_thread) {
grpc_init();
{
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx(
GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
grpc_shutdown();
}
grpc_maybe_wait_for_async_shutdown();
EXPECT_FALSE(grpc_is_initialized());
}
TEST(Init, mixed) {
static void test_mixed(void) {
grpc_init();
grpc_init();
grpc_shutdown();
grpc_init();
grpc_shutdown();
grpc_shutdown();
EXPECT_FALSE(grpc_is_initialized());
}
TEST(Init, mixed_with_thread) {
grpc_init();
{
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx(
GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
grpc_init();
grpc_shutdown();
grpc_init();
grpc_shutdown();
grpc_shutdown();
}
grpc_maybe_wait_for_async_shutdown();
EXPECT_FALSE(grpc_is_initialized());
}
TEST(Init, plugin) {
static void plugin_init(void) { g_flag = 1; }
static void plugin_destroy(void) { g_flag = 2; }
static void test_plugin() {
grpc_register_plugin(plugin_init, plugin_destroy);
grpc_init();
EXPECT_TRUE(plugin_is_intialized());
GPR_ASSERT(g_flag == 1);
grpc_shutdown_blocking();
EXPECT_TRUE(plugin_is_destroyed());
EXPECT_FALSE(grpc_is_initialized());
GPR_ASSERT(g_flag == 2);
}
TEST(Init, repeatedly) {
for (int i = 0; i < 10; i++) {
static void test_repeatedly() {
for (int i = 0; i < 1000; i++) {
grpc_init();
{
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx(
GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
grpc_shutdown();
}
grpc_shutdown();
}
grpc_maybe_wait_for_async_shutdown();
EXPECT_FALSE(grpc_is_initialized());
}
TEST(Init, repeatedly_blocking) {
for (int i = 0; i < 10; i++) {
static void test_repeatedly_blocking() {
for (int i = 0; i < 1000; i++) {
grpc_init();
{
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx(
GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
grpc_shutdown_blocking();
}
grpc_shutdown_blocking();
}
EXPECT_FALSE(grpc_is_initialized());
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
grpc_register_plugin(plugin_init, plugin_destroy);
return RUN_ALL_TESTS();
test(1);
test(2);
test(3);
test_blocking(1);
test_blocking(2);
test_blocking(3);
test_mixed();
test_plugin();
test_repeatedly();
test_repeatedly_blocking();
return 0;
}

@ -104,7 +104,6 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_channel_watch_connectivity_state);
printf("%lx", (unsigned long) grpc_channel_support_connectivity_watcher);
printf("%lx", (unsigned long) grpc_channel_create_call);
printf("%lx", (unsigned long) grpc_channel_ping);
printf("%lx", (unsigned long) grpc_channel_register_call);
printf("%lx", (unsigned long) grpc_channel_create_registered_call);
printf("%lx", (unsigned long) grpc_call_arena_alloc);

@ -49,6 +49,7 @@
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/channel.h"
#include "test/core/util/memory_counters.h"
#include "test/core/util/port.h"

@ -38,8 +38,14 @@
static int* chosen_ports = nullptr;
static size_t num_chosen_ports = 0;
static grpc_core::Mutex* g_default_port_picker_mu;
static gpr_once g_default_port_picker_init = GPR_ONCE_INIT;
static int free_chosen_port(int port) {
static void init_default_port_picker() {
g_default_port_picker_mu = new grpc_core::Mutex();
}
static int free_chosen_port_locked(int port) {
size_t i;
int found = 0;
size_t found_at = 0;
@ -61,6 +67,7 @@ static int free_chosen_port(int port) {
}
static void free_chosen_ports(void) {
grpc_core::MutexLock lock(g_default_port_picker_mu);
size_t i;
grpc_init();
for (i = 0; i < num_chosen_ports; i++) {
@ -70,7 +77,7 @@ static void free_chosen_ports(void) {
gpr_free(chosen_ports);
}
static void chose_port(int port) {
static void chose_port_locked(int port) {
if (chosen_ports == nullptr) {
atexit(free_chosen_ports);
}
@ -81,9 +88,11 @@ static void chose_port(int port) {
}
static int grpc_pick_unused_port_impl(void) {
gpr_once_init(&g_default_port_picker_init, init_default_port_picker);
grpc_core::MutexLock lock(g_default_port_picker_mu);
int port = grpc_pick_port_using_server();
if (port != 0) {
chose_port(port);
chose_port_locked(port);
}
return port;
@ -103,7 +112,9 @@ static int grpc_pick_unused_port_or_die_impl(void) {
}
static void grpc_recycle_unused_port_impl(int port) {
GPR_ASSERT(free_chosen_port(port));
gpr_once_init(&g_default_port_picker_init, init_default_port_picker);
grpc_core::MutexLock lock(g_default_port_picker_mu);
GPR_ASSERT(free_chosen_port_locked(port));
}
static grpc_pick_port_functions g_pick_port_functions = {

@ -1531,7 +1531,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
std::tuple<int, int, int> WaitForAllBackends(
size_t start_index = 0, size_t stop_index = 0, bool reset_counters = true,
const RpcOptions& rpc_options = RpcOptions()) {
const RpcOptions& rpc_options = RpcOptions(),
bool allow_failures = false) {
int num_ok = 0;
int num_failure = 0;
int num_drops = 0;
@ -1545,7 +1546,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
"Performed %d warm up requests against the backends. "
"%d succeeded, %d failed, %d dropped.",
num_total, num_ok, num_failure, num_drops);
EXPECT_EQ(num_failure, 0);
if (!allow_failures) EXPECT_EQ(num_failure, 0);
return std::make_tuple(num_ok, num_failure, num_drops);
}
@ -1662,8 +1663,10 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
for (const auto& metadata : rpc_options.metadata) {
context.AddMetadata(metadata.first, metadata.second);
}
context.set_deadline(
grpc_timeout_milliseconds_to_deadline(rpc_options.timeout_ms));
if (rpc_options.timeout_ms != 0) {
context.set_deadline(
grpc_timeout_milliseconds_to_deadline(rpc_options.timeout_ms));
}
if (rpc_options.wait_for_ready) context.set_wait_for_ready(true);
request.set_message(kRequestMessage_);
if (rpc_options.server_fail) {
@ -3593,6 +3596,101 @@ TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
(1 + kErrorToleranceSmallLoad))));
}
TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClusters) {
const char* kNewCluster1Name = "new_cluster_1";
const size_t kNumEchoRpcs = 5;
SetNextResolution({});
SetNextResolutionForLbChannelAllBalancers();
// Populate new EDS resources.
AdsServiceImpl::EdsResourceArgs args({
{"locality0", GetBackendPorts(0, 1)},
});
AdsServiceImpl::EdsResourceArgs args1({
{"locality0", GetBackendPorts(1, 2)},
});
balancers_[0]->ads_service()->SetEdsResource(
AdsServiceImpl::BuildEdsResource(args));
balancers_[0]->ads_service()->SetEdsResource(
AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name));
// Populate new CDS resources.
Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster();
new_cluster1.set_name(kNewCluster1Name);
balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
// Send Route Configuration.
RouteConfiguration new_route_config =
balancers_[0]->ads_service()->default_route_config();
SetRouteConfiguration(0, new_route_config);
WaitForAllBackends(0, 1);
CheckRpcSendOk(kNumEchoRpcs);
// Make sure RPCs all go to the correct backend.
EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
// Change Route Configurations: new default cluster.
auto* default_route =
new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
default_route->mutable_route()->set_cluster(kNewCluster1Name);
SetRouteConfiguration(0, new_route_config);
WaitForAllBackends(1, 2);
CheckRpcSendOk(kNumEchoRpcs);
// Make sure RPCs all go to the correct backend.
EXPECT_EQ(kNumEchoRpcs, backends_[1]->backend_service()->request_count());
}
TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClustersWithPickingDelays) {
const char* kNewCluster1Name = "new_cluster_1";
SetNextResolution({});
SetNextResolutionForLbChannelAllBalancers();
// Populate new EDS resources.
AdsServiceImpl::EdsResourceArgs args({
{"locality0", GetBackendPorts(0, 1)},
});
AdsServiceImpl::EdsResourceArgs args1({
{"locality0", GetBackendPorts(1, 2)},
});
balancers_[0]->ads_service()->SetEdsResource(
AdsServiceImpl::BuildEdsResource(args));
balancers_[0]->ads_service()->SetEdsResource(
AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name));
// Populate new CDS resources.
Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster();
new_cluster1.set_name(kNewCluster1Name);
balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
// Bring down the current backend: 0, this will delay route picking time,
// resulting in un-committed RPCs.
ShutdownBackend(0);
// Send a RouteConfiguration with a default route that points to
// backend 0.
RouteConfiguration new_route_config =
balancers_[0]->ads_service()->default_route_config();
SetRouteConfiguration(0, new_route_config);
// Send exactly one RPC with no deadline and with wait_for_ready=true.
// This RPC will not complete until after backend 0 is started.
std::thread sending_rpc([this]() {
CheckRpcSendOk(1, RpcOptions().set_wait_for_ready(true).set_timeout_ms(0));
});
// Send a non-wait_for_ready RPC which should fail, this will tell us
// that the client has received the update and attempted to connect.
const Status status = SendRpc(RpcOptions().set_timeout_ms(0));
EXPECT_FALSE(status.ok());
// Send a update RouteConfiguration to use backend 1.
auto* default_route =
new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
default_route->mutable_route()->set_cluster(kNewCluster1Name);
SetRouteConfiguration(0, new_route_config);
// Wait for RPCs to go to the new backend: 1, this ensures that the client has
// processed the update.
WaitForAllBackends(1, 2, false, RpcOptions(), true);
// Bring up the previous backend: 0, this will allow the delayed RPC to
// finally call on_call_committed upon completion.
StartBackend(0);
sending_rpc.join();
// Make sure RPCs go to the correct backend:
// Before moving routing to XdsConfigSelector, 2 to backend 1;
// TODO(donnadionne): After moving routing to XdsConfigSelector, 1 for each
// backend.
EXPECT_EQ(0, backends_[0]->backend_service()->request_count());
EXPECT_EQ(2, backends_[1]->backend_service()->request_count());
}
TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) {
const char* kNewCluster1Name = "new_cluster_1";
const size_t kNumEcho1Rpcs = 100;

@ -310,3 +310,54 @@ grpc_cc_binary(
"//src/proto/grpc/reflection/v1alpha:reflection_proto",
],
)
grpc_cc_binary(
name = "channelz_sampler",
srcs = ["channelz_sampler.cc"],
external_deps = [
"gflags",
],
language = "c++",
tags = [
"no_windows", # unistd.h
],
deps = [
"//:gpr",
"//:grpc++",
"//:grpcpp_channelz",
"//src/proto/grpc/channelz:channelz_proto",
"//test/cpp/util:test_config",
"//test/cpp/util:test_util",
],
)
grpc_cc_test(
name = "channelz_sampler_test",
srcs = [
"channelz_sampler_test.cc",
],
data = [
":channelz_sampler",
],
external_deps = [
"gflags",
"gtest",
],
tags = [
"no_mac", # cmake does not build channelz_sampler in Basic Tests C/C++ MacOS test
"no_test_android", # android_cc_test doesn't work with data dependency.
"no_test_ios",
"no_windows", # unistd.h
],
deps = [
"//:gpr",
"//:grpc",
"//:grpc++",
"//:grpcpp_channelz",
"//src/proto/grpc/channelz:channelz_proto",
"//src/proto/grpc/testing:test_proto",
"//test/core/util:grpc_test_util",
"//test/core/util:grpc_test_util_base",
"//test/cpp/util:test_util",
],
)

@ -0,0 +1,588 @@
/*
*
* Copyright 2015 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 <unistd.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <memory>
#include <ostream>
#include <queue>
#include <string>
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "gflags/gflags.h"
#include "google/protobuf/text_format.h"
#include "grpc/grpc.h"
#include "grpc/support/port_platform.h"
#include "grpcpp/channel.h"
#include "grpcpp/client_context.h"
#include "grpcpp/create_channel.h"
#include "grpcpp/ext/channelz_service_plugin.h"
#include "grpcpp/grpcpp.h"
#include "grpcpp/security/credentials.h"
#include "grpcpp/security/server_credentials.h"
#include "grpcpp/server.h"
#include "grpcpp/server_builder.h"
#include "grpcpp/server_context.h"
#include "src/core/lib/json/json.h"
#include "src/cpp/server/channelz/channelz_service.h"
#include "src/proto/grpc/channelz/channelz.pb.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/test_config.h"
#include "test/cpp/util/test_credentials_provider.h"
DEFINE_string(server_address, "", "channelz server address");
DEFINE_string(custom_credentials_type, "", "custom credentials type");
DEFINE_int64(sampling_times, 1, "number of sampling");
DEFINE_int64(sampling_interval_seconds, 0, "sampling interval in seconds");
DEFINE_string(output_json, "", "output filename in json format");
namespace {
using grpc::ClientContext;
using grpc::Status;
using grpc::StatusCode;
using grpc::channelz::v1::GetChannelRequest;
using grpc::channelz::v1::GetChannelResponse;
using grpc::channelz::v1::GetServerRequest;
using grpc::channelz::v1::GetServerResponse;
using grpc::channelz::v1::GetServerSocketsRequest;
using grpc::channelz::v1::GetServerSocketsResponse;
using grpc::channelz::v1::GetServersRequest;
using grpc::channelz::v1::GetServersResponse;
using grpc::channelz::v1::GetSocketRequest;
using grpc::channelz::v1::GetSocketResponse;
using grpc::channelz::v1::GetSubchannelRequest;
using grpc::channelz::v1::GetSubchannelResponse;
using grpc::channelz::v1::GetTopChannelsRequest;
using grpc::channelz::v1::GetTopChannelsResponse;
} // namespace
class ChannelzSampler final {
public:
// Get server_id of a server
int64_t GetServerID(const grpc::channelz::v1::Server& server) {
return server.ref().server_id();
}
// Get channel_id of a channel
inline int64_t GetChannelID(const grpc::channelz::v1::Channel& channel) {
return channel.ref().channel_id();
}
// Get subchannel_id of a subchannel
inline int64_t GetSubchannelID(
const grpc::channelz::v1::Subchannel& subchannel) {
return subchannel.ref().subchannel_id();
}
// Get socket_id of a socket
inline int64_t GetSocketID(const grpc::channelz::v1::Socket& socket) {
return socket.ref().socket_id();
}
// Get name of a server
inline std::string GetServerName(const grpc::channelz::v1::Server& server) {
return server.ref().name();
}
// Get name of a channel
inline std::string GetChannelName(
const grpc::channelz::v1::Channel& channel) {
return channel.ref().name();
}
// Get name of a subchannel
inline std::string GetSubchannelName(
const grpc::channelz::v1::Subchannel& subchannel) {
return subchannel.ref().name();
}
// Get name of a socket
inline std::string GetSocketName(const grpc::channelz::v1::Socket& socket) {
return socket.ref().name();
}
// Get a channel based on channel_id
grpc::channelz::v1::Channel GetChannelRPC(int64_t channel_id) {
GetChannelRequest get_channel_request;
get_channel_request.set_channel_id(channel_id);
GetChannelResponse get_channel_response;
ClientContext get_channel_context;
get_channel_context.set_deadline(
grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
Status status = channelz_stub_->GetChannel(
&get_channel_context, get_channel_request, &get_channel_response);
if (!status.ok()) {
gpr_log(GPR_ERROR, "GetChannelRPC failed: %s",
get_channel_context.debug_error_string().c_str());
GPR_ASSERT(0);
}
return get_channel_response.channel();
}
// Get a subchannel based on subchannel_id
grpc::channelz::v1::Subchannel GetSubchannelRPC(int64_t subchannel_id) {
GetSubchannelRequest get_subchannel_request;
get_subchannel_request.set_subchannel_id(subchannel_id);
GetSubchannelResponse get_subchannel_response;
ClientContext get_subchannel_context;
get_subchannel_context.set_deadline(
grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
Status status = channelz_stub_->GetSubchannel(&get_subchannel_context,
get_subchannel_request,
&get_subchannel_response);
if (!status.ok()) {
gpr_log(GPR_ERROR, "GetSubchannelRPC failed: %s",
get_subchannel_context.debug_error_string().c_str());
GPR_ASSERT(0);
}
return get_subchannel_response.subchannel();
}
// get a socket based on socket_id
grpc::channelz::v1::Socket GetSocketRPC(int64_t socket_id) {
GetSocketRequest get_socket_request;
get_socket_request.set_socket_id(socket_id);
GetSocketResponse get_socket_response;
ClientContext get_socket_context;
get_socket_context.set_deadline(
grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
Status status = channelz_stub_->GetSocket(
&get_socket_context, get_socket_request, &get_socket_response);
if (!status.ok()) {
gpr_log(GPR_ERROR, "GetSocketRPC failed: %s",
get_socket_context.debug_error_string().c_str());
GPR_ASSERT(0);
}
return get_socket_response.socket();
}
// get the descedent channels/subchannels/sockets of a channel
// push descedent channels/subchannels to queue for layer traverse
// store descedent channels/subchannels/sockets for dumping data
void GetChannelDescedence(
const grpc::channelz::v1::Channel& channel,
std::queue<grpc::channelz::v1::Channel>& channel_queue,
std::queue<grpc::channelz::v1::Subchannel>& subchannel_queue) {
std::cout << " Channel ID" << GetChannelID(channel) << "_"
<< GetChannelName(channel) << " descendence - ";
if (channel.channel_ref_size() > 0 || channel.subchannel_ref_size() > 0) {
if (channel.channel_ref_size() > 0) {
std::cout << "channel: ";
for (const auto& _channelref : channel.channel_ref()) {
int64_t ch_id = _channelref.channel_id();
std::cout << "ID" << ch_id << "_" << _channelref.name() << " ";
grpc::channelz::v1::Channel ch = GetChannelRPC(ch_id);
channel_queue.push(ch);
if (CheckID(ch_id)) {
all_channels_.push_back(ch);
StoreChannelInJson(ch);
}
}
if (channel.subchannel_ref_size() > 0) {
std::cout << ", ";
}
}
if (channel.subchannel_ref_size() > 0) {
std::cout << "subchannel: ";
for (const auto& _subchannelref : channel.subchannel_ref()) {
int64_t subch_id = _subchannelref.subchannel_id();
std::cout << "ID" << subch_id << "_" << _subchannelref.name() << " ";
grpc::channelz::v1::Subchannel subch = GetSubchannelRPC(subch_id);
subchannel_queue.push(subch);
if (CheckID(subch_id)) {
all_subchannels_.push_back(subch);
StoreSubchannelInJson(subch);
}
}
}
} else if (channel.socket_ref_size() > 0) {
std::cout << "socket: ";
for (const auto& _socketref : channel.socket_ref()) {
int64_t so_id = _socketref.socket_id();
std::cout << "ID" << so_id << "_" << _socketref.name() << " ";
grpc::channelz::v1::Socket so = GetSocketRPC(so_id);
if (CheckID(so_id)) {
all_sockets_.push_back(so);
StoreSocketInJson(so);
}
}
}
std::cout << std::endl;
}
// get the descedent channels/subchannels/sockets of a subchannel
// push descedent channels/subchannels to queue for layer traverse
// store descedent channels/subchannels/sockets for dumping data
void GetSubchannelDescedence(
grpc::channelz::v1::Subchannel& subchannel,
std::queue<grpc::channelz::v1::Channel>& channel_queue,
std::queue<grpc::channelz::v1::Subchannel>& subchannel_queue) {
std::cout << " Subchannel ID" << GetSubchannelID(subchannel) << "_"
<< GetSubchannelName(subchannel) << " descendence - ";
if (subchannel.channel_ref_size() > 0 ||
subchannel.subchannel_ref_size() > 0) {
if (subchannel.channel_ref_size() > 0) {
std::cout << "channel: ";
for (const auto& _channelref : subchannel.channel_ref()) {
int64_t ch_id = _channelref.channel_id();
std::cout << "ID" << ch_id << "_" << _channelref.name() << " ";
grpc::channelz::v1::Channel ch = GetChannelRPC(ch_id);
channel_queue.push(ch);
if (CheckID(ch_id)) {
all_channels_.push_back(ch);
StoreChannelInJson(ch);
}
}
if (subchannel.subchannel_ref_size() > 0) {
std::cout << ", ";
}
}
if (subchannel.subchannel_ref_size() > 0) {
std::cout << "subchannel: ";
for (const auto& _subchannelref : subchannel.subchannel_ref()) {
int64_t subch_id = _subchannelref.subchannel_id();
std::cout << "ID" << subch_id << "_" << _subchannelref.name() << " ";
grpc::channelz::v1::Subchannel subch = GetSubchannelRPC(subch_id);
subchannel_queue.push(subch);
if (CheckID(subch_id)) {
all_subchannels_.push_back(subch);
StoreSubchannelInJson(subch);
}
}
}
} else if (subchannel.socket_ref_size() > 0) {
std::cout << "socket: ";
for (const auto& _socketref : subchannel.socket_ref()) {
int64_t so_id = _socketref.socket_id();
std::cout << "ID" << so_id << "_" << _socketref.name() << " ";
grpc::channelz::v1::Socket so = GetSocketRPC(so_id);
if (CheckID(so_id)) {
all_sockets_.push_back(so);
StoreSocketInJson(so);
}
}
}
std::cout << std::endl;
}
// Set up the channelz sampler client
// Initialize json as an array
void Setup(const std::string& custom_credentials_type,
const std::string& server_address) {
json_ = grpc_core::Json::Array();
rpc_timeout_seconds_ = 20;
grpc::ChannelArguments channel_args;
std::shared_ptr<grpc::ChannelCredentials> channel_creds =
grpc::testing::GetCredentialsProvider()->GetChannelCredentials(
custom_credentials_type, &channel_args);
if (!channel_creds) {
gpr_log(GPR_ERROR,
"Wrong user credential type: %s. Allowed credential types: "
"INSECURE_CREDENTIALS, ssl, alts, google_default_credentials.",
custom_credentials_type.c_str());
GPR_ASSERT(0);
}
std::shared_ptr<grpc::Channel> channel =
CreateChannel(server_address, channel_creds);
channelz_stub_ = grpc::channelz::v1::Channelz::NewStub(channel);
}
// Get all servers, keep querying until getting all
// Store servers for dumping data
// Need to check id repeating for servers
void GetServersRPC() {
int64_t server_start_id = 0;
while (true) {
GetServersRequest get_servers_request;
GetServersResponse get_servers_response;
ClientContext get_servers_context;
get_servers_context.set_deadline(
grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
get_servers_request.set_start_server_id(server_start_id);
Status status = channelz_stub_->GetServers(
&get_servers_context, get_servers_request, &get_servers_response);
if (!status.ok()) {
if (status.error_code() == StatusCode::UNIMPLEMENTED) {
gpr_log(GPR_ERROR,
"Error status UNIMPLEMENTED. Please check and make sure "
"channelz has been registered on the server being queried.");
} else {
gpr_log(GPR_ERROR,
"GetServers RPC with GetServersRequest.server_start_id=%d, "
"failed: %s",
int(server_start_id),
get_servers_context.debug_error_string().c_str());
}
GPR_ASSERT(0);
}
for (const auto& _server : get_servers_response.server()) {
all_servers_.push_back(_server);
StoreServerInJson(_server);
}
if (!get_servers_response.end()) {
server_start_id = GetServerID(all_servers_.back()) + 1;
} else {
break;
}
}
std::cout << "Number of servers = " << all_servers_.size() << std::endl;
}
// Get sockets that belongs to servers
// Store sockets for dumping data
void GetSocketsOfServers() {
for (const auto& _server : all_servers_) {
std::cout << "Server ID" << GetServerID(_server) << "_"
<< GetServerName(_server) << " listen_socket - ";
for (const auto& _socket : _server.listen_socket()) {
int64_t so_id = _socket.socket_id();
std::cout << "ID" << so_id << "_" << _socket.name() << " ";
if (CheckID(so_id)) {
grpc::channelz::v1::Socket so = GetSocketRPC(so_id);
all_sockets_.push_back(so);
StoreSocketInJson(so);
}
}
std::cout << std::endl;
}
}
// Get all top channels, keep querying until getting all
// Store channels for dumping data
// No need to check id repeating for top channels
void GetTopChannelsRPC() {
int64_t channel_start_id = 0;
while (true) {
GetTopChannelsRequest get_top_channels_request;
GetTopChannelsResponse get_top_channels_response;
ClientContext get_top_channels_context;
get_top_channels_context.set_deadline(
grpc_timeout_seconds_to_deadline(rpc_timeout_seconds_));
get_top_channels_request.set_start_channel_id(channel_start_id);
Status status = channelz_stub_->GetTopChannels(
&get_top_channels_context, get_top_channels_request,
&get_top_channels_response);
if (!status.ok()) {
gpr_log(GPR_ERROR,
"GetTopChannels RPC with "
"GetTopChannelsRequest.channel_start_id=%d failed: %s",
int(channel_start_id),
get_top_channels_context.debug_error_string().c_str());
GPR_ASSERT(0);
}
for (const auto& _topchannel : get_top_channels_response.channel()) {
top_channels_.push_back(_topchannel);
all_channels_.push_back(_topchannel);
StoreChannelInJson(_topchannel);
}
if (!get_top_channels_response.end()) {
channel_start_id = GetChannelID(top_channels_.back()) + 1;
} else {
break;
}
}
std::cout << std::endl
<< "Number of top channels = " << top_channels_.size()
<< std::endl;
}
// layer traverse for each top channel
void TraverseTopChannels() {
for (const auto& _topchannel : top_channels_) {
int tree_depth = 0;
std::queue<grpc::channelz::v1::Channel> channel_queue;
std::queue<grpc::channelz::v1::Subchannel> subchannel_queue;
std::cout << "Tree depth = " << tree_depth << std::endl;
GetChannelDescedence(_topchannel, channel_queue, subchannel_queue);
while (!channel_queue.empty() || !subchannel_queue.empty()) {
++tree_depth;
std::cout << "Tree depth = " << tree_depth << std::endl;
int ch_q_size = channel_queue.size();
int subch_q_size = subchannel_queue.size();
for (int i = 0; i < ch_q_size; ++i) {
grpc::channelz::v1::Channel ch = channel_queue.front();
channel_queue.pop();
GetChannelDescedence(ch, channel_queue, subchannel_queue);
}
for (int i = 0; i < subch_q_size; ++i) {
grpc::channelz::v1::Subchannel subch = subchannel_queue.front();
subchannel_queue.pop();
GetSubchannelDescedence(subch, channel_queue, subchannel_queue);
}
}
std::cout << std::endl;
}
}
// dump data of all entities to stdout
void DumpStdout() {
std::string data_str;
for (const auto& _channel : all_channels_) {
std::cout << "channel ID" << GetChannelID(_channel) << "_"
<< GetChannelName(_channel) << " data:" << std::endl;
// TODO(mohanli): TextFormat::PrintToString records time as seconds and
// nanos. Need a more human readable way.
::google::protobuf::TextFormat::PrintToString(_channel.data(), &data_str);
printf("%s\n", data_str.c_str());
}
for (const auto& _subchannel : all_subchannels_) {
std::cout << "subchannel ID" << GetSubchannelID(_subchannel) << "_"
<< GetSubchannelName(_subchannel) << " data:" << std::endl;
::google::protobuf::TextFormat::PrintToString(_subchannel.data(),
&data_str);
printf("%s\n", data_str.c_str());
}
for (const auto& _server : all_servers_) {
std::cout << "server ID" << GetServerID(_server) << "_"
<< GetServerName(_server) << " data:" << std::endl;
::google::protobuf::TextFormat::PrintToString(_server.data(), &data_str);
printf("%s\n", data_str.c_str());
}
for (const auto& _socket : all_sockets_) {
std::cout << "socket ID" << GetSocketID(_socket) << "_"
<< GetSocketName(_socket) << " data:" << std::endl;
::google::protobuf::TextFormat::PrintToString(_socket.data(), &data_str);
printf("%s\n", data_str.c_str());
}
}
// Store a channel in Json
void StoreChannelInJson(const grpc::channelz::v1::Channel& channel) {
std::string id = grpc::to_string(GetChannelID(channel));
std::string type = "Channel";
std::string description;
::google::protobuf::TextFormat::PrintToString(channel.data(), &description);
grpc_core::Json description_json = grpc_core::Json(description);
StoreEntityInJson(id, type, description_json);
}
// Store a subchannel in Json
void StoreSubchannelInJson(const grpc::channelz::v1::Subchannel& subchannel) {
std::string id = grpc::to_string(GetSubchannelID(subchannel));
std::string type = "Subchannel";
std::string description;
::google::protobuf::TextFormat::PrintToString(subchannel.data(),
&description);
grpc_core::Json description_json = grpc_core::Json(description);
StoreEntityInJson(id, type, description_json);
}
// Store a server in Json
void StoreServerInJson(const grpc::channelz::v1::Server& server) {
std::string id = grpc::to_string(GetServerID(server));
std::string type = "Server";
std::string description;
::google::protobuf::TextFormat::PrintToString(server.data(), &description);
grpc_core::Json description_json = grpc_core::Json(description);
StoreEntityInJson(id, type, description_json);
}
// Store a socket in Json
void StoreSocketInJson(const grpc::channelz::v1::Socket& socket) {
std::string id = grpc::to_string(GetSocketID(socket));
std::string type = "Socket";
std::string description;
::google::protobuf::TextFormat::PrintToString(socket.data(), &description);
grpc_core::Json description_json = grpc_core::Json(description);
StoreEntityInJson(id, type, description_json);
}
// Store an entity in Json
void StoreEntityInJson(std::string& id, std::string& type,
const grpc_core::Json& description) {
std::string start, finish;
gpr_timespec ago = gpr_time_sub(
now_,
gpr_time_from_seconds(FLAGS_sampling_interval_seconds, GPR_TIMESPAN));
std::stringstream ss;
const time_t time_now = now_.tv_sec;
ss << std::put_time(std::localtime(&time_now), "%F %T");
finish = ss.str(); // example: "2019-02-01 12:12:18"
ss.str("");
const time_t time_ago = ago.tv_sec;
ss << std::put_time(std::localtime(&time_ago), "%F %T");
start = ss.str();
grpc_core::Json obj =
grpc_core::Json::Object{{"Task", absl::StrFormat("%s_ID%s", type, id)},
{"Start", start},
{"Finish", finish},
{"ID", id},
{"Type", type},
{"Description", description}};
json_.mutable_array()->push_back(obj);
}
// Dump data in json
std::string DumpJson() { return json_.Dump(); }
// Check if one entity has been recorded
bool CheckID(int64_t id) {
if (id_set_.count(id) == 0) {
id_set_.insert(id);
return true;
} else {
return false;
}
}
// Record current time
void RecordNow() { now_ = gpr_now(GPR_CLOCK_REALTIME); }
private:
std::unique_ptr<grpc::channelz::v1::Channelz::Stub> channelz_stub_;
std::vector<grpc::channelz::v1::Channel> top_channels_;
std::vector<grpc::channelz::v1::Server> all_servers_;
std::vector<grpc::channelz::v1::Channel> all_channels_;
std::vector<grpc::channelz::v1::Subchannel> all_subchannels_;
std::vector<grpc::channelz::v1::Socket> all_sockets_;
std::unordered_set<int64_t> id_set_;
grpc_core::Json json_;
int64_t rpc_timeout_seconds_;
gpr_timespec now_;
};
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc::testing::InitTest(&argc, &argv, true);
std::ofstream output_file(FLAGS_output_json);
for (int i = 0; i < FLAGS_sampling_times; ++i) {
ChannelzSampler channelz_sampler;
channelz_sampler.Setup(FLAGS_custom_credentials_type, FLAGS_server_address);
std::cout << "Wait for sampling interval "
<< FLAGS_sampling_interval_seconds << "s..." << std::endl;
const gpr_timespec kDelay = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(FLAGS_sampling_interval_seconds, GPR_TIMESPAN));
gpr_sleep_until(kDelay);
std::cout << "##### " << i << "th sampling #####" << std::endl;
channelz_sampler.RecordNow();
channelz_sampler.GetServersRPC();
channelz_sampler.GetSocketsOfServers();
channelz_sampler.GetTopChannelsRPC();
channelz_sampler.TraverseTopChannels();
channelz_sampler.DumpStdout();
if (!FLAGS_output_json.empty()) {
output_file << channelz_sampler.DumpJson() << "\n" << std::flush;
}
}
output_file.close();
return 0;
}

@ -0,0 +1,176 @@
/*
*
* Copyright 2016 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 <stdlib.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include "grpc/grpc.h"
#include "grpc/support/alloc.h"
#include "grpc/support/port_platform.h"
#include "grpcpp/channel.h"
#include "grpcpp/client_context.h"
#include "grpcpp/create_channel.h"
#include "grpcpp/ext/channelz_service_plugin.h"
#include "grpcpp/grpcpp.h"
#include "grpcpp/security/credentials.h"
#include "grpcpp/security/server_credentials.h"
#include "grpcpp/server.h"
#include "grpcpp/server_builder.h"
#include "grpcpp/server_context.h"
#include "gtest/gtest.h"
#include "src/core/lib/gpr/env.h"
#include "src/cpp/server/channelz/channelz_service.h"
#include "src/proto/grpc/testing/test.grpc.pb.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/subprocess.h"
#include "test/cpp/util/test_credentials_provider.h"
static std::string g_root;
namespace {
using grpc::ClientContext;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
} // namespace
// Test variables
std::string server_address("0.0.0.0:10000");
std::string custom_credentials_type("INSECURE_CREDENTIALS");
std::string sampling_times = "2";
std::string sampling_interval_seconds = "3";
std::string output_json("output.json");
// Creata an echo server
class EchoServerImpl final : public grpc::testing::TestService::Service {
Status EmptyCall(::grpc::ServerContext* context,
const grpc::testing::Empty* request,
grpc::testing::Empty* response) {
return Status::OK;
}
};
// Run client in a thread
void RunClient(const std::string& client_id, gpr_event* done_ev) {
grpc::ChannelArguments channel_args;
std::shared_ptr<grpc::ChannelCredentials> channel_creds =
grpc::testing::GetCredentialsProvider()->GetChannelCredentials(
custom_credentials_type, &channel_args);
std::unique_ptr<grpc::testing::TestService::Stub> stub =
grpc::testing::TestService::NewStub(
grpc::CreateChannel(server_address, channel_creds));
gpr_log(GPR_INFO, "Client %s is echoing!", client_id.c_str());
while (true) {
if (gpr_event_wait(done_ev, grpc_timeout_seconds_to_deadline(1)) !=
nullptr) {
return;
}
grpc::testing::Empty request;
grpc::testing::Empty response;
ClientContext context;
Status status = stub->EmptyCall(&context, request, &response);
if (!status.ok()) {
gpr_log(GPR_ERROR, "Client echo failed.");
GPR_ASSERT(0);
}
}
}
// Create the channelz to test the connection to the server
bool WaitForConnection(int wait_server_seconds) {
grpc::ChannelArguments channel_args;
std::shared_ptr<grpc::ChannelCredentials> channel_creds =
grpc::testing::GetCredentialsProvider()->GetChannelCredentials(
custom_credentials_type, &channel_args);
auto channel = grpc::CreateChannel(server_address, channel_creds);
return channel->WaitForConnected(
grpc_timeout_seconds_to_deadline(wait_server_seconds));
}
// Test the channelz sampler
TEST(ChannelzSamplerTest, SimpleTest) {
// start server
::grpc::channelz::experimental::InitChannelzService();
EchoServerImpl service;
grpc::ServerBuilder builder;
auto server_creds =
grpc::testing::GetCredentialsProvider()->GetServerCredentials(
custom_credentials_type);
builder.AddListeningPort(server_address, server_creds);
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
gpr_log(GPR_INFO, "Server listening on %s", server_address.c_str());
const int kWaitForServerSeconds = 10;
ASSERT_TRUE(WaitForConnection(kWaitForServerSeconds));
// client threads
gpr_event done_ev1, done_ev2;
gpr_event_init(&done_ev1);
gpr_event_init(&done_ev2);
std::thread client_thread_1(RunClient, "1", &done_ev1);
std::thread client_thread_2(RunClient, "2", &done_ev2);
// Run the channelz sampler
grpc::SubProcess* test_driver = new grpc::SubProcess(
{g_root + "/channelz_sampler", "--server_address=" + server_address,
"--custom_credentials_type=" + custom_credentials_type,
"--sampling_times=" + sampling_times,
"--sampling_interval_seconds=" + sampling_interval_seconds,
"--output_json=" + output_json});
int status = test_driver->Join();
if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) {
gpr_log(GPR_ERROR,
"Channelz sampler test test-runner exited with code %d",
WEXITSTATUS(status));
GPR_ASSERT(0); // log the line number of the assertion failure
}
} else if (WIFSIGNALED(status)) {
gpr_log(GPR_ERROR, "Channelz sampler test test-runner ended from signal %d",
WTERMSIG(status));
GPR_ASSERT(0);
} else {
gpr_log(GPR_ERROR,
"Channelz sampler test test-runner ended with unknown status %d",
status);
GPR_ASSERT(0);
}
delete test_driver;
gpr_event_set(&done_ev1, (void*)1);
gpr_event_set(&done_ev2, (void*)1);
client_thread_1.join();
client_thread_2.join();
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
std::string me = argv[0];
auto lslash = me.rfind('/');
if (lslash != std::string::npos) {
g_root = me.substr(0, lslash);
} else {
g_root = ".";
}
int ret = RUN_ALL_TESTS();
return ret;
}

@ -468,6 +468,12 @@ def _filter_cc_tests(tests):
lambda test: not test.startswith(
'test/core/tsi:ssl_session_cache_test'), tests))
# the binary of this test does not get built with cmake
tests = list(
filter(
lambda test: not test.startswith(
'test/cpp/util:channelz_sampler_test'), tests))
return tests

@ -38,7 +38,8 @@ def main(command_arguments):
return _protoc_compiler.run_main(command_arguments)
if sys.version_info[0] > 2:
# NOTE(rbellevi): importlib.abc is not supported on 3.4.
if sys.version_info >= (3, 5, 0):
import contextlib
import importlib
import importlib.machinery

@ -1393,6 +1393,10 @@ src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/upb-generated/validate/validate.upb.h \
src/core/ext/xds/certificate_provider_factory.h \
src/core/ext/xds/certificate_provider_registry.cc \
src/core/ext/xds/certificate_provider_registry.h \
src/core/ext/xds/certificate_provider_store.h \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
@ -1757,6 +1761,8 @@ src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.h \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.h \
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc \
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h \
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h \
src/core/lib/security/credentials/tls/tls_credentials.cc \

@ -1217,6 +1217,10 @@ src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/upb-generated/validate/validate.upb.h \
src/core/ext/xds/certificate_provider_factory.h \
src/core/ext/xds/certificate_provider_registry.cc \
src/core/ext/xds/certificate_provider_registry.h \
src/core/ext/xds/certificate_provider_store.h \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
@ -1586,6 +1590,8 @@ src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.h \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.h \
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc \
src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h \
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc \
src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h \
src/core/lib/security/credentials/tls/tls_credentials.cc \

@ -17,7 +17,7 @@
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/macos/grpc_build_artifacts.sh"
gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
timeout_mins: 120
timeout_mins: 150
action {
define_artifacts {
regex: "**/*sponge_log.*"

@ -222,7 +222,7 @@ LANG_RELEASE_MATRIX = {
('v1.28.1', ReleaseInfo()),
('v1.29.0', ReleaseInfo()),
('v1.30.2', ReleaseInfo()),
('v1.31.0', ReleaseInfo()),
('v1.31.1', ReleaseInfo()),
]),
'python':
OrderedDict([

@ -1607,6 +1607,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
"name": "init_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -3857,6 +3881,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": "certificate_provider_registry_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
@ -4470,7 +4518,7 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "grpc_tls_credentials_options_test",
"name": "grpc_tls_certificate_distributor_test",
"platforms": [
"linux",
"mac",
@ -4485,7 +4533,8 @@
"ci_platforms": [
"linux",
"mac",
"posix"
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
@ -4493,11 +4542,12 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "grpc_tool_test",
"name": "grpc_tls_credentials_options_test",
"platforms": [
"linux",
"mac",
"posix"
"posix",
"windows"
],
"uses_polling": true
},
@ -4507,8 +4557,7 @@
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
"posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
@ -4516,12 +4565,11 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "grpclb_api_test",
"name": "grpc_tool_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
"posix"
],
"uses_polling": true
},
@ -4540,7 +4588,7 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "h2_ssl_session_reuse_test",
"name": "grpclb_api_test",
"platforms": [
"linux",
"mac",
@ -4564,7 +4612,7 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "head_of_line_blocking_bad_client_test",
"name": "h2_ssl_session_reuse_test",
"platforms": [
"linux",
"mac",
@ -4588,7 +4636,7 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "headers_bad_client_test",
"name": "head_of_line_blocking_bad_client_test",
"platforms": [
"linux",
"mac",
@ -4612,7 +4660,7 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "health_service_end2end_test",
"name": "headers_bad_client_test",
"platforms": [
"linux",
"mac",
@ -4636,7 +4684,7 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "hybrid_end2end_test",
"name": "health_service_end2end_test",
"platforms": [
"linux",
"mac",
@ -4660,14 +4708,14 @@
"flaky": false,
"gtest": true,
"language": "c++",
"name": "init_test",
"name": "hybrid_end2end_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
"uses_polling": true
},
{
"args": [],

@ -20,7 +20,7 @@ cd "$(dirname "$0")/../../.."
sudo apt-get install -y python3-pip
sudo python3 -m pip install --upgrade pip
sudo python3 -m pip install grpcio grpcio-tools google-api-python-client google-auth-httplib2 oauth2client
sudo python3 -m pip install grpcio==1.31.0 grpcio-tools==1.31.0 google-api-python-client google-auth-httplib2 oauth2client
# Prepare generated Python code.
TOOLS_DIR=tools/run_tests

@ -25,7 +25,7 @@ import sys
import tempfile
import time
# must be synchronized with test/core/utils/port_server_client.h
# must be synchronized with test/core/util/port_server_client.h
_PORT_SERVER_PORT = 32766

@ -683,13 +683,6 @@ def prepare_services_for_urlmap_tests(gcp, original_backend_service,
Returns:
Returns original and alternate backend names as lists of strings.
'''
# The config validation for proxyless doesn't allow setting
# default_route_action or route_rules. Disable validate
# validate_for_proxyless for this test. This can be removed when validation
# accepts default_route_action.
logger.info('disabling validate_for_proxyless in target proxy')
set_validate_for_proxyless(gcp, False)
logger.info('waiting for original backends to become healthy')
wait_for_healthy_backends(gcp, original_backend_service, instance_group)
@ -784,7 +777,6 @@ def test_traffic_splitting(gcp, original_backend_service, instance_group,
finally:
patch_url_map_backend_service(gcp, original_backend_service)
patch_backend_instances(gcp, alternate_backend_service, [])
set_validate_for_proxyless(gcp, True)
def test_path_matching(gcp, original_backend_service, instance_group,
@ -892,7 +884,6 @@ def test_path_matching(gcp, original_backend_service, instance_group,
finally:
patch_url_map_backend_service(gcp, original_backend_service)
patch_backend_instances(gcp, alternate_backend_service, [])
set_validate_for_proxyless(gcp, True)
def test_header_matching(gcp, original_backend_service, instance_group,
@ -963,7 +954,6 @@ def test_header_matching(gcp, original_backend_service, instance_group,
finally:
patch_url_map_backend_service(gcp, original_backend_service)
patch_backend_instances(gcp, alternate_backend_service, [])
set_validate_for_proxyless(gcp, True)
def get_serving_status(instance, service_port):
@ -1194,27 +1184,12 @@ def patch_url_map_host_rule_with_port(gcp, name, backend_service, host_name):
wait_for_global_operation(gcp, result['name'])
def set_validate_for_proxyless(gcp, validate_for_proxyless):
if not gcp.alpha_compute:
logger.debug(
'Not setting validateForProxy because alpha is not enabled')
return
# This function deletes global_forwarding_rule and target_proxy, then
# recreate target_proxy with validateForProxyless=False. This is necessary
# because patching target_grpc_proxy isn't supported.
delete_global_forwarding_rule(gcp)
delete_target_proxy(gcp)
create_target_proxy(gcp, gcp.target_proxy.name, validate_for_proxyless)
create_global_forwarding_rule(gcp, gcp.global_forwarding_rule.name,
[gcp.service_port])
def create_target_proxy(gcp, name, validate_for_proxyless=True):
def create_target_proxy(gcp, name):
if gcp.alpha_compute:
config = {
'name': name,
'url_map': gcp.url_map.url,
'validate_for_proxyless': validate_for_proxyless,
'validate_for_proxyless': True,
}
logger.debug('Sending GCP request with body=%s', config)
result = gcp.alpha_compute.targetGrpcProxies().insert(

Loading…
Cancel
Save