[xDS] move CDS and EDS watchers into xds resolver (#35011)

Implements gRFC A74 (https://github.com/grpc/proposal/pull/404).

Closes #35011

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35011 from markdroth:xds_watchers_in_xds_resolver a39f71f37f
PiperOrigin-RevId: 595134549
pull/35425/head
Mark D. Roth 1 year ago committed by Copybara-Service
parent 2c18d16475
commit c7101d0867
  1. 1
      BUILD
  2. 3
      CMakeLists.txt
  3. 6
      Makefile
  4. 7
      Package.swift
  5. 7
      build_autogenerated.yaml
  6. 3
      config.m4
  7. 3
      config.w32
  8. 1
      doc/environment_variables.md
  9. 8
      gRPC-C++.podspec
  10. 11
      gRPC-Core.podspec
  11. 7
      grpc.gemspec
  12. 3
      grpc.gyp
  13. 7
      package.xml
  14. 109
      src/core/BUILD
  15. 1037
      src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
  16. 334
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
  17. 2
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
  18. 1231
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
  19. 121
      src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc
  20. 8
      src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h
  21. 1039
      src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc
  22. 281
      src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h
  23. 365
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
  24. 9
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h
  25. 25
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc
  26. 30
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h
  27. 2
      src/core/ext/filters/stateful_session/stateful_session_filter.cc
  28. 3
      src/core/ext/xds/xds_bootstrap.h
  29. 336
      src/core/ext/xds/xds_certificate_provider.cc
  30. 132
      src/core/ext/xds/xds_certificate_provider.h
  31. 22
      src/core/ext/xds/xds_cluster.cc
  32. 2
      src/core/ext/xds/xds_cluster.h
  33. 5
      src/core/ext/xds/xds_cluster_specifier_plugin.cc
  34. 14
      src/core/ext/xds/xds_health_status.cc
  35. 6
      src/core/ext/xds/xds_health_status.h
  36. 51
      src/core/ext/xds/xds_route_config.cc
  37. 1
      src/core/ext/xds/xds_route_config.h
  38. 50
      src/core/ext/xds/xds_server_config_fetcher.cc
  39. 49
      src/core/lib/security/credentials/xds/xds_credentials.cc
  40. 6
      src/core/lib/security/credentials/xds/xds_credentials.h
  41. 3
      src/core/plugin_registry/grpc_plugin_registry_extra.cc
  42. 3
      src/python/grpcio/grpc_core_dependencies.py
  43. 31
      test/core/client_channel/client_channel_service_config_test.cc
  44. 41
      test/core/client_channel/lb_policy/lb_policy_test_lib.h
  45. 117
      test/core/client_channel/lb_policy/xds_override_host_lb_config_parser_test.cc
  46. 86
      test/core/client_channel/lb_policy/xds_override_host_test.cc
  47. 2
      test/core/security/grpc_tls_credentials_options_comparator_test.cc
  48. 19
      test/core/security/xds_credentials_test.cc
  49. 298
      test/core/xds/xds_certificate_provider_test.cc
  50. 65
      test/core/xds/xds_cluster_resource_type_test.cc
  51. 4
      test/core/xds/xds_route_config_resource_type_test.cc
  52. 6
      test/cpp/end2end/xds/xds_cluster_end2end_test.cc
  53. 10
      test/cpp/end2end/xds/xds_cluster_type_end2end_test.cc
  54. 23
      test/cpp/end2end/xds/xds_core_end2end_test.cc
  55. 2
      test/cpp/end2end/xds/xds_csds_end2end_test.cc
  56. 3
      test/cpp/end2end/xds/xds_fault_injection_end2end_test.cc
  57. 4
      test/cpp/end2end/xds/xds_routing_end2end_test.cc
  58. 2
      tools/codegen/core/gen_grpc_tls_credentials_options.py
  59. 7
      tools/doxygen/Doxyfile.c++.internal
  60. 7
      tools/doxygen/Doxyfile.core.internal

@ -584,7 +584,6 @@ GRPC_XDS_TARGETS = [
"//src/core:grpc_lb_policy_cds", "//src/core:grpc_lb_policy_cds",
"//src/core:grpc_lb_policy_xds_cluster_impl", "//src/core:grpc_lb_policy_xds_cluster_impl",
"//src/core:grpc_lb_policy_xds_cluster_manager", "//src/core:grpc_lb_policy_xds_cluster_manager",
"//src/core:grpc_lb_policy_xds_cluster_resolver",
"//src/core:grpc_lb_policy_xds_override_host", "//src/core:grpc_lb_policy_xds_override_host",
"//src/core:grpc_lb_policy_xds_wrr_locality", "//src/core:grpc_lb_policy_xds_wrr_locality",
"//src/core:grpc_lb_policy_ring_hash", "//src/core:grpc_lb_policy_ring_hash",

3
CMakeLists.txt generated

@ -1793,7 +1793,6 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc
src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc
src/core/ext/filters/client_channel/local_subchannel_pool.cc src/core/ext/filters/client_channel/local_subchannel_pool.cc
@ -1812,7 +1811,9 @@ add_library(grpc
src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
src/core/ext/filters/client_channel/resolver/polling_resolver.cc src/core/ext/filters/client_channel/resolver/polling_resolver.cc
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc
src/core/ext/filters/client_channel/retry_filter.cc src/core/ext/filters/client_channel/retry_filter.cc
src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc
src/core/ext/filters/client_channel/retry_service_config.cc src/core/ext/filters/client_channel/retry_service_config.cc

6
Makefile generated

@ -994,7 +994,6 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \ src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \
src/core/ext/filters/client_channel/local_subchannel_pool.cc \ src/core/ext/filters/client_channel/local_subchannel_pool.cc \
@ -1013,7 +1012,9 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \
src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \ src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \
@ -3375,11 +3376,12 @@ src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc: $(OPENSSL_
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/lb_policy/xds/cds.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc: $(OPENSSL_DEP) src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc: $(OPENSSL_DEP)
src/core/ext/filters/rbac/rbac_filter.cc: $(OPENSSL_DEP) src/core/ext/filters/rbac/rbac_filter.cc: $(OPENSSL_DEP)
src/core/ext/filters/rbac/rbac_service_config_parser.cc: $(OPENSSL_DEP) src/core/ext/filters/rbac/rbac_service_config_parser.cc: $(OPENSSL_DEP)
src/core/ext/filters/server_config_selector/server_config_selector_filter.cc: $(OPENSSL_DEP) src/core/ext/filters/server_config_selector/server_config_selector_filter.cc: $(OPENSSL_DEP)

7
Package.swift generated

@ -189,7 +189,6 @@ let package = Package(
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h", "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc", "src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc", "src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc", "src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h", "src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc", "src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc",
@ -219,8 +218,12 @@ let package = Package(
"src/core/ext/filters/client_channel/resolver/polling_resolver.cc", "src/core/ext/filters/client_channel/resolver/polling_resolver.cc",
"src/core/ext/filters/client_channel/resolver/polling_resolver.h", "src/core/ext/filters/client_channel/resolver/polling_resolver.h",
"src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc", "src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc",
"src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc",
"src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h",
"src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc", "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc",
"src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h", "src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h",
"src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc",
"src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h",
"src/core/ext/filters/client_channel/retry_filter.cc", "src/core/ext/filters/client_channel/retry_filter.cc",
"src/core/ext/filters/client_channel/retry_filter.h", "src/core/ext/filters/client_channel/retry_filter.h",
"src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc", "src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc",

@ -263,7 +263,9 @@ libs:
- src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
- src/core/ext/filters/client_channel/resolver/polling_resolver.h - src/core/ext/filters/client_channel/resolver/polling_resolver.h
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h - src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h
- src/core/ext/filters/client_channel/retry_filter.h - src/core/ext/filters/client_channel/retry_filter.h
- src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h - src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h
- src/core/ext/filters/client_channel/retry_service_config.h - src/core/ext/filters/client_channel/retry_service_config.h
@ -1252,7 +1254,6 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/xds/cds.cc - src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc - src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc - src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc - src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc - src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc
- src/core/ext/filters/client_channel/local_subchannel_pool.cc - src/core/ext/filters/client_channel/local_subchannel_pool.cc
@ -1271,7 +1272,9 @@ libs:
- src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc - src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
- src/core/ext/filters/client_channel/resolver/polling_resolver.cc - src/core/ext/filters/client_channel/resolver/polling_resolver.cc
- src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
- src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc - src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc
- src/core/ext/filters/client_channel/retry_filter.cc - src/core/ext/filters/client_channel/retry_filter.cc
- src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc - src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc
- src/core/ext/filters/client_channel/retry_service_config.cc - src/core/ext/filters/client_channel/retry_service_config.cc

3
config.m4 generated

@ -80,7 +80,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \ src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \
src/core/ext/filters/client_channel/local_subchannel_pool.cc \ src/core/ext/filters/client_channel/local_subchannel_pool.cc \
@ -99,7 +98,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \
src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \ src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \

3
config.w32 generated

@ -45,7 +45,6 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\cds.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\cds.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_cluster_impl.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_cluster_impl.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_cluster_manager.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_cluster_manager.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_cluster_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_override_host.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_override_host.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_wrr_locality.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_wrr_locality.cc " +
"src\\core\\ext\\filters\\client_channel\\local_subchannel_pool.cc " + "src\\core\\ext\\filters\\client_channel\\local_subchannel_pool.cc " +
@ -64,7 +63,9 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\resolver\\google_c2p\\google_c2p_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\google_c2p\\google_c2p_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\polling_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\polling_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_dependency_manager.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver_trace.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_filter.cc " + "src\\core\\ext\\filters\\client_channel\\retry_filter.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_filter_legacy_call_data.cc " + "src\\core\\ext\\filters\\client_channel\\retry_filter_legacy_call_data.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_service_config.cc " + "src\\core\\ext\\filters\\client_channel\\retry_service_config.cc " +

@ -102,7 +102,6 @@ some configuration as environment variables that can be set.
- xds_client - traces xds client - xds_client - traces xds client
- xds_cluster_manager_lb - traces cluster manager LB policy - xds_cluster_manager_lb - traces cluster manager LB policy
- xds_cluster_impl_lb - traces cluster impl LB policy - xds_cluster_impl_lb - traces cluster impl LB policy
- xds_cluster_resolver_lb - traces xds cluster resolver LB policy
- xds_resolver - traces xds resolver - xds_resolver - traces xds resolver
The following tracers will only run in binaries built in DEBUG mode. This is The following tracers will only run in binaries built in DEBUG mode. This is

8
gRPC-C++.podspec generated

@ -294,7 +294,9 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h',
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h', 'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h',
'src/core/ext/filters/client_channel/retry_service_config.h', 'src/core/ext/filters/client_channel/retry_service_config.h',
@ -1552,7 +1554,9 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h',
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h', 'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h',
'src/core/ext/filters/client_channel/retry_service_config.h', 'src/core/ext/filters/client_channel/retry_service_config.h',

11
gRPC-Core.podspec generated

@ -292,7 +292,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc',
@ -322,8 +321,12 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc', 'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc',
@ -2339,7 +2342,9 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.h',
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h', 'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.h',
'src/core/ext/filters/client_channel/retry_service_config.h', 'src/core/ext/filters/client_channel/retry_service_config.h',

7
grpc.gemspec generated

@ -195,7 +195,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc )
@ -225,8 +224,12 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/resolver/polling_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/polling_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/polling_resolver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/polling_resolver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h )
s.files += %w( src/core/ext/filters/client_channel/retry_filter.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_filter.cc )
s.files += %w( src/core/ext/filters/client_channel/retry_filter.h ) s.files += %w( src/core/ext/filters/client_channel/retry_filter.h )
s.files += %w( src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc )

3
grpc.gyp generated

@ -313,7 +313,6 @@
'src/core/ext/filters/client_channel/lb_policy/xds/cds.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/cds.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc',
'src/core/ext/filters/client_channel/local_subchannel_pool.cc', 'src/core/ext/filters/client_channel/local_subchannel_pool.cc',
@ -332,7 +331,9 @@
'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc', 'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc',
'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc',
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc', 'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc',
'src/core/ext/filters/client_channel/retry_service_config.cc', 'src/core/ext/filters/client_channel/retry_service_config.cc',

7
package.xml generated

@ -177,7 +177,6 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc" role="src" />
@ -207,8 +206,12 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/polling_resolver.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/polling_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/polling_resolver.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/polling_resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc" role="src" />

@ -4187,7 +4187,7 @@ grpc_cc_library(
"channel_args", "channel_args",
"channel_fwd", "channel_fwd",
"context", "context",
"grpc_resolver_xds_header", "grpc_resolver_xds_attributes",
"grpc_service_config", "grpc_service_config",
"json", "json",
"json_args", "json_args",
@ -4710,9 +4710,9 @@ grpc_cc_library(
deps = [ deps = [
"channel_args", "channel_args",
"delegating_helper", "delegating_helper",
"grpc_matchers", "grpc_lb_address_filtering",
"grpc_lb_xds_channel_args",
"grpc_outlier_detection_header", "grpc_outlier_detection_header",
"grpc_tls_credentials",
"grpc_xds_client", "grpc_xds_client",
"json", "json",
"json_args", "json_args",
@ -4725,6 +4725,7 @@ grpc_cc_library(
"pollset_set", "pollset_set",
"time", "time",
"unique_type_name", "unique_type_name",
"xds_dependency_manager",
"//:config", "//:config",
"//:debug_location", "//:debug_location",
"//:gpr", "//:gpr",
@ -4750,54 +4751,6 @@ grpc_cc_library(
], ],
) )
grpc_cc_library(
name = "grpc_lb_policy_xds_cluster_resolver",
srcs = [
"ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc",
],
external_deps = [
"absl/functional:function_ref",
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/types:optional",
],
language = "c++",
deps = [
"channel_args",
"delegating_helper",
"grpc_lb_address_filtering",
"grpc_lb_xds_channel_args",
"grpc_xds_client",
"json",
"json_args",
"json_object_loader",
"json_writer",
"lb_policy",
"lb_policy_factory",
"lb_policy_registry",
"no_destruct",
"pollset_set",
"ref_counted_string",
"resolved_address",
"validation_errors",
"//:channel_arg_names",
"//:config",
"//:debug_location",
"//:endpoint_addresses",
"//:gpr",
"//:grpc_base",
"//:grpc_client_channel",
"//:grpc_resolver",
"//:grpc_resolver_fake",
"//:grpc_trace",
"//:orphanable",
"//:ref_counted_ptr",
"//:work_serializer",
"//:xds_client",
],
)
grpc_cc_library( grpc_cc_library(
name = "grpc_lb_policy_xds_cluster_impl", name = "grpc_lb_policy_xds_cluster_impl",
srcs = [ srcs = [
@ -4829,6 +4782,7 @@ grpc_cc_library(
"resolved_address", "resolved_address",
"subchannel_interface", "subchannel_interface",
"validation_errors", "validation_errors",
"xds_dependency_manager",
"//:config", "//:config",
"//:debug_location", "//:debug_location",
"//:endpoint_addresses", "//:endpoint_addresses",
@ -4857,7 +4811,7 @@ grpc_cc_library(
deps = [ deps = [
"channel_args", "channel_args",
"delegating_helper", "delegating_helper",
"grpc_resolver_xds_header", "grpc_resolver_xds_attributes",
"json", "json",
"json_args", "json_args",
"json_object_loader", "json_object_loader",
@ -5449,6 +5403,7 @@ grpc_cc_library(
"resolved_address", "resolved_address",
"subchannel_interface", "subchannel_interface",
"validation_errors", "validation_errors",
"xds_dependency_manager",
"//:config", "//:config",
"//:debug_location", "//:debug_location",
"//:endpoint_addresses", "//:endpoint_addresses",
@ -5758,9 +5713,9 @@ grpc_cc_library(
) )
grpc_cc_library( grpc_cc_library(
name = "grpc_resolver_xds_header", name = "grpc_resolver_xds_attributes",
hdrs = [ hdrs = [
"ext/filters/client_channel/resolver/xds/xds_resolver.h", "ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h",
], ],
external_deps = ["absl/strings"], external_deps = ["absl/strings"],
language = "c++", language = "c++",
@ -5771,6 +5726,48 @@ grpc_cc_library(
], ],
) )
grpc_cc_library(
name = "grpc_resolver_xds_trace",
srcs = [
"ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc",
],
hdrs = [
"ext/filters/client_channel/resolver/xds/xds_resolver_trace.h",
],
language = "c++",
deps = [
"//:gpr_platform",
"//:grpc_trace",
],
)
grpc_cc_library(
name = "xds_dependency_manager",
srcs = [
"ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc",
],
hdrs = [
"ext/filters/client_channel/resolver/xds/xds_dependency_manager.h",
],
external_deps = [
"absl/container:flat_hash_map",
"absl/container:flat_hash_set",
"absl/strings",
],
language = "c++",
deps = [
"grpc_lb_xds_channel_args",
"grpc_resolver_xds_trace",
"grpc_xds_client",
"match",
"ref_counted",
"//:config",
"//:gpr",
"//:grpc_resolver",
"//:grpc_resolver_fake",
],
)
grpc_cc_library( grpc_cc_library(
name = "grpc_resolver_xds", name = "grpc_resolver_xds",
srcs = [ srcs = [
@ -5797,7 +5794,8 @@ grpc_cc_library(
"dual_ref_counted", "dual_ref_counted",
"experiments", "experiments",
"grpc_lb_policy_ring_hash", "grpc_lb_policy_ring_hash",
"grpc_resolver_xds_header", "grpc_resolver_xds_attributes",
"grpc_resolver_xds_trace",
"grpc_service_config", "grpc_service_config",
"grpc_xds_client", "grpc_xds_client",
"iomgr_fwd", "iomgr_fwd",
@ -5806,6 +5804,7 @@ grpc_cc_library(
"ref_counted", "ref_counted",
"slice", "slice",
"time", "time",
"xds_dependency_manager",
"xxhash_inline", "xxhash_inline",
"//:channel_arg_names", "//:channel_arg_names",
"//:config", "//:config",

File diff suppressed because it is too large Load Diff

@ -40,6 +40,7 @@
#include "src/core/ext/filters/client_channel/lb_policy/backend_metric_data.h" #include "src/core/ext/filters/client_channel/lb_policy/backend_metric_data.h"
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h" #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h"
#include "src/core/ext/xds/xds_bootstrap.h" #include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/ext/xds/xds_bootstrap_grpc.h" #include "src/core/ext/xds/xds_bootstrap_grpc.h"
#include "src/core/ext/xds/xds_client.h" #include "src/core/ext/xds/xds_client.h"
@ -66,6 +67,7 @@
#include "src/core/lib/load_balancing/lb_policy_registry.h" #include "src/core/lib/load_balancing/lb_policy_registry.h"
#include "src/core/lib/load_balancing/subchannel_interface.h" #include "src/core/lib/load_balancing/subchannel_interface.h"
#include "src/core/lib/resolver/endpoint_addresses.h" #include "src/core/lib/resolver/endpoint_addresses.h"
#include "src/core/lib/security/credentials/xds/xds_credentials.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
namespace grpc_core { namespace grpc_core {
@ -74,6 +76,8 @@ TraceFlag grpc_xds_cluster_impl_lb_trace(false, "xds_cluster_impl_lb");
namespace { namespace {
using XdsConfig = XdsDependencyManager::XdsConfig;
// //
// global circuit breaker atomic map // global circuit breaker atomic map
// //
@ -156,37 +160,24 @@ class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
absl::string_view name() const override { return kXdsClusterImpl; } absl::string_view name() const override { return kXdsClusterImpl; }
const std::string& cluster_name() const { return cluster_name_; }
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const { RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_; return child_policy_;
} }
const std::string& cluster_name() const { return cluster_name_; }
const std::string& eds_service_name() const { return eds_service_name_; }
const absl::optional<GrpcXdsBootstrap::GrpcXdsServer>&
lrs_load_reporting_server() const {
return lrs_load_reporting_server_;
};
uint32_t max_concurrent_requests() const { return max_concurrent_requests_; }
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config() const {
return drop_config_;
}
static const JsonLoaderInterface* JsonLoader(const JsonArgs&); static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
void JsonPostLoad(const Json& json, const JsonArgs& args, void JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors); ValidationErrors* errors);
private: private:
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
std::string cluster_name_; std::string cluster_name_;
std::string eds_service_name_; RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
absl::optional<GrpcXdsBootstrap::GrpcXdsServer> lrs_load_reporting_server_;
uint32_t max_concurrent_requests_;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config_;
}; };
// xDS Cluster Impl LB policy. // xDS Cluster Impl LB policy.
class XdsClusterImplLb : public LoadBalancingPolicy { class XdsClusterImplLb : public LoadBalancingPolicy {
public: public:
XdsClusterImplLb(RefCountedPtr<XdsClient> xds_client, Args args); XdsClusterImplLb(RefCountedPtr<GrpcXdsClient> xds_client, Args args);
absl::string_view name() const override { return kXdsClusterImpl; } absl::string_view name() const override { return kXdsClusterImpl; }
@ -247,16 +238,25 @@ class XdsClusterImplLb : public LoadBalancingPolicy {
void ShutdownLocked() override; void ShutdownLocked() override;
void ResetState();
void ReportTransientFailure(absl::Status status);
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked( OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
const ChannelArgs& args); const ChannelArgs& args);
absl::Status UpdateChildPolicyLocked( absl::Status UpdateChildPolicyLocked(
absl::StatusOr<std::shared_ptr<EndpointAddressesIterator>> addresses, absl::StatusOr<std::shared_ptr<EndpointAddressesIterator>> addresses,
std::string resolution_note, const ChannelArgs& args); std::string resolution_note, const ChannelArgs& args);
absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
MaybeCreateCertificateProviderLocked(
const XdsClusterResource& cluster_resource) const;
void MaybeUpdatePickerLocked(); void MaybeUpdatePickerLocked();
// Current config from the resolver. // Current config from the resolver.
RefCountedPtr<XdsClusterImplLbConfig> config_; RefCountedPtr<XdsClusterImplLbConfig> config_;
std::shared_ptr<const XdsClusterResource> cluster_resource_;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config_;
// Current concurrent number of requests. // Current concurrent number of requests.
RefCountedPtr<CircuitBreakerCallCounterMap::CallCounter> call_counter_; RefCountedPtr<CircuitBreakerCallCounterMap::CallCounter> call_counter_;
@ -265,7 +265,7 @@ class XdsClusterImplLb : public LoadBalancingPolicy {
bool shutting_down_ = false; bool shutting_down_ = false;
// The xds client. // The xds client.
RefCountedPtr<XdsClient> xds_client_; RefCountedPtr<GrpcXdsClient> xds_client_;
// The stats for client-side load reporting. // The stats for client-side load reporting.
RefCountedPtr<XdsClusterDropStats> drop_stats_; RefCountedPtr<XdsClusterDropStats> drop_stats_;
@ -357,8 +357,8 @@ XdsClusterImplLb::Picker::Picker(XdsClusterImplLb* xds_cluster_impl_lb,
RefCountedPtr<SubchannelPicker> picker) RefCountedPtr<SubchannelPicker> picker)
: call_counter_(xds_cluster_impl_lb->call_counter_), : call_counter_(xds_cluster_impl_lb->call_counter_),
max_concurrent_requests_( max_concurrent_requests_(
xds_cluster_impl_lb->config_->max_concurrent_requests()), xds_cluster_impl_lb->cluster_resource_->max_concurrent_requests),
drop_config_(xds_cluster_impl_lb->config_->drop_config()), drop_config_(xds_cluster_impl_lb->drop_config_),
drop_stats_(xds_cluster_impl_lb->drop_stats_), drop_stats_(xds_cluster_impl_lb->drop_stats_),
picker_(std::move(picker)) { picker_(std::move(picker)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
@ -423,7 +423,7 @@ LoadBalancingPolicy::PickResult XdsClusterImplLb::Picker::Pick(
// XdsClusterImplLb // XdsClusterImplLb
// //
XdsClusterImplLb::XdsClusterImplLb(RefCountedPtr<XdsClient> xds_client, XdsClusterImplLb::XdsClusterImplLb(RefCountedPtr<GrpcXdsClient> xds_client,
Args args) Args args)
: LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) { : LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
@ -445,6 +445,11 @@ void XdsClusterImplLb::ShutdownLocked() {
gpr_log(GPR_INFO, "[xds_cluster_impl_lb %p] shutting down", this); gpr_log(GPR_INFO, "[xds_cluster_impl_lb %p] shutting down", this);
} }
shutting_down_ = true; shutting_down_ = true;
ResetState();
xds_client_.reset(DEBUG_LOCATION, "XdsClusterImpl");
}
void XdsClusterImplLb::ResetState() {
// Remove the child policy's interested_parties pollset_set from the // Remove the child policy's interested_parties pollset_set from the
// xDS policy. // xDS policy.
if (child_policy_ != nullptr) { if (child_policy_ != nullptr) {
@ -456,7 +461,18 @@ void XdsClusterImplLb::ShutdownLocked() {
// the child. // the child.
picker_.reset(); picker_.reset();
drop_stats_.reset(); drop_stats_.reset();
xds_client_.reset(DEBUG_LOCATION, "XdsClusterImpl"); }
void XdsClusterImplLb::ReportTransientFailure(absl::Status status) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
gpr_log(GPR_INFO,
"[xds_cluster_impl_lb %p] reporting TRANSIENT_FAILURE: %s", this,
status.ToString().c_str());
}
ResetState();
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, status,
MakeRefCounted<TransientFailurePicker>(status));
} }
void XdsClusterImplLb::ExitIdleLocked() { void XdsClusterImplLb::ExitIdleLocked() {
@ -469,56 +485,174 @@ void XdsClusterImplLb::ResetBackoffLocked() {
if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked(); if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked();
} }
std::string GetEdsResourceName(const XdsClusterResource& cluster_resource) {
auto* eds = absl::get_if<XdsClusterResource::Eds>(&cluster_resource.type);
if (eds == nullptr) return "";
return eds->eds_service_name;
}
absl::Status XdsClusterImplLb::UpdateLocked(UpdateArgs args) { absl::Status XdsClusterImplLb::UpdateLocked(UpdateArgs args) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
gpr_log(GPR_INFO, "[xds_cluster_impl_lb %p] Received update", this); gpr_log(GPR_INFO, "[xds_cluster_impl_lb %p] Received update", this);
} }
// Update config. // Grab new LB policy config.
const bool is_initial_update = config_ == nullptr; auto new_config = args.config.TakeAsSubclass<XdsClusterImplLbConfig>();
auto old_config = std::move(config_); // Cluster name should never change, because the cds policy will assign a
config_ = args.config.TakeAsSubclass<XdsClusterImplLbConfig>(); // different priority child name if that happens, which means that this
// On initial update, create drop stats. // policy instance will get replaced instead of being updated.
if (is_initial_update) { if (config_ != nullptr) {
if (config_->lrs_load_reporting_server().has_value()) { GPR_ASSERT(config_->cluster_name() == new_config->cluster_name());
drop_stats_ = xds_client_->AddClusterDropStats( }
config_->lrs_load_reporting_server().value(), config_->cluster_name(), // Get xDS config.
config_->eds_service_name()); auto new_xds_config = args.args.GetObjectRef<XdsConfig>();
if (drop_stats_ == nullptr) { if (new_xds_config == nullptr) {
gpr_log(GPR_ERROR, // Should never happen.
"[xds_cluster_impl_lb %p] Failed to get cluster drop stats for " absl::Status status = absl::InternalError(
"LRS server %s, cluster %s, EDS service name %s, load " "xDS config not passed to xds_cluster_impl LB policy");
"reporting for drops will not be done.", ReportTransientFailure(status);
this, return status;
config_->lrs_load_reporting_server()->server_uri().c_str(), }
config_->cluster_name().c_str(), auto it = new_xds_config->clusters.find(new_config->cluster_name());
config_->eds_service_name().c_str()); if (it == new_xds_config->clusters.end() || !it->second.ok() ||
} it->second->cluster == nullptr) {
// Should never happen.
absl::Status status = absl::InternalError(absl::StrCat(
"xDS config has no entry for cluster ", new_config->cluster_name()));
ReportTransientFailure(status);
return status;
}
auto& new_cluster_config = *it->second;
auto* endpoint_config =
absl::get_if<XdsConfig::ClusterConfig::EndpointConfig>(
&new_cluster_config.children);
if (endpoint_config == nullptr) {
// Should never happen.
absl::Status status = absl::InternalError(
absl::StrCat("cluster config for ", new_config->cluster_name(),
" has no endpoint config"));
ReportTransientFailure(status);
return status;
}
auto xds_cert_provider =
MaybeCreateCertificateProviderLocked(*new_cluster_config.cluster);
if (!xds_cert_provider.ok()) {
// Should never happen.
ReportTransientFailure(xds_cert_provider.status());
return xds_cert_provider.status();
}
if (*xds_cert_provider != nullptr) {
args.args = args.args.SetObject(std::move(*xds_cert_provider));
}
// Now we've verified the new config is good.
// Get new and old (if any) EDS service name.
std::string new_eds_service_name =
GetEdsResourceName(*new_cluster_config.cluster);
std::string old_eds_service_name =
cluster_resource_ == nullptr ? ""
: GetEdsResourceName(*cluster_resource_);
// Update drop stats if needed.
// Note: We need a drop stats object whenever load reporting is enabled,
// even if we have no EDS drop config, because we also use it when
// reporting circuit breaker drops.
if (!new_cluster_config.cluster->lrs_load_reporting_server.has_value()) {
drop_stats_.reset();
} else if (cluster_resource_ == nullptr ||
old_eds_service_name != new_eds_service_name ||
cluster_resource_->lrs_load_reporting_server !=
new_cluster_config.cluster->lrs_load_reporting_server) {
drop_stats_ = xds_client_->AddClusterDropStats(
*new_cluster_config.cluster->lrs_load_reporting_server,
new_config->cluster_name(), new_eds_service_name);
if (drop_stats_ == nullptr) {
gpr_log(
GPR_ERROR,
"[xds_cluster_impl_lb %p] Failed to get cluster drop stats for "
"LRS server %s, cluster %s, EDS service name %s, load "
"reporting for drops will not be done.",
this,
new_cluster_config.cluster->lrs_load_reporting_server->server_uri()
.c_str(),
new_config->cluster_name().c_str(), new_eds_service_name.c_str());
} }
call_counter_ = g_call_counter_map->GetOrCreate(
config_->cluster_name(), config_->eds_service_name());
} else {
// Cluster name, EDS service name, and LRS server name should never
// change, because the xds_cluster_resolver policy above us should be
// swapped out if that happens.
GPR_ASSERT(config_->cluster_name() == old_config->cluster_name());
GPR_ASSERT(config_->eds_service_name() == old_config->eds_service_name());
GPR_ASSERT(config_->lrs_load_reporting_server() ==
old_config->lrs_load_reporting_server());
}
// Update picker if max_concurrent_requests has changed.
if (is_initial_update || config_->max_concurrent_requests() !=
old_config->max_concurrent_requests()) {
MaybeUpdatePickerLocked();
} }
// Update call counter if needed.
if (cluster_resource_ == nullptr ||
old_eds_service_name != new_eds_service_name) {
call_counter_ = g_call_counter_map->GetOrCreate(new_config->cluster_name(),
new_eds_service_name);
}
// Update config state, now that we're done comparing old and new fields.
config_ = std::move(new_config);
cluster_resource_ = new_cluster_config.cluster;
drop_config_ = endpoint_config->endpoints != nullptr
? endpoint_config->endpoints->drop_config
: nullptr;
// Update picker in case some dependent config field changed.
MaybeUpdatePickerLocked();
// Update child policy. // Update child policy.
return UpdateChildPolicyLocked(std::move(args.addresses), return UpdateChildPolicyLocked(std::move(args.addresses),
std::move(args.resolution_note), args.args); std::move(args.resolution_note), args.args);
} }
absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
XdsClusterImplLb::MaybeCreateCertificateProviderLocked(
const XdsClusterResource& cluster_resource) const {
// If the channel is not using XdsCreds, do nothing.
auto channel_credentials = channel_control_helper()->GetChannelCredentials();
if (channel_credentials == nullptr ||
channel_credentials->type() != XdsCredentials::Type()) {
return nullptr;
}
// Configure root cert.
absl::string_view root_provider_instance_name =
cluster_resource.common_tls_context.certificate_validation_context
.ca_certificate_provider_instance.instance_name;
absl::string_view root_cert_name =
cluster_resource.common_tls_context.certificate_validation_context
.ca_certificate_provider_instance.certificate_name;
RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider;
if (!root_provider_instance_name.empty()) {
root_cert_provider =
xds_client_->certificate_provider_store()
.CreateOrGetCertificateProvider(root_provider_instance_name);
if (root_cert_provider == nullptr) {
return absl::InternalError(
absl::StrCat("Certificate provider instance name: \"",
root_provider_instance_name, "\" not recognized."));
}
}
// Configure identity cert.
absl::string_view identity_provider_instance_name =
cluster_resource.common_tls_context.tls_certificate_provider_instance
.instance_name;
absl::string_view identity_cert_name =
cluster_resource.common_tls_context.tls_certificate_provider_instance
.certificate_name;
RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider;
if (!identity_provider_instance_name.empty()) {
identity_cert_provider =
xds_client_->certificate_provider_store()
.CreateOrGetCertificateProvider(identity_provider_instance_name);
if (identity_cert_provider == nullptr) {
return absl::InternalError(
absl::StrCat("Certificate provider instance name: \"",
identity_provider_instance_name, "\" not recognized."));
}
}
// Configure SAN matchers.
const std::vector<StringMatcher>& san_matchers =
cluster_resource.common_tls_context.certificate_validation_context
.match_subject_alt_names;
// Create xds cert provider.
return MakeRefCounted<XdsCertificateProvider>(
root_cert_provider, root_cert_name, identity_cert_provider,
identity_cert_name, san_matchers);
}
void XdsClusterImplLb::MaybeUpdatePickerLocked() { void XdsClusterImplLb::MaybeUpdatePickerLocked() {
// If we're dropping all calls, report READY, regardless of what (or // If we're dropping all calls, report READY, regardless of what (or
// whether) the child has reported. // whether) the child has reported.
if (config_->drop_config() != nullptr && config_->drop_config()->drop_all()) { if (drop_config_ != nullptr && drop_config_->drop_all()) {
auto drop_picker = MakeRefCounted<Picker>(this, picker_); auto drop_picker = MakeRefCounted<Picker>(this, picker_);
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
@ -601,28 +735,30 @@ RefCountedPtr<SubchannelInterface> XdsClusterImplLb::Helper::CreateSubchannel(
if (parent()->shutting_down_) return nullptr; if (parent()->shutting_down_) return nullptr;
// If load reporting is enabled, wrap the subchannel such that it // If load reporting is enabled, wrap the subchannel such that it
// includes the locality stats object, which will be used by the Picker. // includes the locality stats object, which will be used by the Picker.
if (parent()->config_->lrs_load_reporting_server().has_value()) { if (parent()->cluster_resource_->lrs_load_reporting_server.has_value()) {
auto locality_name = per_address_args.GetObjectRef<XdsLocalityName>(); auto locality_name = per_address_args.GetObjectRef<XdsLocalityName>();
RefCountedPtr<XdsClusterLocalityStats> locality_stats = RefCountedPtr<XdsClusterLocalityStats> locality_stats =
parent()->xds_client_->AddClusterLocalityStats( parent()->xds_client_->AddClusterLocalityStats(
parent()->config_->lrs_load_reporting_server().value(), parent()->cluster_resource_->lrs_load_reporting_server.value(),
parent()->config_->cluster_name(), parent()->config_->cluster_name(),
parent()->config_->eds_service_name(), std::move(locality_name)); GetEdsResourceName(*parent()->cluster_resource_),
std::move(locality_name));
if (locality_stats != nullptr) { if (locality_stats != nullptr) {
return MakeRefCounted<StatsSubchannelWrapper>( return MakeRefCounted<StatsSubchannelWrapper>(
parent()->channel_control_helper()->CreateSubchannel( parent()->channel_control_helper()->CreateSubchannel(
address, per_address_args, args), address, per_address_args, args),
std::move(locality_stats)); std::move(locality_stats));
} }
gpr_log( gpr_log(GPR_ERROR,
GPR_ERROR, "[xds_cluster_impl_lb %p] Failed to get locality stats object for "
"[xds_cluster_impl_lb %p] Failed to get locality stats object for " "LRS server %s, cluster %s, EDS service name %s; load reports will "
"LRS server %s, cluster %s, EDS service name %s; load reports will " "not be generated (not wrapping subchannel)",
"not be generated (not wrapping subchannel)", parent(),
parent(), parent()
parent()->config_->lrs_load_reporting_server()->server_uri().c_str(), ->cluster_resource_->lrs_load_reporting_server->server_uri()
parent()->config_->cluster_name().c_str(), .c_str(),
parent()->config_->eds_service_name().c_str()); parent()->config_->cluster_name().c_str(),
GetEdsResourceName(*parent()->cluster_resource_).c_str());
} }
// Load reporting not enabled, so don't wrap the subchannel. // Load reporting not enabled, so don't wrap the subchannel.
return parent()->channel_control_helper()->CreateSubchannel( return parent()->channel_control_helper()->CreateSubchannel(
@ -652,67 +788,31 @@ void XdsClusterImplLb::Helper::UpdateState(
// factory // factory
// //
struct DropCategory {
std::string category;
uint32_t requests_per_million;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<DropCategory>()
.Field("category", &DropCategory::category)
.Field("requests_per_million", &DropCategory::requests_per_million)
.Finish();
return loader;
}
};
const JsonLoaderInterface* XdsClusterImplLbConfig::JsonLoader(const JsonArgs&) { const JsonLoaderInterface* XdsClusterImplLbConfig::JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
JsonObjectLoader<XdsClusterImplLbConfig>() JsonObjectLoader<XdsClusterImplLbConfig>()
// Note: Some fields require custom processing, so they are // Note: Some fields require custom processing, so they are
// handled in JsonPostLoad() instead. // handled in JsonPostLoad() instead.
.Field("clusterName", &XdsClusterImplLbConfig::cluster_name_) .Field("clusterName", &XdsClusterImplLbConfig::cluster_name_)
.OptionalField("edsServiceName",
&XdsClusterImplLbConfig::eds_service_name_)
.OptionalField("lrsLoadReportingServer",
&XdsClusterImplLbConfig::lrs_load_reporting_server_)
.OptionalField("maxConcurrentRequests",
&XdsClusterImplLbConfig::max_concurrent_requests_)
.Finish(); .Finish();
return loader; return loader;
} }
void XdsClusterImplLbConfig::JsonPostLoad(const Json& json, void XdsClusterImplLbConfig::JsonPostLoad(const Json& json, const JsonArgs&,
const JsonArgs& args,
ValidationErrors* errors) { ValidationErrors* errors) {
// Parse "childPolicy" field. // Parse "childPolicy" field.
{ ValidationErrors::ScopedField field(errors, ".childPolicy");
ValidationErrors::ScopedField field(errors, ".childPolicy"); auto it = json.object().find("childPolicy");
auto it = json.object().find("childPolicy"); if (it == json.object().end()) {
if (it == json.object().end()) { errors->AddError("field not present");
errors->AddError("field not present"); } else {
auto lb_config =
CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig(
it->second);
if (!lb_config.ok()) {
errors->AddError(lb_config.status().message());
} else { } else {
auto lb_config = CoreConfiguration::Get() child_policy_ = std::move(*lb_config);
.lb_policy_registry()
.ParseLoadBalancingConfig(it->second);
if (!lb_config.ok()) {
errors->AddError(lb_config.status().message());
} else {
child_policy_ = std::move(*lb_config);
}
}
}
// Parse "dropCategories" field.
{
auto value = LoadJsonObjectField<std::vector<DropCategory>>(
json.object(), args, "dropCategories", errors, /*required=*/false);
if (value.has_value()) {
drop_config_ = MakeRefCounted<XdsEndpointResource::DropConfig>();
for (size_t i = 0; i < value->size(); ++i) {
DropCategory& drop_category = (*value)[i];
drop_config_->AddCategory(std::move(drop_category.category),
drop_category.requests_per_million);
}
} }
} }
} }

@ -40,7 +40,7 @@
#include "src/core/ext/filters/client_channel/client_channel_internal.h" #include "src/core/ext/filters/client_channel/client_channel_internal.h"
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h" #include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/debug/trace.h" #include "src/core/lib/debug/trace.h"

@ -48,6 +48,7 @@
#include "src/core/ext/filters/client_channel/client_channel_internal.h" #include "src/core/ext/filters/client_channel/client_channel_internal.h"
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h"
#include "src/core/ext/filters/stateful_session/stateful_session_filter.h" #include "src/core/ext/filters/stateful_session/stateful_session_filter.h"
#include "src/core/ext/xds/xds_health_status.h" #include "src/core/ext/xds/xds_health_status.h"
#include "src/core/lib/address_utils/sockaddr_utils.h" #include "src/core/lib/address_utils/sockaddr_utils.h"
@ -349,6 +350,9 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
void ShutdownLocked() override; void ShutdownLocked() override;
void ResetState();
void ReportTransientFailure(absl::Status status);
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked( OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
const ChannelArgs& args); const ChannelArgs& args);
@ -361,7 +365,7 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
RefCountedPtr<SubchannelInterface> subchannel); RefCountedPtr<SubchannelInterface> subchannel);
// Current config from the resolver. // Current config from the resolver.
RefCountedPtr<XdsOverrideHostLbConfig> config_; XdsHealthStatusSet override_host_status_set_;
// Internal state. // Internal state.
bool shutting_down_ = false; bool shutting_down_ = false;
@ -526,6 +530,10 @@ void XdsOverrideHostLb::ShutdownLocked() {
gpr_log(GPR_INFO, "[xds_override_host_lb %p] shutting down", this); gpr_log(GPR_INFO, "[xds_override_host_lb %p] shutting down", this);
} }
shutting_down_ = true; shutting_down_ = true;
ResetState();
}
void XdsOverrideHostLb::ResetState() {
{ {
// Drop subchannel refs after releasing the lock to avoid deadlock. // Drop subchannel refs after releasing the lock to avoid deadlock.
std::vector<SubchannelEntry::SubchannelPtr> subchannel_refs_to_drop; std::vector<SubchannelEntry::SubchannelPtr> subchannel_refs_to_drop;
@ -551,6 +559,18 @@ void XdsOverrideHostLb::ShutdownLocked() {
picker_.reset(); picker_.reset();
} }
void XdsOverrideHostLb::ReportTransientFailure(absl::Status status) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO,
"[xds_override_host_lb %p] reporting TRANSIENT_FAILURE: %s", this,
status.ToString().c_str());
}
ResetState();
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, status,
MakeRefCounted<TransientFailurePicker>(status));
}
void XdsOverrideHostLb::ExitIdleLocked() { void XdsOverrideHostLb::ExitIdleLocked() {
if (child_policy_ != nullptr) child_policy_->ExitIdleLocked(); if (child_policy_ != nullptr) child_policy_->ExitIdleLocked();
} }
@ -590,12 +610,35 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO, "[xds_override_host_lb %p] Received update", this); gpr_log(GPR_INFO, "[xds_override_host_lb %p] Received update", this);
} }
auto old_config = std::move(config_); // Grab new LB policy config.
// Update config. if (args.config == nullptr) {
config_ = args.config.TakeAsSubclass<XdsOverrideHostLbConfig>();
if (config_ == nullptr) {
return absl::InvalidArgumentError("Missing policy config"); return absl::InvalidArgumentError("Missing policy config");
} }
auto new_config = args.config.TakeAsSubclass<XdsOverrideHostLbConfig>();
// Get xDS config.
auto new_xds_config =
args.args.GetObjectRef<XdsDependencyManager::XdsConfig>();
if (new_xds_config == nullptr) {
// Should never happen.
absl::Status status = absl::InternalError(
"xDS config not passed to xds_cluster_impl LB policy");
ReportTransientFailure(status);
return status;
}
auto it = new_xds_config->clusters.find(new_config->cluster_name());
if (it == new_xds_config->clusters.end() || !it->second.ok() ||
it->second->cluster == nullptr) {
// Should never happen.
absl::Status status = absl::InternalError(absl::StrCat(
"xDS config has no entry for cluster ", new_config->cluster_name()));
ReportTransientFailure(status);
return status;
}
override_host_status_set_ = it->second->cluster->override_host_statuses;
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO, "[xds_override_host_lb %p] override host status set: %s",
this, override_host_status_set_.ToString().c_str());
}
// Update address map and wrap endpoint iterator for child policy. // Update address map and wrap endpoint iterator for child policy.
if (args.addresses.ok()) { if (args.addresses.ok()) {
UpdateAddressMap(**args.addresses); UpdateAddressMap(**args.addresses);
@ -615,7 +658,7 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
UpdateArgs update_args; UpdateArgs update_args;
update_args.addresses = std::move(args.addresses); update_args.addresses = std::move(args.addresses);
update_args.resolution_note = std::move(args.resolution_note); update_args.resolution_note = std::move(args.resolution_note);
update_args.config = config_->child_config(); update_args.config = new_config->child_config();
update_args.args = std::move(args.args); update_args.args = std::move(args.args);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
@ -627,9 +670,8 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
void XdsOverrideHostLb::MaybeUpdatePickerLocked() { void XdsOverrideHostLb::MaybeUpdatePickerLocked() {
if (picker_ != nullptr) { if (picker_ != nullptr) {
auto xds_override_host_picker = auto xds_override_host_picker = MakeRefCounted<Picker>(
MakeRefCounted<Picker>(RefAsSubclass<XdsOverrideHostLb>(), picker_, RefAsSubclass<XdsOverrideHostLb>(), picker_, override_host_status_set_);
config_->override_host_status_set());
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"[xds_override_host_lb %p] updating connectivity: state=%s " "[xds_override_host_lb %p] updating connectivity: state=%s "
@ -679,7 +721,7 @@ void XdsOverrideHostLb::UpdateAddressMap(
XdsHealthStatus status = GetEndpointHealthStatus(endpoint); XdsHealthStatus status = GetEndpointHealthStatus(endpoint);
// Skip draining hosts if not in the override status set. // Skip draining hosts if not in the override status set.
if (status.status() == XdsHealthStatus::kDraining && if (status.status() == XdsHealthStatus::kDraining &&
!config_->override_host_status_set().Contains(status)) { !override_host_status_set_.Contains(status)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"[xds_override_host_lb %p] endpoint %s: draining but not in " "[xds_override_host_lb %p] endpoint %s: draining but not in "
@ -795,6 +837,14 @@ XdsOverrideHostLb::AdoptSubchannel(
RefCountedPtr<SubchannelInterface> XdsOverrideHostLb::Helper::CreateSubchannel( RefCountedPtr<SubchannelInterface> XdsOverrideHostLb::Helper::CreateSubchannel(
const grpc_resolved_address& address, const ChannelArgs& per_address_args, const grpc_resolved_address& address, const ChannelArgs& per_address_args,
const ChannelArgs& args) { const ChannelArgs& args) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
auto key = grpc_sockaddr_to_string(&address, /*normalize=*/false);
gpr_log(GPR_INFO,
"[xds_override_host_lb %p] creating subchannel for %s, "
"per_address_args=%s, args=%s",
this, key.value_or("<unknown>").c_str(),
per_address_args.ToString().c_str(), args.ToString().c_str());
}
auto subchannel = parent()->channel_control_helper()->CreateSubchannel( auto subchannel = parent()->channel_control_helper()->CreateSubchannel(
address, per_address_args, args); address, per_address_args, args);
return parent()->AdoptSubchannel(address, std::move(subchannel)); return parent()->AdoptSubchannel(address, std::move(subchannel));
@ -921,50 +971,25 @@ const JsonLoaderInterface* XdsOverrideHostLbConfig::JsonLoader(
static const auto kJsonLoader = static const auto kJsonLoader =
JsonObjectLoader<XdsOverrideHostLbConfig>() JsonObjectLoader<XdsOverrideHostLbConfig>()
// Child policy config is parsed in JsonPostLoad // Child policy config is parsed in JsonPostLoad
.Field("clusterName", &XdsOverrideHostLbConfig::cluster_name_)
.Finish(); .Finish();
return kJsonLoader; return kJsonLoader;
} }
void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json, void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json, const JsonArgs&,
const JsonArgs& args,
ValidationErrors* errors) { ValidationErrors* errors) {
{ ValidationErrors::ScopedField field(errors, ".childPolicy");
ValidationErrors::ScopedField field(errors, ".childPolicy"); auto it = json.object().find("childPolicy");
auto it = json.object().find("childPolicy"); if (it == json.object().end()) {
if (it == json.object().end()) { errors->AddError("field not present");
errors->AddError("field not present"); } else {
} else { auto child_policy_config =
auto child_policy_config = CoreConfiguration::Get() CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig(
.lb_policy_registry() it->second);
.ParseLoadBalancingConfig(it->second); if (!child_policy_config.ok()) {
if (!child_policy_config.ok()) { errors->AddError(child_policy_config.status().message());
errors->AddError(child_policy_config.status().message());
} else {
child_config_ = std::move(*child_policy_config);
}
}
}
{
ValidationErrors::ScopedField field(errors, ".overrideHostStatus");
auto host_status_list = LoadJsonObjectField<std::vector<std::string>>(
json.object(), args, "overrideHostStatus", errors,
/*required=*/false);
if (host_status_list.has_value()) {
for (size_t i = 0; i < host_status_list->size(); ++i) {
const std::string& host_status = (*host_status_list)[i];
auto status = XdsHealthStatus::FromString(host_status);
if (!status.has_value()) {
ValidationErrors::ScopedField field(errors,
absl::StrCat("[", i, "]"));
errors->AddError("invalid host status");
} else {
override_host_status_set_.Add(*status);
}
}
} else { } else {
override_host_status_set_ = XdsHealthStatusSet( child_config_ = std::move(*child_policy_config);
{XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown)});
} }
} }
} }

@ -21,7 +21,6 @@
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "src/core/ext/xds/xds_health_status.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/validation_errors.h" #include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
@ -46,21 +45,18 @@ class XdsOverrideHostLbConfig : public LoadBalancingPolicy::Config {
absl::string_view name() const override { return Name(); } absl::string_view name() const override { return Name(); }
const std::string& cluster_name() const { return cluster_name_; }
RefCountedPtr<LoadBalancingPolicy::Config> child_config() const { RefCountedPtr<LoadBalancingPolicy::Config> child_config() const {
return child_config_; return child_config_;
} }
XdsHealthStatusSet override_host_status_set() const {
return override_host_status_set_;
}
static const JsonLoaderInterface* JsonLoader(const JsonArgs&); static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
void JsonPostLoad(const Json& json, const JsonArgs&, void JsonPostLoad(const Json& json, const JsonArgs&,
ValidationErrors* errors); ValidationErrors* errors);
private: private:
std::string cluster_name_;
RefCountedPtr<LoadBalancingPolicy::Config> child_config_; RefCountedPtr<LoadBalancingPolicy::Config> child_config_;
XdsHealthStatusSet override_host_status_set_;
}; };
} // namespace grpc_core } // namespace grpc_core

@ -0,0 +1,281 @@
//
// Copyright 2019 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_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_DEPENDENCY_MANAGER_H
#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_DEPENDENCY_MANAGER_H
#include <grpc/support/port_platform.h>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/xds/xds_client_grpc.h"
#include "src/core/ext/xds/xds_cluster.h"
#include "src/core/ext/xds/xds_endpoint.h"
#include "src/core/ext/xds/xds_listener.h"
#include "src/core/ext/xds/xds_route_config.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/resolver/resolver.h"
namespace grpc_core {
// Watches all xDS resources and handles dependencies between them.
// Reports updates only when all necessary resources have been obtained.
class XdsDependencyManager : public RefCounted<XdsDependencyManager>,
public Orphanable {
public:
struct XdsConfig : public RefCounted<XdsConfig> {
// Listener resource.
std::shared_ptr<const XdsListenerResource> listener;
// RouteConfig resource. Will be populated even if RouteConfig is
// inlined into the Listener resource.
std::shared_ptr<const XdsRouteConfigResource> route_config;
// Virtual host. Points into route_config. Will always be non-null.
const XdsRouteConfigResource::VirtualHost* virtual_host;
// Cluster map. A cluster will have a non-OK status if either
// (a) there was an error and we did not already have a valid
// resource or (b) the resource does not exist.
struct ClusterConfig {
// Cluster name and resource.
std::string cluster_name;
std::shared_ptr<const XdsClusterResource> cluster;
// Endpoint info. If there was an error, endpoints will be null
// and resolution_note will be set. Not used for aggregate clusters.
struct EndpointConfig {
std::shared_ptr<const XdsEndpointResource> endpoints;
std::string resolution_note;
EndpointConfig(std::shared_ptr<const XdsEndpointResource> endpoints,
std::string resolution_note)
: endpoints(std::move(endpoints)),
resolution_note(std::move(resolution_note)) {}
bool operator==(const EndpointConfig& other) const {
return endpoints == other.endpoints &&
resolution_note == other.resolution_note;
}
};
// The list of leaf clusters for an aggregate cluster.
struct AggregateConfig {
std::vector<absl::string_view> leaf_clusters;
explicit AggregateConfig(std::vector<absl::string_view> leaf_clusters)
: leaf_clusters(std::move(leaf_clusters)) {}
bool operator==(const AggregateConfig& other) const {
return leaf_clusters == other.leaf_clusters;
}
};
absl::variant<EndpointConfig, AggregateConfig> children;
// Ctor for leaf clusters.
ClusterConfig(std::string cluster_name,
std::shared_ptr<const XdsClusterResource> cluster,
std::shared_ptr<const XdsEndpointResource> endpoints,
std::string resolution_note);
// Ctor for aggregate clusters.
ClusterConfig(std::string cluster_name,
std::shared_ptr<const XdsClusterResource> cluster,
std::vector<absl::string_view> leaf_clusters);
bool operator==(const ClusterConfig& other) const {
return cluster_name == other.cluster_name && cluster == other.cluster &&
children == other.children;
}
};
absl::flat_hash_map<std::string, absl::StatusOr<ClusterConfig>> clusters;
std::string ToString() const;
static absl::string_view ChannelArgName() {
return GRPC_ARG_NO_SUBCHANNEL_PREFIX "xds_config";
}
static int ChannelArgsCompare(const XdsConfig* a, const XdsConfig* b) {
return QsortCompare(a, b);
}
static constexpr bool ChannelArgUseConstPtr() { return true; }
};
class Watcher {
public:
virtual ~Watcher() = default;
virtual void OnUpdate(RefCountedPtr<const XdsConfig> config) = 0;
// These methods are invoked when there is an error or
// does-not-exist on LDS or RDS only.
virtual void OnError(absl::string_view context, absl::Status status) = 0;
virtual void OnResourceDoesNotExist(std::string context) = 0;
};
class ClusterSubscription : public DualRefCounted<ClusterSubscription> {
public:
ClusterSubscription(absl::string_view cluster_name,
RefCountedPtr<XdsDependencyManager> dependency_mgr)
: cluster_name_(cluster_name),
dependency_mgr_(std::move(dependency_mgr)) {}
void Orphan() override;
absl::string_view cluster_name() const { return cluster_name_; }
private:
std::string cluster_name_;
RefCountedPtr<XdsDependencyManager> dependency_mgr_;
};
XdsDependencyManager(RefCountedPtr<GrpcXdsClient> xds_client,
std::shared_ptr<WorkSerializer> work_serializer,
std::unique_ptr<Watcher> watcher,
std::string data_plane_authority,
std::string listener_resource_name, ChannelArgs args,
grpc_pollset_set* interested_parties);
void Orphan() override;
// Gets an external cluster subscription. This allows us to include
// clusters in the config that are referenced by something other than
// the route config (e.g., RLS). The cluster will be included in the
// config as long as the returned object is still referenced.
RefCountedPtr<ClusterSubscription> GetClusterSubscription(
absl::string_view cluster_name);
static absl::string_view ChannelArgName() {
return GRPC_ARG_NO_SUBCHANNEL_PREFIX "xds_dependency_manager";
}
static int ChannelArgsCompare(const XdsDependencyManager* a,
const XdsDependencyManager* b) {
return QsortCompare(a, b);
}
private:
class ListenerWatcher;
class RouteConfigWatcher;
class ClusterWatcher;
class EndpointWatcher;
class DnsResultHandler;
struct ClusterWatcherState {
// Pointer to watcher, to be used when cancelling.
// Not owned, so do not dereference.
ClusterWatcher* watcher = nullptr;
// Most recent update obtained from this watcher.
absl::StatusOr<std::shared_ptr<const XdsClusterResource>> update = nullptr;
};
struct EndpointConfig {
// If there was an error, update will be null and resolution_note
// will be non-empty.
std::shared_ptr<const XdsEndpointResource> endpoints;
std::string resolution_note;
};
struct EndpointWatcherState {
// Pointer to watcher, to be used when cancelling.
// Not owned, so do not dereference.
EndpointWatcher* watcher = nullptr;
// Most recent update obtained from this watcher.
EndpointConfig update;
};
struct DnsState {
OrphanablePtr<Resolver> resolver;
// Most recent result from the resolver.
EndpointConfig update;
};
// Event handlers.
void OnListenerUpdate(std::shared_ptr<const XdsListenerResource> listener);
void OnRouteConfigUpdate(
const std::string& name,
std::shared_ptr<const XdsRouteConfigResource> route_config);
void OnError(std::string context, absl::Status status);
void OnResourceDoesNotExist(std::string context);
void OnClusterUpdate(const std::string& name,
std::shared_ptr<const XdsClusterResource> cluster);
void OnClusterError(const std::string& name, absl::Status status);
void OnClusterDoesNotExist(const std::string& name);
void OnEndpointUpdate(const std::string& name,
std::shared_ptr<const XdsEndpointResource> endpoint);
void OnEndpointError(const std::string& name, absl::Status status);
void OnEndpointDoesNotExist(const std::string& name);
void OnDnsResult(const std::string& dns_name, Resolver::Result result);
void PopulateDnsUpdate(const std::string& dns_name, Resolver::Result result,
DnsState* dns_state);
// Starts CDS and EDS/DNS watches for the specified cluster if needed.
// Adds an entry to cluster_config_map, which will contain the cluster
// data if the data is available.
// For each EDS cluster, adds the EDS resource to eds_resources_seen.
// For each Logical DNS cluster, adds the DNS hostname to dns_names_seen.
// For aggregate clusters, calls itself recursively. If leaf_clusters is
// non-null, populates it with a list of leaf clusters, or an error if
// max depth is exceeded.
// Returns true if all resources have been obtained.
bool PopulateClusterConfigMap(
absl::string_view name, int depth,
absl::flat_hash_map<std::string,
absl::StatusOr<XdsConfig::ClusterConfig>>*
cluster_config_map,
std::set<absl::string_view>* eds_resources_seen,
std::set<absl::string_view>* dns_names_seen,
absl::StatusOr<std::vector<absl::string_view>>* leaf_clusters = nullptr);
// Called when an external cluster subscription is unreffed.
void OnClusterSubscriptionUnref(absl::string_view cluster_name,
ClusterSubscription* subscription);
// Checks whether all necessary resources have been obtained, and if
// so reports an update to the watcher.
void MaybeReportUpdate();
// Parameters passed into ctor.
RefCountedPtr<GrpcXdsClient> xds_client_;
std::shared_ptr<WorkSerializer> work_serializer_;
std::unique_ptr<Watcher> watcher_;
const std::string data_plane_authority_;
const std::string listener_resource_name_;
ChannelArgs args_;
grpc_pollset_set* interested_parties_;
// Listener state.
ListenerWatcher* listener_watcher_ = nullptr;
std::shared_ptr<const XdsListenerResource> current_listener_;
std::string route_config_name_;
// RouteConfig state.
RouteConfigWatcher* route_config_watcher_ = nullptr;
std::shared_ptr<const XdsRouteConfigResource> current_route_config_;
const XdsRouteConfigResource::VirtualHost* current_virtual_host_ = nullptr;
absl::flat_hash_set<absl::string_view> clusters_from_route_config_;
// Cluster state.
absl::flat_hash_map<std::string, ClusterWatcherState> cluster_watchers_;
absl::flat_hash_map<absl::string_view, WeakRefCountedPtr<ClusterSubscription>>
cluster_subscriptions_;
// Endpoint state.
absl::flat_hash_map<std::string, EndpointWatcherState> endpoint_watchers_;
absl::flat_hash_map<std::string, DnsState> dns_resolvers_;
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_DEPENDENCY_MANAGER_H

@ -16,8 +16,6 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -53,9 +51,11 @@
#include "src/core/ext/filters/client_channel/client_channel_internal.h" #include "src/core/ext/filters/client_channel/client_channel_internal.h"
#include "src/core/ext/filters/client_channel/config_selector.h" #include "src/core/ext/filters/client_channel/config_selector.h"
#include "src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h" #include "src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h"
#include "src/core/ext/xds/xds_bootstrap.h" #include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/ext/xds/xds_bootstrap_grpc.h" #include "src/core/ext/xds/xds_bootstrap_grpc.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/ext/xds/xds_client_grpc.h" #include "src/core/ext/xds/xds_client_grpc.h"
#include "src/core/ext/xds/xds_http_filters.h" #include "src/core/ext/xds/xds_http_filters.h"
#include "src/core/ext/xds/xds_listener.h" #include "src/core/ext/xds/xds_listener.h"
@ -96,12 +96,8 @@
namespace grpc_core { namespace grpc_core {
TraceFlag grpc_xds_resolver_trace(false, "xds_resolver");
namespace { namespace {
using ReadDelayHandle = XdsClient::ReadDelayHandle;
// //
// XdsResolver // XdsResolver
// //
@ -139,87 +135,22 @@ class XdsResolver : public Resolver {
} }
private: private:
class ListenerWatcher : public XdsListenerResourceType::WatcherInterface { class XdsWatcher : public XdsDependencyManager::Watcher {
public: public:
explicit ListenerWatcher(RefCountedPtr<XdsResolver> resolver) explicit XdsWatcher(RefCountedPtr<XdsResolver> resolver)
: resolver_(std::move(resolver)) {} : resolver_(std::move(resolver)) {}
void OnResourceChanged(
std::shared_ptr<const XdsListenerResource> listener,
RefCountedPtr<ReadDelayHandle> read_delay_handle) override {
resolver_->work_serializer_->Run(
[self = RefAsSubclass<ListenerWatcher>(),
listener = std::move(listener),
read_delay_handle = std::move(read_delay_handle)]() mutable {
self->resolver_->OnListenerUpdate(std::move(listener));
},
DEBUG_LOCATION);
}
void OnError(absl::Status status,
RefCountedPtr<ReadDelayHandle> read_delay_handle) override {
resolver_->work_serializer_->Run(
[self = RefAsSubclass<ListenerWatcher>(), status = std::move(status),
read_delay_handle = std::move(read_delay_handle)]() mutable {
self->resolver_->OnError(self->resolver_->lds_resource_name_,
std::move(status));
},
DEBUG_LOCATION);
}
void OnResourceDoesNotExist(
RefCountedPtr<ReadDelayHandle> read_delay_handle) override {
resolver_->work_serializer_->Run(
[self = RefAsSubclass<ListenerWatcher>(),
read_delay_handle = std::move(read_delay_handle)]() {
self->resolver_->OnResourceDoesNotExist(
absl::StrCat(self->resolver_->lds_resource_name_,
": xDS listener resource does not exist"));
},
DEBUG_LOCATION);
}
private:
RefCountedPtr<XdsResolver> resolver_;
};
class RouteConfigWatcher void OnUpdate(
: public XdsRouteConfigResourceType::WatcherInterface { RefCountedPtr<const XdsDependencyManager::XdsConfig> config) override {
public: resolver_->OnUpdate(std::move(config));
explicit RouteConfigWatcher(RefCountedPtr<XdsResolver> resolver)
: resolver_(std::move(resolver)) {}
void OnResourceChanged(
std::shared_ptr<const XdsRouteConfigResource> route_config,
RefCountedPtr<ReadDelayHandle> read_delay_handle) override {
resolver_->work_serializer_->Run(
[self = RefAsSubclass<RouteConfigWatcher>(),
route_config = std::move(route_config),
read_delay_handle = std::move(read_delay_handle)]() mutable {
if (self != self->resolver_->route_config_watcher_) return;
self->resolver_->OnRouteConfigUpdate(std::move(route_config));
},
DEBUG_LOCATION);
} }
void OnError(absl::Status status,
RefCountedPtr<ReadDelayHandle> read_delay_handle) override { void OnError(absl::string_view context, absl::Status status) override {
resolver_->work_serializer_->Run( resolver_->OnError(context, std::move(status));
[self = RefAsSubclass<RouteConfigWatcher>(),
status = std::move(status),
read_delay_handle = std::move(read_delay_handle)]() mutable {
if (self != self->resolver_->route_config_watcher_) return;
self->resolver_->OnError(self->resolver_->route_config_name_,
std::move(status));
},
DEBUG_LOCATION);
} }
void OnResourceDoesNotExist(
RefCountedPtr<ReadDelayHandle> read_delay_handle) override { void OnResourceDoesNotExist(std::string context) override {
resolver_->work_serializer_->Run( resolver_->OnResourceDoesNotExist(std::move(context));
[self = RefAsSubclass<RouteConfigWatcher>(),
read_delay_handle = std::move(read_delay_handle)]() {
if (self != self->resolver_->route_config_watcher_) return;
self->resolver_->OnResourceDoesNotExist(absl::StrCat(
self->resolver_->route_config_name_,
": xDS route configuration resource does not exist"));
},
DEBUG_LOCATION);
} }
private: private:
@ -235,8 +166,12 @@ class XdsResolver : public Resolver {
class ClusterRef : public DualRefCounted<ClusterRef> { class ClusterRef : public DualRefCounted<ClusterRef> {
public: public:
ClusterRef(RefCountedPtr<XdsResolver> resolver, ClusterRef(RefCountedPtr<XdsResolver> resolver,
absl::string_view cluster_name) RefCountedPtr<XdsDependencyManager::ClusterSubscription>
: resolver_(std::move(resolver)), cluster_name_(cluster_name) {} cluster_subscription,
absl::string_view cluster_key)
: resolver_(std::move(resolver)),
cluster_subscription_(std::move(cluster_subscription)),
cluster_key_(cluster_key) {}
void Orphan() override { void Orphan() override {
XdsResolver* resolver_ptr = resolver_.get(); XdsResolver* resolver_ptr = resolver_.get();
@ -245,13 +180,16 @@ class XdsResolver : public Resolver {
resolver->MaybeRemoveUnusedClusters(); resolver->MaybeRemoveUnusedClusters();
}, },
DEBUG_LOCATION); DEBUG_LOCATION);
cluster_subscription_.reset();
} }
const std::string& cluster_name() const { return cluster_name_; } const std::string& cluster_key() const { return cluster_key_; }
private: private:
RefCountedPtr<XdsResolver> resolver_; RefCountedPtr<XdsResolver> resolver_;
std::string cluster_name_; RefCountedPtr<XdsDependencyManager::ClusterSubscription>
cluster_subscription_;
std::string cluster_key_;
}; };
// A routing data including cluster refs and routes table held by the // A routing data including cluster refs and routes table held by the
@ -288,9 +226,7 @@ class XdsResolver : public Resolver {
}; };
static absl::StatusOr<RefCountedPtr<RouteConfigData>> Create( static absl::StatusOr<RefCountedPtr<RouteConfigData>> Create(
XdsResolver* resolver, XdsResolver* resolver, const Duration& default_max_stream_duration);
const std::vector<XdsRouteConfigResource::Route>& routes,
const Duration& default_max_stream_duration);
bool operator==(const RouteConfigData& other) const { bool operator==(const RouteConfigData& other) const {
return clusters_ == other.clusters_ && routes_ == other.routes_; return clusters_ == other.clusters_ && routes_ == other.routes_;
@ -322,9 +258,9 @@ class XdsResolver : public Resolver {
return sc1->json_string() == sc2->json_string(); return sc1->json_string() == sc2->json_string();
} }
absl::Status AddRouteEntry(const XdsRouteConfigResource::Route& route, absl::Status AddRouteEntry(XdsResolver* resolver,
const Duration& default_max_stream_duration, const XdsRouteConfigResource::Route& route,
XdsResolver* resolver); const Duration& default_max_stream_duration);
std::map<absl::string_view, RefCountedPtr<ClusterRef>> clusters_; std::map<absl::string_view, RefCountedPtr<ClusterRef>> clusters_;
std::vector<RouteEntry> routes_; std::vector<RouteEntry> routes_;
@ -397,27 +333,31 @@ class XdsResolver : public Resolver {
}; };
RefCountedPtr<ClusterRef> GetOrCreateClusterRef( RefCountedPtr<ClusterRef> GetOrCreateClusterRef(
absl::string_view cluster_name) { absl::string_view cluster_key, absl::string_view cluster_name) {
auto it = cluster_ref_map_.find(cluster_name); auto it = cluster_ref_map_.find(cluster_key);
if (it == cluster_ref_map_.end()) { if (it == cluster_ref_map_.end()) {
auto cluster = MakeRefCounted<ClusterRef>(RefAsSubclass<XdsResolver>(), RefCountedPtr<XdsDependencyManager::ClusterSubscription> subscription;
cluster_name); if (!cluster_name.empty()) {
cluster_ref_map_.emplace(cluster->cluster_name(), cluster->WeakRef()); // The cluster ref will hold a subscription to ensure that the
// XdsDependencyManager stays subscribed to the CDS resource as
// long as the cluster ref exists.
subscription = dependency_mgr_->GetClusterSubscription(cluster_name);
}
auto cluster = MakeRefCounted<ClusterRef>(
RefAsSubclass<XdsResolver>(), std::move(subscription), cluster_key);
cluster_ref_map_.emplace(cluster->cluster_key(), cluster->WeakRef());
return cluster; return cluster;
} }
return it->second->Ref(); return it->second->Ref();
} }
void OnListenerUpdate(std::shared_ptr<const XdsListenerResource> listener); void OnUpdate(RefCountedPtr<const XdsDependencyManager::XdsConfig> config);
void OnRouteConfigUpdate(
std::shared_ptr<const XdsRouteConfigResource> rds_update);
void OnError(absl::string_view context, absl::Status status); void OnError(absl::string_view context, absl::Status status);
void OnResourceDoesNotExist(std::string context); void OnResourceDoesNotExist(std::string context);
absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateServiceConfig(); absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateServiceConfig();
void GenerateResult(); void GenerateResult();
void MaybeRemoveUnusedClusters(); void MaybeRemoveUnusedClusters();
uint64_t channel_id() const { return channel_id_; }
std::shared_ptr<WorkSerializer> work_serializer_; std::shared_ptr<WorkSerializer> work_serializer_;
std::unique_ptr<ResultHandler> result_handler_; std::unique_ptr<ResultHandler> result_handler_;
@ -427,17 +367,10 @@ class XdsResolver : public Resolver {
RefCountedPtr<GrpcXdsClient> xds_client_; RefCountedPtr<GrpcXdsClient> xds_client_;
std::string lds_resource_name_; std::string lds_resource_name_;
std::string data_plane_authority_; std::string data_plane_authority_;
uint64_t channel_id_; const uint64_t channel_id_;
ListenerWatcher* listener_watcher_ = nullptr;
std::shared_ptr<const XdsListenerResource> current_listener_;
std::string route_config_name_;
RouteConfigWatcher* route_config_watcher_ = nullptr;
std::shared_ptr<const XdsRouteConfigResource> current_route_config_;
const XdsRouteConfigResource::VirtualHost* current_virtual_host_ = nullptr;
OrphanablePtr<XdsDependencyManager> dependency_mgr_;
RefCountedPtr<const XdsDependencyManager::XdsConfig> current_config_;
std::map<absl::string_view, WeakRefCountedPtr<ClusterRef>> cluster_ref_map_; std::map<absl::string_view, WeakRefCountedPtr<ClusterRef>> cluster_ref_map_;
}; };
@ -470,19 +403,17 @@ class XdsResolver::RouteConfigData::RouteListIterator
absl::StatusOr<RefCountedPtr<XdsResolver::RouteConfigData>> absl::StatusOr<RefCountedPtr<XdsResolver::RouteConfigData>>
XdsResolver::RouteConfigData::Create( XdsResolver::RouteConfigData::Create(
XdsResolver* resolver, XdsResolver* resolver, const Duration& default_max_stream_duration) {
const std::vector<XdsRouteConfigResource::Route>& routes,
const Duration& default_max_stream_duration) {
auto data = MakeRefCounted<RouteConfigData>(); auto data = MakeRefCounted<RouteConfigData>();
// Reserve the necessary entries up-front to avoid reallocation as we add // Reserve the necessary entries up-front to avoid reallocation as we add
// elements. This is necessary because the string_view in the entry's // elements. This is necessary because the string_view in the entry's
// weighted_cluster_state field points to the memory in the route field, so // weighted_cluster_state field points to the memory in the route field, so
// moving the entry in a reallocation will cause the string_view to point to // moving the entry in a reallocation will cause the string_view to point to
// invalid data. // invalid data.
data->routes_.reserve(routes.size()); data->routes_.reserve(resolver->current_config_->virtual_host->routes.size());
for (auto& route : routes) { for (auto& route : resolver->current_config_->virtual_host->routes) {
absl::Status status = absl::Status status =
data->AddRouteEntry(route, default_max_stream_duration, resolver); data->AddRouteEntry(resolver, route, default_max_stream_duration);
if (!status.ok()) { if (!status.ok()) {
return status; return status;
} }
@ -555,12 +486,12 @@ XdsResolver::RouteConfigData::CreateMethodConfig(
} }
// Handle xDS HTTP filters. // Handle xDS HTTP filters.
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>( const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
resolver->current_listener_->listener); resolver->current_config_->listener->listener);
auto result = XdsRouting::GeneratePerHTTPFilterConfigs( auto result = XdsRouting::GeneratePerHTTPFilterConfigs(
static_cast<const GrpcXdsBootstrap&>(resolver->xds_client_->bootstrap()) static_cast<const GrpcXdsBootstrap&>(resolver->xds_client_->bootstrap())
.http_filter_registry(), .http_filter_registry(),
hcm.http_filters, *resolver->current_virtual_host_, route, cluster_weight, hcm.http_filters, *resolver->current_config_->virtual_host, route,
resolver->args_); cluster_weight, resolver->args_);
if (!result.ok()) return result.status(); if (!result.ok()) return result.status();
for (const auto& p : result->per_filter_configs) { for (const auto& p : result->per_filter_configs) {
fields.emplace_back(absl::StrCat(" \"", p.first, "\": [\n", fields.emplace_back(absl::StrCat(" \"", p.first, "\": [\n",
@ -585,19 +516,21 @@ XdsResolver::RouteConfigData::CreateMethodConfig(
} }
absl::Status XdsResolver::RouteConfigData::AddRouteEntry( absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
const XdsRouteConfigResource::Route& route, XdsResolver* resolver, const XdsRouteConfigResource::Route& route,
const Duration& default_max_stream_duration, XdsResolver* resolver) { const Duration& default_max_stream_duration) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] XdsConfigSelector %p: route: %s", gpr_log(GPR_INFO, "[xds_resolver %p] XdsConfigSelector %p: route: %s",
resolver, this, route.ToString().c_str()); resolver, this, route.ToString().c_str());
} }
routes_.emplace_back(route); routes_.emplace_back(route);
auto* route_entry = &routes_.back(); auto* route_entry = &routes_.back();
auto maybe_add_cluster = [&](absl::string_view cluster_name) { auto maybe_add_cluster = [&](absl::string_view cluster_key,
if (clusters_.find(cluster_name) != clusters_.end()) return; absl::string_view cluster_name) {
auto cluster_state = resolver->GetOrCreateClusterRef(cluster_name); if (clusters_.find(cluster_key) != clusters_.end()) return;
absl::string_view name = cluster_state->cluster_name(); auto cluster_state =
clusters_.emplace(name, std::move(cluster_state)); resolver->GetOrCreateClusterRef(cluster_key, cluster_name);
absl::string_view key = cluster_state->cluster_key();
clusters_.emplace(key, std::move(cluster_state));
}; };
auto* route_action = absl::get_if<XdsRouteConfigResource::Route::RouteAction>( auto* route_action = absl::get_if<XdsRouteConfigResource::Route::RouteAction>(
&route_entry->route.action); &route_entry->route.action);
@ -618,8 +551,8 @@ absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
return result.status(); return result.status();
} }
route_entry->method_config = std::move(*result); route_entry->method_config = std::move(*result);
maybe_add_cluster( maybe_add_cluster(absl::StrCat("cluster:", cluster_name.cluster_name),
absl::StrCat("cluster:", cluster_name.cluster_name)); cluster_name.cluster_name);
return absl::OkStatus(); return absl::OkStatus();
}, },
// WeightedClusters // WeightedClusters
@ -640,7 +573,8 @@ absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
cluster_weight_state.cluster = weighted_cluster.name; cluster_weight_state.cluster = weighted_cluster.name;
route_entry->weighted_cluster_state.push_back( route_entry->weighted_cluster_state.push_back(
std::move(cluster_weight_state)); std::move(cluster_weight_state));
maybe_add_cluster(absl::StrCat("cluster:", weighted_cluster.name)); maybe_add_cluster(absl::StrCat("cluster:", weighted_cluster.name),
weighted_cluster.name);
} }
return absl::OkStatus(); return absl::OkStatus();
}, },
@ -653,9 +587,11 @@ absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
return result.status(); return result.status();
} }
route_entry->method_config = std::move(*result); route_entry->method_config = std::move(*result);
maybe_add_cluster(absl::StrCat( maybe_add_cluster(
"cluster_specifier_plugin:", absl::StrCat(
cluster_specifier_plugin_name.cluster_specifier_plugin_name)); "cluster_specifier_plugin:",
cluster_specifier_plugin_name.cluster_specifier_plugin_name),
/*subscription_name=*/"");
return absl::OkStatus(); return absl::OkStatus();
}); });
if (!status.ok()) { if (!status.ok()) {
@ -683,7 +619,7 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector(
static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap()) static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap())
.http_filter_registry(); .http_filter_registry();
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>( const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
resolver_->current_listener_->listener); resolver_->current_config_->listener->listener);
for (const auto& http_filter : hcm.http_filters) { for (const auto& http_filter : hcm.http_filters) {
// Find filter. This is guaranteed to succeed, because it's checked // Find filter. This is guaranteed to succeed, because it's checked
// at config validation time in the XdsApi code. // at config validation time in the XdsApi code.
@ -814,7 +750,7 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig(
}, },
[&](const XdsRouteConfigResource::Route::RouteAction::HashPolicy:: [&](const XdsRouteConfigResource::Route::RouteAction::HashPolicy::
ChannelId&) -> absl::optional<uint64_t> { ChannelId&) -> absl::optional<uint64_t> {
return resolver_->channel_id(); return resolver_->channel_id_;
}); });
if (new_hash.has_value()) { if (new_hash.has_value()) {
// Rotating the old value prevents duplicate hash rules from cancelling // Rotating the old value prevents duplicate hash rules from cancelling
@ -840,7 +776,7 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig(
parsed_method_configs); parsed_method_configs);
} }
args.service_config_call_data->SetCallAttribute( args.service_config_call_data->SetCallAttribute(
args.arena->New<XdsClusterAttribute>(cluster->cluster_name())); args.arena->New<XdsClusterAttribute>(cluster->cluster_key()));
args.service_config_call_data->SetCallAttribute( args.service_config_call_data->SetCallAttribute(
args.arena->New<RequestHashAttribute>(*hash)); args.arena->New<RequestHashAttribute>(*hash));
args.service_config_call_data->SetCallAttribute( args.service_config_call_data->SetCallAttribute(
@ -944,6 +880,9 @@ void XdsResolver::StartLocked() {
return; return;
} }
xds_client_ = std::move(*xds_client); xds_client_ = std::move(*xds_client);
grpc_pollset_set_add_pollset_set(xds_client_->interested_parties(),
interested_parties_);
// Determine LDS resource name.
std::string resource_name_fragment(absl::StripPrefix(uri_.path(), "/")); std::string resource_name_fragment(absl::StripPrefix(uri_.path(), "/"));
if (!uri_.authority().empty()) { if (!uri_.authority().empty()) {
// target_uri.authority is set case // target_uri.authority is set case
@ -989,13 +928,11 @@ void XdsResolver::StartLocked() {
gpr_log(GPR_INFO, "[xds_resolver %p] Started with lds_resource_name %s.", gpr_log(GPR_INFO, "[xds_resolver %p] Started with lds_resource_name %s.",
this, lds_resource_name_.c_str()); this, lds_resource_name_.c_str());
} }
grpc_pollset_set_add_pollset_set( // Start watch for xDS config.
static_cast<GrpcXdsClient*>(xds_client_.get())->interested_parties(), dependency_mgr_ = MakeOrphanable<XdsDependencyManager>(
interested_parties_); xds_client_, work_serializer_,
auto watcher = MakeRefCounted<ListenerWatcher>(RefAsSubclass<XdsResolver>()); std::make_unique<XdsWatcher>(RefAsSubclass<XdsResolver>()),
listener_watcher_ = watcher.get(); data_plane_authority_, lds_resource_name_, args_, interested_parties_);
XdsListenerResourceType::StartWatch(xds_client_.get(), lds_resource_name_,
std::move(watcher));
} }
void XdsResolver::ShutdownLocked() { void XdsResolver::ShutdownLocked() {
@ -1003,122 +940,20 @@ void XdsResolver::ShutdownLocked() {
gpr_log(GPR_INFO, "[xds_resolver %p] shutting down", this); gpr_log(GPR_INFO, "[xds_resolver %p] shutting down", this);
} }
if (xds_client_ != nullptr) { if (xds_client_ != nullptr) {
if (listener_watcher_ != nullptr) { dependency_mgr_.reset();
XdsListenerResourceType::CancelWatch( grpc_pollset_set_del_pollset_set(xds_client_->interested_parties(),
xds_client_.get(), lds_resource_name_, listener_watcher_, interested_parties_);
/*delay_unsubscription=*/false);
}
if (route_config_watcher_ != nullptr) {
XdsRouteConfigResourceType::CancelWatch(
xds_client_.get(), route_config_name_, route_config_watcher_,
/*delay_unsubscription=*/false);
}
grpc_pollset_set_del_pollset_set(
static_cast<GrpcXdsClient*>(xds_client_.get())->interested_parties(),
interested_parties_);
xds_client_.reset(DEBUG_LOCATION, "xds resolver"); xds_client_.reset(DEBUG_LOCATION, "xds resolver");
} }
} }
void XdsResolver::OnListenerUpdate( void XdsResolver::OnUpdate(
std::shared_ptr<const XdsListenerResource> listener) { RefCountedPtr<const XdsDependencyManager::XdsConfig> config) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] received updated listener data", this);
}
if (xds_client_ == nullptr) return;
const auto* hcm = absl::get_if<XdsListenerResource::HttpConnectionManager>(
&listener->listener);
if (hcm == nullptr) {
return OnError(lds_resource_name_,
absl::UnavailableError("not an API listener"));
}
current_listener_ = std::move(listener);
Match(
hcm->route_config,
// RDS resource name
[&](const std::string& rds_name) {
// If the RDS name changed, update the RDS watcher.
// Note that this will be true on the initial update, because
// route_config_name_ will be empty.
if (route_config_name_ != rds_name) {
// If we already had a watch (i.e., if the previous config had
// a different RDS name), stop the previous watch.
// There will be no previous watch if either (a) this is the
// initial resource update or (b) the previous Listener had an
// inlined RouteConfig.
if (route_config_watcher_ != nullptr) {
XdsRouteConfigResourceType::CancelWatch(
xds_client_.get(), route_config_name_, route_config_watcher_,
/*delay_unsubscription=*/true);
route_config_watcher_ = nullptr;
}
// Start watch for the new RDS resource name.
route_config_name_ = rds_name;
auto watcher =
MakeRefCounted<RouteConfigWatcher>(RefAsSubclass<XdsResolver>());
route_config_watcher_ = watcher.get();
XdsRouteConfigResourceType::StartWatch(
xds_client_.get(), route_config_name_, std::move(watcher));
} else {
// RDS resource name has not changed, so no watch needs to be
// updated, but we still need to propagate any changes in the
// HCM config (e.g., the list of HTTP filters).
GenerateResult();
}
},
// inlined RouteConfig
[&](const std::shared_ptr<const XdsRouteConfigResource>& route_config) {
// If the previous update specified an RDS resource instead of
// having an inlined RouteConfig, we need to cancel the RDS watch.
if (route_config_watcher_ != nullptr) {
XdsRouteConfigResourceType::CancelWatch(
xds_client_.get(), route_config_name_, route_config_watcher_);
route_config_watcher_ = nullptr;
route_config_name_.clear();
}
OnRouteConfigUpdate(route_config);
});
}
class VirtualHostListIterator : public XdsRouting::VirtualHostListIterator {
public:
explicit VirtualHostListIterator(
const std::vector<XdsRouteConfigResource::VirtualHost>* virtual_hosts)
: virtual_hosts_(virtual_hosts) {}
size_t Size() const override { return virtual_hosts_->size(); }
const std::vector<std::string>& GetDomainsForVirtualHost(
size_t index) const override {
return (*virtual_hosts_)[index].domains;
}
private:
const std::vector<XdsRouteConfigResource::VirtualHost>* virtual_hosts_;
};
void XdsResolver::OnRouteConfigUpdate(
std::shared_ptr<const XdsRouteConfigResource> rds_update) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] received updated route config", this); gpr_log(GPR_INFO, "[xds_resolver %p] received updated xDS config", this);
} }
if (xds_client_ == nullptr) return; if (xds_client_ == nullptr) return;
// Find the relevant VirtualHost from the RouteConfiguration. current_config_ = std::move(config);
auto vhost_index = XdsRouting::FindVirtualHostForDomain(
VirtualHostListIterator(&rds_update->virtual_hosts),
data_plane_authority_);
if (!vhost_index.has_value()) {
OnError(
route_config_name_.empty() ? lds_resource_name_ : route_config_name_,
absl::UnavailableError(absl::StrCat("could not find VirtualHost for ",
data_plane_authority_,
" in RouteConfiguration")));
return;
}
// Save the virtual host in the resolver.
current_route_config_ = std::move(rds_update);
current_virtual_host_ = &current_route_config_->virtual_hosts[*vhost_index];
// Send a new result to the channel.
GenerateResult(); GenerateResult();
} }
@ -1142,7 +977,7 @@ void XdsResolver::OnResourceDoesNotExist(std::string context) {
"update and returning empty service config", "update and returning empty service config",
this); this);
if (xds_client_ == nullptr) return; if (xds_client_ == nullptr) return;
current_virtual_host_ = nullptr; current_config_.reset();
Result result; Result result;
result.addresses.emplace(); result.addresses.emplace();
result.service_config = ServiceConfigImpl::Create(args_, "{}"); result.service_config = ServiceConfigImpl::Create(args_, "{}");
@ -1163,7 +998,7 @@ XdsResolver::CreateServiceConfig() {
" \"childPolicy\": %s\n" " \"childPolicy\": %s\n"
" }", " }",
cluster.first, cluster.first,
current_route_config_->cluster_specifier_plugin_map.at( current_config_->route_config->cluster_specifier_plugin_map.at(
std::string(child_name)))); std::string(child_name))));
} else { } else {
absl::ConsumePrefix(&child_name, "cluster:"); absl::ConsumePrefix(&child_name, "cluster:");
@ -1195,13 +1030,13 @@ XdsResolver::CreateServiceConfig() {
} }
void XdsResolver::GenerateResult() { void XdsResolver::GenerateResult() {
if (current_virtual_host_ == nullptr) return; if (xds_client_ == nullptr || current_config_ == nullptr) return;
// First create XdsConfigSelector, which may add new entries to the cluster // First create XdsConfigSelector, which may add new entries to the cluster
// state map, and then CreateServiceConfig for LB policies. // state map.
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>( const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
current_listener_->listener); current_config_->listener->listener);
auto route_config_data = RouteConfigData::Create( auto route_config_data =
this, current_virtual_host_->routes, hcm.http_max_stream_duration); RouteConfigData::Create(this, hcm.http_max_stream_duration);
if (!route_config_data.ok()) { if (!route_config_data.ok()) {
OnError("could not create ConfigSelector", OnError("could not create ConfigSelector",
absl::UnavailableError(route_config_data.status().message())); absl::UnavailableError(route_config_data.status().message()));
@ -1209,6 +1044,7 @@ void XdsResolver::GenerateResult() {
} }
auto config_selector = MakeRefCounted<XdsConfigSelector>( auto config_selector = MakeRefCounted<XdsConfigSelector>(
RefAsSubclass<XdsResolver>(), std::move(*route_config_data)); RefAsSubclass<XdsResolver>(), std::move(*route_config_data));
// Now create the service config.
Result result; Result result;
result.addresses.emplace(); result.addresses.emplace();
result.service_config = CreateServiceConfig(); result.service_config = CreateServiceConfig();
@ -1220,7 +1056,9 @@ void XdsResolver::GenerateResult() {
} }
result.args = result.args =
args_.SetObject(xds_client_.Ref(DEBUG_LOCATION, "xds resolver result")) args_.SetObject(xds_client_.Ref(DEBUG_LOCATION, "xds resolver result"))
.SetObject(config_selector); .SetObject(config_selector)
.SetObject(current_config_)
.SetObject(dependency_mgr_->Ref());
result_handler_->ReportResult(std::move(result)); result_handler_->ReportResult(std::move(result));
} }
@ -1235,10 +1073,7 @@ void XdsResolver::MaybeRemoveUnusedClusters() {
it = cluster_ref_map_.erase(it); it = cluster_ref_map_.erase(it);
} }
} }
if (update_needed && xds_client_ != nullptr) { if (update_needed) GenerateResult();
// Send a new result to the channel.
GenerateResult();
}
} }
// //

@ -14,8 +14,8 @@
// limitations under the License. // limitations under the License.
// //
#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_H #ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_ATTRIBUTES_H
#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_H #define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_ATTRIBUTES_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
@ -49,13 +49,14 @@ class XdsRouteStateAttribute
: public ServiceConfigCallData::CallAttributeInterface { : public ServiceConfigCallData::CallAttributeInterface {
public: public:
static UniqueTypeName TypeName() { static UniqueTypeName TypeName() {
static UniqueTypeName::Factory factory("xds_cluster_lb_data"); static UniqueTypeName::Factory factory("xds_route_state");
return factory.Create(); return factory.Create();
} }
virtual bool HasClusterForRoute(absl::string_view cluster_name) const = 0; virtual bool HasClusterForRoute(absl::string_view cluster_name) const = 0;
UniqueTypeName type() const override { return TypeName(); } UniqueTypeName type() const override { return TypeName(); }
}; };
} // namespace grpc_core } // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_H #endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_ATTRIBUTES_H

@ -0,0 +1,25 @@
//
// Copyright 2019 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/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h"
namespace grpc_core {
TraceFlag grpc_xds_resolver_trace(false, "xds_resolver");
} // namespace grpc_core

@ -0,0 +1,30 @@
//
// Copyright 2019 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_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_TRACE_H
#define GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_TRACE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/debug/trace.h"
namespace grpc_core {
extern TraceFlag grpc_xds_resolver_trace;
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_TRACE_H

@ -38,7 +38,7 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h" #include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h"
#include "src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h" #include "src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h"
#include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/context.h" #include "src/core/lib/channel/context.h"

@ -53,6 +53,9 @@ class XdsBootstrap {
friend bool operator==(const XdsServer& a, const XdsServer& b) { friend bool operator==(const XdsServer& a, const XdsServer& b) {
return a.Equals(b); return a.Equals(b);
} }
friend bool operator!=(const XdsServer& a, const XdsServer& b) {
return !a.Equals(b);
}
}; };
class Authority { class Authority {

@ -43,16 +43,15 @@ class RootCertificatesWatcher
// presently, the watcher is immediately deleted when // presently, the watcher is immediately deleted when
// CancelTlsCertificatesWatch() is called, but that can potentially change in // CancelTlsCertificatesWatch() is called, but that can potentially change in
// the future. // the future.
RootCertificatesWatcher( explicit RootCertificatesWatcher(
RefCountedPtr<grpc_tls_certificate_distributor> parent, RefCountedPtr<grpc_tls_certificate_distributor> parent)
std::string cert_name) : parent_(std::move(parent)) {}
: parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
void OnCertificatesChanged(absl::optional<absl::string_view> root_certs, void OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList> absl::optional<PemKeyCertPairList>
/* key_cert_pairs */) override { /* key_cert_pairs */) override {
if (root_certs.has_value()) { if (root_certs.has_value()) {
parent_->SetKeyMaterials(cert_name_, std::string(root_certs.value()), parent_->SetKeyMaterials("", std::string(root_certs.value()),
absl::nullopt); absl::nullopt);
} }
} }
@ -60,14 +59,13 @@ class RootCertificatesWatcher
void OnError(grpc_error_handle root_cert_error, void OnError(grpc_error_handle root_cert_error,
grpc_error_handle /*identity_cert_error*/) override { grpc_error_handle /*identity_cert_error*/) override {
if (!root_cert_error.ok()) { if (!root_cert_error.ok()) {
parent_->SetErrorForCert(cert_name_, root_cert_error /* pass the ref */, parent_->SetErrorForCert("", root_cert_error /* pass the ref */,
absl::nullopt); absl::nullopt);
} }
} }
private: private:
RefCountedPtr<grpc_tls_certificate_distributor> parent_; RefCountedPtr<grpc_tls_certificate_distributor> parent_;
std::string cert_name_;
}; };
class IdentityCertificatesWatcher class IdentityCertificatesWatcher
@ -78,300 +76,142 @@ class IdentityCertificatesWatcher
// presently, the watcher is immediately deleted when // presently, the watcher is immediately deleted when
// CancelTlsCertificatesWatch() is called, but that can potentially change in // CancelTlsCertificatesWatch() is called, but that can potentially change in
// the future. // the future.
IdentityCertificatesWatcher( explicit IdentityCertificatesWatcher(
RefCountedPtr<grpc_tls_certificate_distributor> parent, RefCountedPtr<grpc_tls_certificate_distributor> parent)
std::string cert_name) : parent_(std::move(parent)) {}
: parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
void OnCertificatesChanged( void OnCertificatesChanged(
absl::optional<absl::string_view> /* root_certs */, absl::optional<absl::string_view> /* root_certs */,
absl::optional<PemKeyCertPairList> key_cert_pairs) override { absl::optional<PemKeyCertPairList> key_cert_pairs) override {
if (key_cert_pairs.has_value()) { if (key_cert_pairs.has_value()) {
parent_->SetKeyMaterials(cert_name_, absl::nullopt, key_cert_pairs); parent_->SetKeyMaterials("", absl::nullopt, key_cert_pairs);
} }
} }
void OnError(grpc_error_handle /*root_cert_error*/, void OnError(grpc_error_handle /*root_cert_error*/,
grpc_error_handle identity_cert_error) override { grpc_error_handle identity_cert_error) override {
if (!identity_cert_error.ok()) { if (!identity_cert_error.ok()) {
parent_->SetErrorForCert(cert_name_, absl::nullopt, parent_->SetErrorForCert("", absl::nullopt,
identity_cert_error /* pass the ref */); identity_cert_error /* pass the ref */);
} }
} }
private: private:
RefCountedPtr<grpc_tls_certificate_distributor> parent_; RefCountedPtr<grpc_tls_certificate_distributor> parent_;
std::string cert_name_;
}; };
} // namespace } // namespace
// //
// XdsCertificateProvider::ClusterCertificateState // XdsCertificateProvider
// //
XdsCertificateProvider::ClusterCertificateState::~ClusterCertificateState() { XdsCertificateProvider::XdsCertificateProvider(
if (root_cert_watcher_ != nullptr) { RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider,
root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_); absl::string_view root_cert_name,
} RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider,
if (identity_cert_watcher_ != nullptr) { absl::string_view identity_cert_name,
identity_cert_distributor_->CancelTlsCertificatesWatch( std::vector<StringMatcher> san_matchers)
identity_cert_watcher_); : distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()),
} root_cert_provider_(std::move(root_cert_provider)),
root_cert_name_(root_cert_name),
identity_cert_provider_(std::move(identity_cert_provider)),
identity_cert_name_(identity_cert_name),
san_matchers_(std::move(san_matchers)),
require_client_certificate_(false) {
distributor_->SetWatchStatusCallback(
absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
} }
bool XdsCertificateProvider::ClusterCertificateState::IsSafeToRemove() const { XdsCertificateProvider::XdsCertificateProvider(
return !watching_root_certs_ && !watching_identity_certs_ && RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider,
root_cert_distributor_ == nullptr && absl::string_view root_cert_name,
identity_cert_distributor_ == nullptr; RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider,
absl::string_view identity_cert_name, bool require_client_certificate)
: distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()),
root_cert_provider_(std::move(root_cert_provider)),
root_cert_name_(root_cert_name),
identity_cert_provider_(std::move(identity_cert_provider)),
identity_cert_name_(identity_cert_name),
require_client_certificate_(require_client_certificate) {
distributor_->SetWatchStatusCallback(
absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
} }
void XdsCertificateProvider::ClusterCertificateState:: XdsCertificateProvider::~XdsCertificateProvider() {
UpdateRootCertNameAndDistributor( distributor_->SetWatchStatusCallback(nullptr);
const std::string& cert_name, absl::string_view root_cert_name, }
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
if (root_cert_name_ == root_cert_name && UniqueTypeName XdsCertificateProvider::type() const {
root_cert_distributor_ == root_cert_distributor) { static UniqueTypeName::Factory kFactory("Xds");
return; return kFactory.Create();
} }
root_cert_name_ = std::string(root_cert_name);
if (watching_root_certs_) { void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
// The root certificates are being watched. Swap out the watcher. bool root_being_watched,
if (root_cert_distributor_ != nullptr) { bool identity_being_watched) {
root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_); if (!cert_name.empty()) {
} if (root_being_watched) {
if (root_cert_distributor != nullptr) { distributor_->SetErrorForCert(
UpdateRootCertWatcher(cert_name, root_cert_distributor.get()); cert_name,
} else {
root_cert_watcher_ = nullptr;
xds_certificate_provider_->distributor_->SetErrorForCert(
"",
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
"No certificate provider available for root certificates"), "No certificate provider available for root certificates"),
absl::nullopt); absl::nullopt);
} }
} if (identity_being_watched) {
// Swap out the root certificate distributor distributor_->SetErrorForCert(
root_cert_distributor_ = std::move(root_cert_distributor); cert_name, absl::nullopt,
}
void XdsCertificateProvider::ClusterCertificateState::
UpdateIdentityCertNameAndDistributor(
const std::string& cert_name, absl::string_view identity_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor>
identity_cert_distributor) {
if (identity_cert_name_ == identity_cert_name &&
identity_cert_distributor_ == identity_cert_distributor) {
return;
}
identity_cert_name_ = std::string(identity_cert_name);
if (watching_identity_certs_) {
// The identity certificates are being watched. Swap out the watcher.
if (identity_cert_distributor_ != nullptr) {
identity_cert_distributor_->CancelTlsCertificatesWatch(
identity_cert_watcher_);
}
if (identity_cert_distributor != nullptr) {
UpdateIdentityCertWatcher(cert_name, identity_cert_distributor.get());
} else {
identity_cert_watcher_ = nullptr;
xds_certificate_provider_->distributor_->SetErrorForCert(
"", absl::nullopt,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
"No certificate provider available for identity certificates")); "No certificate provider available for identity certificates"));
} }
return;
} }
// Swap out the identity certificate distributor
identity_cert_distributor_ = std::move(identity_cert_distributor);
}
void XdsCertificateProvider::ClusterCertificateState::UpdateRootCertWatcher(
const std::string& cert_name,
grpc_tls_certificate_distributor* root_cert_distributor) {
auto watcher = std::make_unique<RootCertificatesWatcher>(
xds_certificate_provider_->distributor_, cert_name);
root_cert_watcher_ = watcher.get();
root_cert_distributor->WatchTlsCertificates(std::move(watcher),
root_cert_name_, absl::nullopt);
}
void XdsCertificateProvider::ClusterCertificateState::UpdateIdentityCertWatcher(
const std::string& cert_name,
grpc_tls_certificate_distributor* identity_cert_distributor) {
auto watcher = std::make_unique<IdentityCertificatesWatcher>(
xds_certificate_provider_->distributor_, cert_name);
identity_cert_watcher_ = watcher.get();
identity_cert_distributor->WatchTlsCertificates(
std::move(watcher), absl::nullopt, identity_cert_name_);
}
void XdsCertificateProvider::ClusterCertificateState::WatchStatusCallback(
const std::string& cert_name, bool root_being_watched,
bool identity_being_watched) {
// We aren't specially handling the case where root_cert_distributor is same // We aren't specially handling the case where root_cert_distributor is same
// as identity_cert_distributor. Always using two separate watchers // as identity_cert_distributor. Always using two separate watchers
// irrespective of the fact results in a straightforward design, and using a // irrespective of the fact results in a straightforward design, and using a
// single watcher does not seem to provide any benefit other than cutting down // single watcher does not seem to provide any benefit other than cutting down
// on the number of callbacks. // on the number of callbacks.
if (root_being_watched && !watching_root_certs_) { if (root_being_watched && root_cert_watcher_ == nullptr) {
// We need to start watching root certs. // Start watching root cert.
watching_root_certs_ = true; if (root_cert_provider_ == nullptr) {
if (root_cert_distributor_ == nullptr) { distributor_->SetErrorForCert(
xds_certificate_provider_->distributor_->SetErrorForCert(
cert_name, cert_name,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
"No certificate provider available for root certificates"), "No certificate provider available for root certificates"),
absl::nullopt); absl::nullopt);
} else { } else {
UpdateRootCertWatcher(cert_name, root_cert_distributor_.get()); auto watcher = std::make_unique<RootCertificatesWatcher>(distributor_);
} root_cert_watcher_ = watcher.get();
} else if (!root_being_watched && watching_root_certs_) { root_cert_provider_->distributor()->WatchTlsCertificates(
// We need to cancel root certs watch. std::move(watcher), root_cert_name_, absl::nullopt);
watching_root_certs_ = false;
if (root_cert_distributor_ != nullptr) {
root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
root_cert_watcher_ = nullptr;
} }
GPR_ASSERT(root_cert_watcher_ == nullptr); } else if (!root_being_watched && root_cert_watcher_ != nullptr) {
} // Cancel root cert watch.
if (identity_being_watched && !watching_identity_certs_) { GPR_ASSERT(root_cert_provider_ != nullptr);
watching_identity_certs_ = true; root_cert_provider_->distributor()->CancelTlsCertificatesWatch(
if (identity_cert_distributor_ == nullptr) { root_cert_watcher_);
xds_certificate_provider_->distributor_->SetErrorForCert( root_cert_watcher_ = nullptr;
}
if (identity_being_watched && identity_cert_watcher_ == nullptr) {
// Start watching identity cert.
if (identity_cert_provider_ == nullptr) {
distributor_->SetErrorForCert(
cert_name, absl::nullopt, cert_name, absl::nullopt,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
"No certificate provider available for identity certificates")); "No certificate provider available for identity certificates"));
} else { } else {
UpdateIdentityCertWatcher(cert_name, identity_cert_distributor_.get()); auto watcher =
} std::make_unique<IdentityCertificatesWatcher>(distributor_);
} else if (!identity_being_watched && watching_identity_certs_) { identity_cert_watcher_ = watcher.get();
watching_identity_certs_ = false; identity_cert_provider_->distributor()->WatchTlsCertificates(
if (identity_cert_distributor_ != nullptr) { std::move(watcher), absl::nullopt, identity_cert_name_);
identity_cert_distributor_->CancelTlsCertificatesWatch(
identity_cert_watcher_);
identity_cert_watcher_ = nullptr;
} }
GPR_ASSERT(identity_cert_watcher_ == nullptr); } else if (!identity_being_watched && identity_cert_watcher_ != nullptr) {
} GPR_ASSERT(identity_cert_provider_ != nullptr);
} identity_cert_provider_->distributor()->CancelTlsCertificatesWatch(
identity_cert_watcher_);
// identity_cert_watcher_ = nullptr;
// XdsCertificateProvider
//
XdsCertificateProvider::XdsCertificateProvider()
: distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
distributor_->SetWatchStatusCallback(
absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
}
XdsCertificateProvider::~XdsCertificateProvider() {
distributor_->SetWatchStatusCallback(nullptr);
}
UniqueTypeName XdsCertificateProvider::type() const {
static UniqueTypeName::Factory kFactory("Xds");
return kFactory.Create();
}
bool XdsCertificateProvider::ProvidesRootCerts(const std::string& cert_name) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) return false;
return it->second->ProvidesRootCerts();
}
void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
const std::string& cert_name, absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) {
it =
certificate_state_map_
.emplace(cert_name, std::make_unique<ClusterCertificateState>(this))
.first;
}
it->second->UpdateRootCertNameAndDistributor(cert_name, root_cert_name,
root_cert_distributor);
// Delete unused entries.
if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
}
bool XdsCertificateProvider::ProvidesIdentityCerts(
const std::string& cert_name) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) return false;
return it->second->ProvidesIdentityCerts();
}
void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
const std::string& cert_name, absl::string_view identity_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) {
it =
certificate_state_map_
.emplace(cert_name, std::make_unique<ClusterCertificateState>(this))
.first;
}
it->second->UpdateIdentityCertNameAndDistributor(
cert_name, identity_cert_name, identity_cert_distributor);
// Delete unused entries.
if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
}
bool XdsCertificateProvider::GetRequireClientCertificate(
const std::string& cert_name) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) return false;
return it->second->require_client_certificate();
}
void XdsCertificateProvider::UpdateRequireClientCertificate(
const std::string& cert_name, bool require_client_certificate) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) return;
it->second->set_require_client_certificate(require_client_certificate);
}
std::vector<StringMatcher> XdsCertificateProvider::GetSanMatchers(
const std::string& cluster) {
MutexLock lock(&san_matchers_mu_);
auto it = san_matcher_map_.find(cluster);
if (it == san_matcher_map_.end()) return {};
return it->second;
}
void XdsCertificateProvider::UpdateSubjectAlternativeNameMatchers(
const std::string& cluster, std::vector<StringMatcher> matchers) {
MutexLock lock(&san_matchers_mu_);
if (matchers.empty()) {
san_matcher_map_.erase(cluster);
} else {
san_matcher_map_[cluster] = std::move(matchers);
}
}
void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
bool root_being_watched,
bool identity_being_watched) {
MutexLock lock(&mu_);
auto it = certificate_state_map_.find(cert_name);
if (it == certificate_state_map_.end()) {
it =
certificate_state_map_
.emplace(cert_name, std::make_unique<ClusterCertificateState>(this))
.first;
} }
it->second->WatchStatusCallback(cert_name, root_being_watched,
identity_being_watched);
// Delete unused entries.
if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
} }
} // namespace grpc_core } // namespace grpc_core

@ -44,7 +44,21 @@ namespace grpc_core {
class XdsCertificateProvider : public grpc_tls_certificate_provider { class XdsCertificateProvider : public grpc_tls_certificate_provider {
public: public:
XdsCertificateProvider(); // ctor for client side
XdsCertificateProvider(
RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider,
absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider,
absl::string_view identity_cert_name,
std::vector<StringMatcher> san_matchers);
// ctor for server side
XdsCertificateProvider(
RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider,
absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider,
absl::string_view identity_cert_name, bool require_client_certificate);
~XdsCertificateProvider() override; ~XdsCertificateProvider() override;
RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override { RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
@ -53,94 +67,27 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
UniqueTypeName type() const override; UniqueTypeName type() const override;
bool ProvidesRootCerts(const std::string& cert_name); bool ProvidesRootCerts() const { return root_cert_provider_ != nullptr; }
void UpdateRootCertNameAndDistributor( bool ProvidesIdentityCerts() const {
const std::string& cert_name, absl::string_view root_cert_name, return identity_cert_provider_ != nullptr;
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor); }
bool require_client_certificate() const {
bool ProvidesIdentityCerts(const std::string& cert_name); return require_client_certificate_;
void UpdateIdentityCertNameAndDistributor( }
const std::string& cert_name, absl::string_view identity_cert_name, const std::vector<StringMatcher>& san_matchers() const {
RefCountedPtr<grpc_tls_certificate_distributor> return san_matchers_;
identity_cert_distributor); }
bool GetRequireClientCertificate(const std::string& cert_name);
// Updating \a require_client_certificate for a non-existing \a cert_name has
// no effect.
void UpdateRequireClientCertificate(const std::string& cert_name,
bool require_client_certificate);
std::vector<StringMatcher> GetSanMatchers(const std::string& cluster);
void UpdateSubjectAlternativeNameMatchers(
const std::string& cluster, std::vector<StringMatcher> matchers);
static absl::string_view ChannelArgName() { static absl::string_view ChannelArgName() {
return "grpc.internal.xds_certificate_provider"; return "grpc.internal.xds_certificate_provider";
} }
static int ChannelArgsCompare(const XdsCertificateProvider* a, static int ChannelArgsCompare(const XdsCertificateProvider* a,
const XdsCertificateProvider* b) { const XdsCertificateProvider* b) {
if (a == nullptr || b == nullptr) return QsortCompare(a, b);
return a->Compare(b); return a->Compare(b);
} }
private: private:
class ClusterCertificateState {
public:
explicit ClusterCertificateState(
XdsCertificateProvider* xds_certificate_provider)
: xds_certificate_provider_(xds_certificate_provider) {}
~ClusterCertificateState();
// Returns true if the certs aren't being watched and there are no
// distributors configured.
bool IsSafeToRemove() const;
bool ProvidesRootCerts() const { return root_cert_distributor_ != nullptr; }
bool ProvidesIdentityCerts() const {
return identity_cert_distributor_ != nullptr;
}
void UpdateRootCertNameAndDistributor(
const std::string& cert_name, absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor);
void UpdateIdentityCertNameAndDistributor(
const std::string& cert_name, absl::string_view identity_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor>
identity_cert_distributor);
void UpdateRootCertWatcher(
const std::string& cert_name,
grpc_tls_certificate_distributor* root_cert_distributor);
void UpdateIdentityCertWatcher(
const std::string& cert_name,
grpc_tls_certificate_distributor* identity_cert_distributor);
bool require_client_certificate() const {
return require_client_certificate_;
}
void set_require_client_certificate(bool require_client_certificate) {
require_client_certificate_ = require_client_certificate;
}
void WatchStatusCallback(const std::string& cert_name,
bool root_being_watched,
bool identity_being_watched);
private:
XdsCertificateProvider* xds_certificate_provider_;
bool watching_root_certs_ = false;
bool watching_identity_certs_ = false;
std::string root_cert_name_;
std::string identity_cert_name_;
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor_;
RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor_;
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
root_cert_watcher_ = nullptr;
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
identity_cert_watcher_ = nullptr;
bool require_client_certificate_ = false;
};
int CompareImpl(const grpc_tls_certificate_provider* other) const override { int CompareImpl(const grpc_tls_certificate_provider* other) const override {
// TODO(yashykt): Maybe do something better here. // TODO(yashykt): Maybe do something better here.
return QsortCompare(static_cast<const grpc_tls_certificate_provider*>(this), return QsortCompare(static_cast<const grpc_tls_certificate_provider*>(this),
@ -151,22 +98,17 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
bool identity_being_watched); bool identity_being_watched);
RefCountedPtr<grpc_tls_certificate_distributor> distributor_; RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider_;
Mutex mu_; std::string root_cert_name_;
std::map<std::string /*cert_name*/, std::unique_ptr<ClusterCertificateState>> RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider_;
certificate_state_map_ ABSL_GUARDED_BY(mu_); std::string identity_cert_name_;
std::vector<StringMatcher> san_matchers_;
// Use a separate mutex for san_matchers_ to avoid deadlocks since bool require_client_certificate_ = false;
// san_matchers_ needs to be accessed when a handshake is being done and we
// run into a possible deadlock scenario if using the same mutex. The mutex grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
// deadlock cycle is formed as - root_cert_watcher_ = nullptr;
// WatchStatusCallback() -> SetKeyMaterials() -> grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
// TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnCertificatesChanged() identity_cert_watcher_ = nullptr;
// -> HandshakeManager::Add() -> SecurityHandshaker::DoHandshake() ->
// subject_alternative_names_matchers()
Mutex san_matchers_mu_;
std::map<std::string /*cluster_name*/, std::vector<StringMatcher>>
san_matcher_map_ ABSL_GUARDED_BY(san_matchers_mu_);
}; };
} // namespace grpc_core } // namespace grpc_core

@ -107,15 +107,8 @@ std::string XdsClusterResource::ToString() const {
} }
contents.push_back( contents.push_back(
absl::StrCat("max_concurrent_requests=", max_concurrent_requests)); absl::StrCat("max_concurrent_requests=", max_concurrent_requests));
if (!override_host_statuses.empty()) { contents.push_back(absl::StrCat("override_host_statuses=",
std::vector<const char*> statuses; override_host_statuses.ToString()));
statuses.reserve(override_host_statuses.size());
for (const auto& status : override_host_statuses) {
statuses.push_back(status.ToString());
}
contents.push_back(absl::StrCat("override_host_statuses={",
absl::StrJoin(statuses, ", "), "}"));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}"); return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
} }
@ -625,6 +618,7 @@ absl::StatusOr<std::shared_ptr<const XdsClusterResource>> CdsResourceParse(
// Validate override host status. // Validate override host status.
const auto* common_lb_config = const auto* common_lb_config =
envoy_config_cluster_v3_Cluster_common_lb_config(cluster); envoy_config_cluster_v3_Cluster_common_lb_config(cluster);
bool override_host_status_found = false;
if (common_lb_config != nullptr) { if (common_lb_config != nullptr) {
ValidationErrors::ScopedField field(&errors, ".common_lb_config"); ValidationErrors::ScopedField field(&errors, ".common_lb_config");
const auto* override_host_status = const auto* override_host_status =
@ -638,11 +632,19 @@ absl::StatusOr<std::shared_ptr<const XdsClusterResource>> CdsResourceParse(
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
auto status = XdsHealthStatus::FromUpb(statuses[i]); auto status = XdsHealthStatus::FromUpb(statuses[i]);
if (status.has_value()) { if (status.has_value()) {
cds_update->override_host_statuses.insert(*status); cds_update->override_host_statuses.Add(*status);
} }
} }
override_host_status_found = true;
} }
} }
// If the field is not set, we default to [UNKNOWN, HEALTHY].
if (!override_host_status_found) {
cds_update->override_host_statuses.Add(
XdsHealthStatus(XdsHealthStatus::kUnknown));
cds_update->override_host_statuses.Add(
XdsHealthStatus(XdsHealthStatus::kHealthy));
}
// Return result. // Return result.
if (!errors.ok()) { if (!errors.ok()) {
return errors.status(absl::StatusCode::kInvalidArgument, return errors.status(absl::StatusCode::kInvalidArgument,

@ -95,7 +95,7 @@ struct XdsClusterResource : public XdsResourceType::ResourceData {
absl::optional<OutlierDetectionConfig> outlier_detection; absl::optional<OutlierDetectionConfig> outlier_detection;
std::set<XdsHealthStatus> override_host_statuses; XdsHealthStatusSet override_host_statuses;
bool operator==(const XdsClusterResource& other) const { bool operator==(const XdsClusterResource& other) const {
return type == other.type && lb_policy_config == other.lb_policy_config && return type == other.type && lb_policy_config == other.lb_policy_config &&

@ -99,7 +99,10 @@ Json XdsRouteLookupClusterSpecifierPlugin::GenerateLoadBalancingPolicyConfig(
{"routeLookupConfig", std::move(*json)}, {"routeLookupConfig", std::move(*json)},
{"childPolicy", {"childPolicy",
Json::FromArray({ Json::FromArray({
Json::FromObject({{"cds_experimental", Json::FromObject({})}}), Json::FromObject({{"cds_experimental",
Json::FromObject({
{"isDynamic", Json::FromBool(true)},
})}}),
})}, })},
{"childPolicyConfigTargetFieldName", Json::FromString("cluster")}, {"childPolicyConfigTargetFieldName", Json::FromString("cluster")},
})}})}); })}})});

@ -20,6 +20,8 @@
#include <string> #include <string>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "envoy/config/core/v3/health_check.upb.h" #include "envoy/config/core/v3/health_check.upb.h"
namespace grpc_core { namespace grpc_core {
@ -58,8 +60,16 @@ const char* XdsHealthStatus::ToString() const {
} }
} }
bool operator<(const XdsHealthStatus& hs1, const XdsHealthStatus& hs2) { std::string XdsHealthStatusSet::ToString() const {
return hs1.status() < hs2.status(); std::vector<const char*> set;
set.reserve(3);
for (const auto& status :
{XdsHealthStatus::kUnknown, XdsHealthStatus::kHealthy,
XdsHealthStatus::kDraining}) {
const XdsHealthStatus health_status(status);
if (Contains(health_status)) set.push_back(health_status.ToString());
}
return absl::StrCat("{", absl::StrJoin(set, ", "), "}");
} }
} // namespace grpc_core } // namespace grpc_core

@ -70,6 +70,8 @@ class XdsHealthStatusSet {
return status_mask_ == other.status_mask_; return status_mask_ == other.status_mask_;
} }
bool Empty() const { return status_mask_ == 0; }
void Clear() { status_mask_ = 0; } void Clear() { status_mask_ = 0; }
void Add(XdsHealthStatus status) { status_mask_ |= (0x1 << status.status()); } void Add(XdsHealthStatus status) { status_mask_ |= (0x1 << status.status()); }
@ -78,12 +80,12 @@ class XdsHealthStatusSet {
return status_mask_ & (0x1 << status.status()); return status_mask_ & (0x1 << status.status());
} }
std::string ToString() const;
private: private:
int status_mask_ = 0; int status_mask_ = 0;
}; };
bool operator<(const XdsHealthStatus& hs1, const XdsHealthStatus& hs2);
} // namespace grpc_core } // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_XDS_XDS_HEALTH_STATUS_H #endif // GRPC_SRC_CORE_EXT_XDS_XDS_HEALTH_STATUS_H

@ -288,33 +288,44 @@ std::string XdsRouteConfigResource::Route::ToString() const {
return absl::StrJoin(contents, "\n"); return absl::StrJoin(contents, "\n");
} }
//
// XdsRouteConfigResource::Route
//
std::string XdsRouteConfigResource::VirtualHost::ToString() const {
std::vector<std::string> parts;
parts.push_back(
absl::StrCat("vhost={\n"
" domains=[",
absl::StrJoin(domains, ", "),
"]\n"
" routes=[\n"));
for (const XdsRouteConfigResource::Route& route : routes) {
parts.push_back(" {\n");
parts.push_back(route.ToString());
parts.push_back("\n }\n");
}
parts.push_back(" ]\n");
parts.push_back(" typed_per_filter_config={\n");
for (const auto& p : typed_per_filter_config) {
const std::string& name = p.first;
const auto& config = p.second;
parts.push_back(absl::StrCat(" ", name, "=", config.ToString(), "\n"));
}
parts.push_back(" }\n");
parts.push_back("}\n");
return absl::StrJoin(parts, "");
}
// //
// XdsRouteConfigResource // XdsRouteConfigResource
// //
std::string XdsRouteConfigResource::ToString() const { std::string XdsRouteConfigResource::ToString() const {
std::vector<std::string> parts; std::vector<std::string> parts;
parts.reserve(virtual_hosts.size());
for (const VirtualHost& vhost : virtual_hosts) { for (const VirtualHost& vhost : virtual_hosts) {
parts.push_back( parts.push_back(vhost.ToString());
absl::StrCat("vhost={\n"
" domains=[",
absl::StrJoin(vhost.domains, ", "),
"]\n"
" routes=[\n"));
for (const XdsRouteConfigResource::Route& route : vhost.routes) {
parts.push_back(" {\n");
parts.push_back(route.ToString());
parts.push_back("\n }\n");
}
parts.push_back(" ]\n");
parts.push_back(" typed_per_filter_config={\n");
for (const auto& p : vhost.typed_per_filter_config) {
const std::string& name = p.first;
const auto& config = p.second;
parts.push_back(absl::StrCat(" ", name, "=", config.ToString(), "\n"));
}
parts.push_back(" }\n");
parts.push_back("]\n");
} }
parts.push_back("cluster_specifier_plugins={\n"); parts.push_back("cluster_specifier_plugins={\n");
for (const auto& it : cluster_specifier_plugin_map) { for (const auto& it : cluster_specifier_plugin_map) {

@ -209,6 +209,7 @@ struct XdsRouteConfigResource : public XdsResourceType::ResourceData {
return domains == other.domains && routes == other.routes && return domains == other.domains && routes == other.routes &&
typed_per_filter_config == other.typed_per_filter_config; typed_per_filter_config == other.typed_per_filter_config;
} }
std::string ToString() const;
}; };
std::vector<VirtualHost> virtual_hosts; std::vector<VirtualHost> virtual_hosts;

@ -231,15 +231,6 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
} }
private: private:
struct CertificateProviders {
// We need to save our own refs to the root and instance certificate
// providers since the xds certificate provider just stores a ref to their
// distributors.
RefCountedPtr<grpc_tls_certificate_provider> root;
RefCountedPtr<grpc_tls_certificate_provider> instance;
RefCountedPtr<XdsCertificateProvider> xds;
};
class RouteConfigWatcher; class RouteConfigWatcher;
struct RdsUpdateState { struct RdsUpdateState {
RouteConfigWatcher* watcher; RouteConfigWatcher* watcher;
@ -277,7 +268,8 @@ class XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager
size_t rds_resources_yet_to_fetch_ ABSL_GUARDED_BY(mu_) = 0; size_t rds_resources_yet_to_fetch_ ABSL_GUARDED_BY(mu_) = 0;
std::map<std::string /* resource_name */, RdsUpdateState> rds_map_ std::map<std::string /* resource_name */, RdsUpdateState> rds_map_
ABSL_GUARDED_BY(mu_); ABSL_GUARDED_BY(mu_);
std::map<const XdsListenerResource::FilterChainData*, CertificateProviders> std::map<const XdsListenerResource::FilterChainData*,
RefCountedPtr<XdsCertificateProvider>>
certificate_providers_map_ ABSL_GUARDED_BY(mu_); certificate_providers_map_ ABSL_GUARDED_BY(mu_);
}; };
@ -809,10 +801,7 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
const XdsListenerResource::FilterChainData* filter_chain) { const XdsListenerResource::FilterChainData* filter_chain) {
MutexLock lock(&mu_); MutexLock lock(&mu_);
auto it = certificate_providers_map_.find(filter_chain); auto it = certificate_providers_map_.find(filter_chain);
if (it != certificate_providers_map_.end()) { if (it != certificate_providers_map_.end()) return it->second;
return it->second.xds;
}
CertificateProviders certificate_providers;
// Configure root cert. // Configure root cert.
absl::string_view root_provider_instance_name = absl::string_view root_provider_instance_name =
filter_chain->downstream_tls_context.common_tls_context filter_chain->downstream_tls_context.common_tls_context
@ -822,11 +811,12 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
filter_chain->downstream_tls_context.common_tls_context filter_chain->downstream_tls_context.common_tls_context
.certificate_validation_context.ca_certificate_provider_instance .certificate_validation_context.ca_certificate_provider_instance
.certificate_name; .certificate_name;
RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider;
if (!root_provider_instance_name.empty()) { if (!root_provider_instance_name.empty()) {
certificate_providers.root = root_cert_provider =
xds_client_->certificate_provider_store() xds_client_->certificate_provider_store()
.CreateOrGetCertificateProvider(root_provider_instance_name); .CreateOrGetCertificateProvider(root_provider_instance_name);
if (certificate_providers.root == nullptr) { if (root_cert_provider == nullptr) {
return absl::NotFoundError( return absl::NotFoundError(
absl::StrCat("Certificate provider instance name: \"", absl::StrCat("Certificate provider instance name: \"",
root_provider_instance_name, "\" not recognized.")); root_provider_instance_name, "\" not recognized."));
@ -839,33 +829,23 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
absl::string_view identity_provider_cert_name = absl::string_view identity_provider_cert_name =
filter_chain->downstream_tls_context.common_tls_context filter_chain->downstream_tls_context.common_tls_context
.tls_certificate_provider_instance.certificate_name; .tls_certificate_provider_instance.certificate_name;
RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider;
if (!identity_provider_instance_name.empty()) { if (!identity_provider_instance_name.empty()) {
certificate_providers.instance = identity_cert_provider =
xds_client_->certificate_provider_store() xds_client_->certificate_provider_store()
.CreateOrGetCertificateProvider(identity_provider_instance_name); .CreateOrGetCertificateProvider(identity_provider_instance_name);
if (certificate_providers.instance == nullptr) { if (identity_cert_provider == nullptr) {
return absl::NotFoundError( return absl::NotFoundError(
absl::StrCat("Certificate provider instance name: \"", absl::StrCat("Certificate provider instance name: \"",
identity_provider_instance_name, "\" not recognized.")); identity_provider_instance_name, "\" not recognized."));
} }
} }
certificate_providers.xds = MakeRefCounted<XdsCertificateProvider>(); auto xds_cert_provider = MakeRefCounted<XdsCertificateProvider>(
certificate_providers.xds->UpdateRootCertNameAndDistributor( std::move(root_cert_provider), root_provider_cert_name,
"", root_provider_cert_name, std::move(identity_cert_provider), identity_provider_cert_name,
certificate_providers.root == nullptr filter_chain->downstream_tls_context.require_client_certificate);
? nullptr certificate_providers_map_.emplace(filter_chain, xds_cert_provider);
: certificate_providers.root->distributor()); return xds_cert_provider;
certificate_providers.xds->UpdateIdentityCertNameAndDistributor(
"", identity_provider_cert_name,
certificate_providers.instance == nullptr
? nullptr
: certificate_providers.instance->distributor());
certificate_providers.xds->UpdateRequireClientCertificate(
"", filter_chain->downstream_tls_context.require_client_certificate);
auto xds_certificate_provider = certificate_providers.xds;
certificate_providers_map_.emplace(filter_chain,
std::move(certificate_providers));
return xds_certificate_provider;
} }
void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager:: void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::

@ -74,10 +74,8 @@ bool XdsVerifySubjectAlternativeNames(
// //
XdsCertificateVerifier::XdsCertificateVerifier( XdsCertificateVerifier::XdsCertificateVerifier(
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider, RefCountedPtr<XdsCertificateProvider> xds_certificate_provider)
std::string cluster_name) : xds_certificate_provider_(std::move(xds_certificate_provider)) {}
: xds_certificate_provider_(std::move(xds_certificate_provider)),
cluster_name_(std::move(cluster_name)) {}
bool XdsCertificateVerifier::Verify( bool XdsCertificateVerifier::Verify(
grpc_tls_custom_verification_check_request* request, grpc_tls_custom_verification_check_request* request,
@ -86,15 +84,15 @@ bool XdsCertificateVerifier::Verify(
if (!XdsVerifySubjectAlternativeNames( if (!XdsVerifySubjectAlternativeNames(
request->peer_info.san_names.uri_names, request->peer_info.san_names.uri_names,
request->peer_info.san_names.uri_names_size, request->peer_info.san_names.uri_names_size,
xds_certificate_provider_->GetSanMatchers(cluster_name_)) && xds_certificate_provider_->san_matchers()) &&
!XdsVerifySubjectAlternativeNames( !XdsVerifySubjectAlternativeNames(
request->peer_info.san_names.ip_names, request->peer_info.san_names.ip_names,
request->peer_info.san_names.ip_names_size, request->peer_info.san_names.ip_names_size,
xds_certificate_provider_->GetSanMatchers(cluster_name_)) && xds_certificate_provider_->san_matchers()) &&
!XdsVerifySubjectAlternativeNames( !XdsVerifySubjectAlternativeNames(
request->peer_info.san_names.dns_names, request->peer_info.san_names.dns_names,
request->peer_info.san_names.dns_names_size, request->peer_info.san_names.dns_names_size,
xds_certificate_provider_->GetSanMatchers(cluster_name_))) { xds_certificate_provider_->san_matchers())) {
*sync_status = absl::Status( *sync_status = absl::Status(
absl::StatusCode::kUnauthenticated, absl::StatusCode::kUnauthenticated,
"SANs from certificate did not match SANs from xDS control plane"); "SANs from certificate did not match SANs from xDS control plane");
@ -108,9 +106,12 @@ void XdsCertificateVerifier::Cancel(
int XdsCertificateVerifier::CompareImpl( int XdsCertificateVerifier::CompareImpl(
const grpc_tls_certificate_verifier* other) const { const grpc_tls_certificate_verifier* other) const {
auto* o = static_cast<const XdsCertificateVerifier*>(other); auto* o = static_cast<const XdsCertificateVerifier*>(other);
int r = QsortCompare(xds_certificate_provider_, o->xds_certificate_provider_); if (xds_certificate_provider_ == nullptr ||
if (r != 0) return r; o->xds_certificate_provider_ == nullptr) {
return cluster_name_.compare(o->cluster_name_); return QsortCompare(xds_certificate_provider_,
o->xds_certificate_provider_);
}
return xds_certificate_provider_->Compare(o->xds_certificate_provider_.get());
} }
UniqueTypeName XdsCertificateVerifier::type() const { UniqueTypeName XdsCertificateVerifier::type() const {
@ -140,12 +141,9 @@ XdsCredentials::create_security_connector(
RefCountedPtr<grpc_channel_security_connector> security_connector; RefCountedPtr<grpc_channel_security_connector> security_connector;
auto xds_certificate_provider = args->GetObjectRef<XdsCertificateProvider>(); auto xds_certificate_provider = args->GetObjectRef<XdsCertificateProvider>();
if (xds_certificate_provider != nullptr) { if (xds_certificate_provider != nullptr) {
std::string cluster_name( const bool watch_root = xds_certificate_provider->ProvidesRootCerts();
args->GetString(GRPC_ARG_XDS_CLUSTER_NAME).value());
const bool watch_root =
xds_certificate_provider->ProvidesRootCerts(cluster_name);
const bool watch_identity = const bool watch_identity =
xds_certificate_provider->ProvidesIdentityCerts(cluster_name); xds_certificate_provider->ProvidesIdentityCerts();
if (watch_root || watch_identity) { if (watch_root || watch_identity) {
auto tls_credentials_options = auto tls_credentials_options =
MakeRefCounted<grpc_tls_credentials_options>(); MakeRefCounted<grpc_tls_credentials_options>();
@ -153,16 +151,14 @@ XdsCredentials::create_security_connector(
xds_certificate_provider); xds_certificate_provider);
if (watch_root) { if (watch_root) {
tls_credentials_options->set_watch_root_cert(true); tls_credentials_options->set_watch_root_cert(true);
tls_credentials_options->set_root_cert_name(cluster_name);
} }
if (watch_identity) { if (watch_identity) {
tls_credentials_options->set_watch_identity_pair(true); tls_credentials_options->set_watch_identity_pair(true);
tls_credentials_options->set_identity_cert_name(cluster_name);
} }
tls_credentials_options->set_verify_server_cert(true); tls_credentials_options->set_verify_server_cert(true);
tls_credentials_options->set_certificate_verifier( tls_credentials_options->set_certificate_verifier(
MakeRefCounted<XdsCertificateVerifier>(xds_certificate_provider, MakeRefCounted<XdsCertificateVerifier>(
std::move(cluster_name))); std::move(xds_certificate_provider)));
tls_credentials_options->set_check_call_host(false); tls_credentials_options->set_check_call_host(false);
auto tls_credentials = auto tls_credentials =
MakeRefCounted<TlsCredentials>(std::move(tls_credentials_options)); MakeRefCounted<TlsCredentials>(std::move(tls_credentials_options));
@ -189,20 +185,17 @@ XdsServerCredentials::create_security_connector(const ChannelArgs& args) {
auto xds_certificate_provider = args.GetObjectRef<XdsCertificateProvider>(); auto xds_certificate_provider = args.GetObjectRef<XdsCertificateProvider>();
// Identity certs are a must for TLS. // Identity certs are a must for TLS.
if (xds_certificate_provider != nullptr && if (xds_certificate_provider != nullptr &&
xds_certificate_provider->ProvidesIdentityCerts("")) { xds_certificate_provider->ProvidesIdentityCerts()) {
auto tls_credentials_options = auto tls_credentials_options =
MakeRefCounted<grpc_tls_credentials_options>(); MakeRefCounted<grpc_tls_credentials_options>();
tls_credentials_options->set_watch_identity_pair(true); tls_credentials_options->set_watch_identity_pair(true);
tls_credentials_options->set_certificate_provider(xds_certificate_provider); tls_credentials_options->set_certificate_provider(xds_certificate_provider);
if (xds_certificate_provider->ProvidesRootCerts("")) { if (xds_certificate_provider->ProvidesRootCerts()) {
tls_credentials_options->set_watch_root_cert(true); tls_credentials_options->set_watch_root_cert(true);
if (xds_certificate_provider->GetRequireClientCertificate("")) { tls_credentials_options->set_cert_request_type(
tls_credentials_options->set_cert_request_type( xds_certificate_provider->require_client_certificate()
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY); ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
} else { : GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
tls_credentials_options->set_cert_request_type(
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
}
} else { } else {
// Do not request client certificate if there is no way to verify. // Do not request client certificate if there is no way to verify.
tls_credentials_options->set_cert_request_type( tls_credentials_options->set_cert_request_type(

@ -46,9 +46,8 @@ namespace grpc_core {
class XdsCertificateVerifier : public grpc_tls_certificate_verifier { class XdsCertificateVerifier : public grpc_tls_certificate_verifier {
public: public:
XdsCertificateVerifier( explicit XdsCertificateVerifier(
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider, RefCountedPtr<XdsCertificateProvider> xds_certificate_provider);
std::string cluster_name);
bool Verify(grpc_tls_custom_verification_check_request* request, bool Verify(grpc_tls_custom_verification_check_request* request,
std::function<void(absl::Status)>, std::function<void(absl::Status)>,
@ -61,7 +60,6 @@ class XdsCertificateVerifier : public grpc_tls_certificate_verifier {
int CompareImpl(const grpc_tls_certificate_verifier* other) const override; int CompareImpl(const grpc_tls_certificate_verifier* other) const override;
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider_; RefCountedPtr<XdsCertificateProvider> xds_certificate_provider_;
std::string cluster_name_;
}; };
class XdsCredentials final : public grpc_channel_credentials { class XdsCredentials final : public grpc_channel_credentials {

@ -34,8 +34,6 @@ extern void RegisterXdsClusterManagerLbPolicy(
CoreConfiguration::Builder* builder); CoreConfiguration::Builder* builder);
extern void RegisterXdsClusterImplLbPolicy(CoreConfiguration::Builder* builder); extern void RegisterXdsClusterImplLbPolicy(CoreConfiguration::Builder* builder);
extern void RegisterCdsLbPolicy(CoreConfiguration::Builder* builder); extern void RegisterCdsLbPolicy(CoreConfiguration::Builder* builder);
extern void RegisterXdsClusterResolverLbPolicy(
CoreConfiguration::Builder* builder);
extern void RegisterXdsOverrideHostLbPolicy( extern void RegisterXdsOverrideHostLbPolicy(
CoreConfiguration::Builder* builder); CoreConfiguration::Builder* builder);
extern void RegisterXdsWrrLocalityLbPolicy(CoreConfiguration::Builder* builder); extern void RegisterXdsWrrLocalityLbPolicy(CoreConfiguration::Builder* builder);
@ -58,7 +56,6 @@ void RegisterExtraFilters(CoreConfiguration::Builder* builder) {
RegisterXdsClusterManagerLbPolicy(builder); RegisterXdsClusterManagerLbPolicy(builder);
RegisterXdsClusterImplLbPolicy(builder); RegisterXdsClusterImplLbPolicy(builder);
RegisterCdsLbPolicy(builder); RegisterCdsLbPolicy(builder);
RegisterXdsClusterResolverLbPolicy(builder);
RegisterXdsOverrideHostLbPolicy(builder); RegisterXdsOverrideHostLbPolicy(builder);
RegisterXdsWrrLocalityLbPolicy(builder); RegisterXdsWrrLocalityLbPolicy(builder);
RegisterRingHashLbPolicy(builder); RegisterRingHashLbPolicy(builder);

@ -54,7 +54,6 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy/xds/cds.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/cds.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc', 'src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc',
'src/core/ext/filters/client_channel/local_subchannel_pool.cc', 'src/core/ext/filters/client_channel/local_subchannel_pool.cc',
@ -73,7 +72,9 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc', 'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc',
'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc',
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc', 'src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc',
'src/core/ext/filters/client_channel/retry_service_config.cc', 'src/core/ext/filters/client_channel/retry_service_config.cc',

@ -83,29 +83,6 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
EXPECT_EQ(lb_config->name(), "grpclb"); EXPECT_EQ(lb_config->name(), "grpclb");
} }
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
const char* test_json =
"{\n"
" \"loadBalancingConfig\":[\n"
" { \"does_not_exist\":{} },\n"
" { \"xds_cluster_resolver_experimental\":{\n"
" \"discoveryMechanisms\": [\n"
" { \"clusterName\": \"foo\",\n"
" \"type\": \"EDS\"\n"
" } ],\n"
" \"xdsLbPolicy\": [{\"round_robin\":{}}]\n"
" } }\n"
" ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
auto lb_config = parsed_config->parsed_lb_config();
EXPECT_EQ(lb_config->name(), "xds_cluster_resolver_experimental");
}
TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) { TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}"; const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json); auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
@ -163,15 +140,15 @@ TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
<< service_config.status(); << service_config.status();
} }
TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) { TEST_F(ClientChannelParserTest,
const char* test_json = LegacyLoadBalancingPolicySpecifiesPolicyThatRequiresConfig) {
"{\"loadBalancingPolicy\":\"xds_cluster_resolver_experimental\"}"; const char* test_json = "{\"loadBalancingPolicy\":\"rls_experimental\"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json); auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(), EXPECT_EQ(service_config.status().message(),
"errors validating service config: [" "errors validating service config: ["
"field:loadBalancingPolicy error:LB policy " "field:loadBalancingPolicy error:LB policy "
"\"xds_cluster_resolver_experimental\" requires a config. Please " "\"rls_experimental\" requires a config. Please "
"use loadBalancingConfig instead.]") "use loadBalancingConfig instead.]")
<< service_config.status(); << service_config.status();
} }

@ -542,7 +542,8 @@ class LoadBalancingPolicyTest : public ::testing::Test {
const ChannelArgs& /*per_address_args*/, const ChannelArgs& /*per_address_args*/,
const ChannelArgs& args) override { const ChannelArgs& args) override {
// TODO(roth): Need to use per_address_args here. // TODO(roth): Need to use per_address_args here.
SubchannelKey key(address, args); SubchannelKey key(
address, args.RemoveAllKeysWithPrefix(GRPC_ARG_NO_SUBCHANNEL_PREFIX));
auto it = test_->subchannel_pool_.find(key); auto it = test_->subchannel_pool_.find(key);
if (it == test_->subchannel_pool_.end()) { if (it == test_->subchannel_pool_.end()) {
auto address_uri = grpc_sockaddr_to_uri(&address); auto address_uri = grpc_sockaddr_to_uri(&address);
@ -771,11 +772,13 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// Constructs an update containing a list of endpoints. // Constructs an update containing a list of endpoints.
LoadBalancingPolicy::UpdateArgs BuildUpdate( LoadBalancingPolicy::UpdateArgs BuildUpdate(
absl::Span<const EndpointAddresses> endpoints, absl::Span<const EndpointAddresses> endpoints,
RefCountedPtr<LoadBalancingPolicy::Config> config) { RefCountedPtr<LoadBalancingPolicy::Config> config,
ChannelArgs args = ChannelArgs()) {
LoadBalancingPolicy::UpdateArgs update; LoadBalancingPolicy::UpdateArgs update;
update.addresses = std::make_shared<EndpointAddressesListIterator>( update.addresses = std::make_shared<EndpointAddressesListIterator>(
EndpointAddressesList(endpoints.begin(), endpoints.end())); EndpointAddressesList(endpoints.begin(), endpoints.end()));
update.config = std::move(config); update.config = std::move(config);
update.args = std::move(args);
return update; return update;
} }
@ -791,9 +794,10 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// Convenient overload that takes a flat address list. // Convenient overload that takes a flat address list.
LoadBalancingPolicy::UpdateArgs BuildUpdate( LoadBalancingPolicy::UpdateArgs BuildUpdate(
absl::Span<const absl::string_view> addresses, absl::Span<const absl::string_view> addresses,
RefCountedPtr<LoadBalancingPolicy::Config> config) { RefCountedPtr<LoadBalancingPolicy::Config> config,
ChannelArgs args = ChannelArgs()) {
return BuildUpdate(MakeEndpointAddressesListFromAddressList(addresses), return BuildUpdate(MakeEndpointAddressesListFromAddressList(addresses),
std::move(config)); std::move(config), std::move(args));
} }
// Applies the update on the LB policy. // Applies the update on the LB policy.
@ -1161,7 +1165,8 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// Expect startup with RR with a set of addresses. // Expect startup with RR with a set of addresses.
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> ExpectRoundRobinStartup( RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> ExpectRoundRobinStartup(
absl::Span<const EndpointAddresses> endpoints) { absl::Span<const EndpointAddresses> endpoints,
SourceLocation location = SourceLocation()) {
GPR_ASSERT(!endpoints.empty()); GPR_ASSERT(!endpoints.empty());
// There should be a subchannel for every address. // There should be a subchannel for every address.
// We will wind up connecting to the first address for every endpoint. // We will wind up connecting to the first address for every endpoint.
@ -1178,7 +1183,9 @@ class LoadBalancingPolicyTest : public ::testing::Test {
const grpc_resolved_address& address = endpoint.addresses()[i]; const grpc_resolved_address& address = endpoint.addresses()[i];
std::string address_str = grpc_sockaddr_to_uri(&address).value(); std::string address_str = grpc_sockaddr_to_uri(&address).value();
auto* subchannel = FindSubchannel(address_str); auto* subchannel = FindSubchannel(address_str);
EXPECT_NE(subchannel, nullptr); EXPECT_NE(subchannel, nullptr)
<< address_str << "\n"
<< location.file() << ":" << location.line();
if (subchannel == nullptr) return nullptr; if (subchannel == nullptr) return nullptr;
endpoint_subchannels.back().push_back(subchannel); endpoint_subchannels.back().push_back(subchannel);
if (i == 0) { if (i == 0) {
@ -1190,16 +1197,19 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// We should request a connection to the first address of each endpoint, // We should request a connection to the first address of each endpoint,
// and not to any of the subsequent addresses. // and not to any of the subsequent addresses.
for (const auto& subchannels : endpoint_subchannels) { for (const auto& subchannels : endpoint_subchannels) {
EXPECT_TRUE(subchannels[0]->ConnectionRequested()); EXPECT_TRUE(subchannels[0]->ConnectionRequested())
<< location.file() << ":" << location.line();
for (size_t i = 1; i < subchannels.size(); ++i) { for (size_t i = 1; i < subchannels.size(); ++i) {
EXPECT_FALSE(subchannels[i]->ConnectionRequested()); EXPECT_FALSE(subchannels[i]->ConnectionRequested())
<< "i=" << i << "\n"
<< location.file() << ":" << location.line();
} }
} }
// The subchannels that we've asked to connect should report // The subchannels that we've asked to connect should report
// CONNECTING state. // CONNECTING state.
for (size_t i = 0; i < endpoint_subchannels.size(); ++i) { for (size_t i = 0; i < endpoint_subchannels.size(); ++i) {
endpoint_subchannels[i][0]->SetConnectivityState(GRPC_CHANNEL_CONNECTING); endpoint_subchannels[i][0]->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
if (i == 0) ExpectConnectingUpdate(); if (i == 0) ExpectConnectingUpdate(location);
} }
// The connection attempts should succeed. // The connection attempts should succeed.
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> picker; RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> picker;
@ -1209,8 +1219,9 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// When the first subchannel becomes READY, accept any number of // When the first subchannel becomes READY, accept any number of
// CONNECTING updates with a picker that queues followed by a READY // CONNECTING updates with a picker that queues followed by a READY
// update with a picker that repeatedly returns only the first address. // update with a picker that repeatedly returns only the first address.
picker = WaitForConnected(); picker = WaitForConnected(location);
ExpectRoundRobinPicks(picker.get(), {chosen_addresses[0]}); ExpectRoundRobinPicks(picker.get(), {chosen_addresses[0]}, {}, 3,
location);
} else { } else {
// When each subsequent subchannel becomes READY, we accept any number // When each subsequent subchannel becomes READY, we accept any number
// of READY updates where the picker returns only the previously // of READY updates where the picker returns only the previously
@ -1219,7 +1230,8 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// connected subchannel. // connected subchannel.
picker = WaitForRoundRobinListChange( picker = WaitForRoundRobinListChange(
absl::MakeSpan(chosen_addresses).subspan(0, i), absl::MakeSpan(chosen_addresses).subspan(0, i),
absl::MakeSpan(chosen_addresses).subspan(0, i + 1)); absl::MakeSpan(chosen_addresses).subspan(0, i + 1), {}, 3,
location);
} }
} }
return picker; return picker;
@ -1228,9 +1240,10 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// A convenient override that takes a flat list of addresses, one per // A convenient override that takes a flat list of addresses, one per
// endpoint. // endpoint.
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> ExpectRoundRobinStartup( RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> ExpectRoundRobinStartup(
absl::Span<const absl::string_view> addresses) { absl::Span<const absl::string_view> addresses,
SourceLocation location = SourceLocation()) {
return ExpectRoundRobinStartup( return ExpectRoundRobinStartup(
MakeEndpointAddressesListFromAddressList(addresses)); MakeEndpointAddressesListFromAddressList(addresses), location);
} }
// Expects zero or more picker updates, each of which returns // Expects zero or more picker updates, each of which returns

@ -43,12 +43,10 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfig) {
"{\n" "{\n"
" \"loadBalancingConfig\":[{\n" " \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n" " \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":[\n" " \"childPolicy\":[\n"
" {\"grpclb\":{}}\n" " {\"grpclb\":{}}\n"
" ],\n" " ]\n"
" \"overrideHostStatus\": [\n"
" \"DRAINING\", \"HEALTHY\", \"UNKNOWN\""
" ]"
" }\n" " }\n"
" }]\n" " }]\n"
"}\n"; "}\n";
@ -64,16 +62,11 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfig) {
auto lb_config = global_config->parsed_lb_config(); auto lb_config = global_config->parsed_lb_config();
ASSERT_NE(lb_config, nullptr); ASSERT_NE(lb_config, nullptr);
ASSERT_EQ(lb_config->name(), XdsOverrideHostLbConfig::Name()); ASSERT_EQ(lb_config->name(), XdsOverrideHostLbConfig::Name());
auto override_host_lb_config = auto* override_host_lb_config =
lb_config.TakeAsSubclass<XdsOverrideHostLbConfig>(); static_cast<XdsOverrideHostLbConfig*>(lb_config.get());
EXPECT_EQ(override_host_lb_config->override_host_status_set(), EXPECT_EQ(override_host_lb_config->cluster_name(), "foo");
XdsHealthStatusSet({
XdsHealthStatus(XdsHealthStatus::HealthStatus::kDraining),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown),
}));
ASSERT_NE(override_host_lb_config->child_config(), nullptr); ASSERT_NE(override_host_lb_config->child_config(), nullptr);
ASSERT_EQ(override_host_lb_config->child_config()->name(), "grpclb"); EXPECT_EQ(override_host_lb_config->child_config()->name(), "grpclb");
} }
TEST(XdsOverrideHostConfigParsingTest, ValidConfigWithRR) { TEST(XdsOverrideHostConfigParsingTest, ValidConfigWithRR) {
@ -81,6 +74,7 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfigWithRR) {
"{\n" "{\n"
" \"loadBalancingConfig\":[{\n" " \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n" " \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":[\n" " \"childPolicy\":[\n"
" {\"round_robin\":{}}\n" " {\"round_robin\":{}}\n"
" ]\n" " ]\n"
@ -99,77 +93,32 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfigWithRR) {
auto lb_config = global_config->parsed_lb_config(); auto lb_config = global_config->parsed_lb_config();
ASSERT_NE(lb_config, nullptr); ASSERT_NE(lb_config, nullptr);
ASSERT_EQ(lb_config->name(), XdsOverrideHostLbConfig::Name()); ASSERT_EQ(lb_config->name(), XdsOverrideHostLbConfig::Name());
auto override_host_lb_config = auto* override_host_lb_config =
lb_config.TakeAsSubclass<XdsOverrideHostLbConfig>(); static_cast<XdsOverrideHostLbConfig*>(lb_config.get());
ASSERT_NE(override_host_lb_config->child_config(), nullptr); EXPECT_EQ(override_host_lb_config->cluster_name(), "foo");
ASSERT_EQ(override_host_lb_config->child_config()->name(), "round_robin");
}
TEST(XdsOverrideHostConfigParsingTest, ValidConfigNoDraining) {
const char* service_config_json =
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"childPolicy\":[\n"
" {\"grpclb\":{}}\n"
" ],\n"
" \"overrideHostStatus\": [\n"
" \"HEALTHY\", \"UNKNOWN\""
" ]"
" }\n"
" }]\n"
"}\n";
auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
ASSERT_TRUE(service_config.ok());
EXPECT_NE(*service_config, nullptr);
auto global_config = static_cast<ClientChannelGlobalParsedConfig*>(
(*service_config)
->GetGlobalParsedConfig(
ClientChannelServiceConfigParser::ParserIndex()));
ASSERT_NE(global_config, nullptr);
auto lb_config = global_config->parsed_lb_config();
ASSERT_NE(lb_config, nullptr);
ASSERT_EQ(lb_config->name(), XdsOverrideHostLbConfig::Name());
auto override_host_lb_config =
lb_config.TakeAsSubclass<XdsOverrideHostLbConfig>();
EXPECT_EQ(override_host_lb_config->override_host_status_set(),
XdsHealthStatusSet(
{XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown)}));
ASSERT_NE(override_host_lb_config->child_config(), nullptr); ASSERT_NE(override_host_lb_config->child_config(), nullptr);
ASSERT_EQ(override_host_lb_config->child_config()->name(), "grpclb"); EXPECT_EQ(override_host_lb_config->child_config()->name(), "round_robin");
} }
TEST(XdsOverrideHostConfigParsingTest, ValidConfigNoOverrideHostStatuses) { TEST(XdsOverrideHostConfigParsingTest, MissingClusterName) {
const char* service_config_json = const char* service_config_json =
"{\n" "{\n"
" \"loadBalancingConfig\":[{\n" " \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n" " \"xds_override_host_experimental\":{\n"
" \"childPolicy\":[\n" " \"childPolicy\":[\n"
" {\"grpclb\":{}}\n" " {\"round_robin\":{}}\n"
" ]" " ]\n"
" }\n" " }\n"
" }]\n" " }]\n"
"}\n"; "}\n";
auto service_config = auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
ASSERT_TRUE(service_config.ok()); ASSERT_FALSE(service_config.ok());
EXPECT_NE(*service_config, nullptr); EXPECT_EQ(service_config.status(),
auto global_config = static_cast<internal::ClientChannelGlobalParsedConfig*>( absl::InvalidArgumentError(
(*service_config)->GetGlobalParsedConfig(0)); "errors validating service config: [field:loadBalancingConfig "
ASSERT_NE(global_config, nullptr); "error:errors validating xds_override_host LB policy config: "
auto lb_config = global_config->parsed_lb_config(); "[field:clusterName error:field not present]]"));
ASSERT_NE(lb_config, nullptr);
ASSERT_EQ(lb_config->name(), XdsOverrideHostLbConfig::Name());
auto override_host_lb_config =
lb_config.TakeAsSubclass<XdsOverrideHostLbConfig>();
EXPECT_EQ(override_host_lb_config->override_host_status_set(),
XdsHealthStatusSet(
{XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown)}));
ASSERT_NE(override_host_lb_config->child_config(), nullptr);
EXPECT_EQ(override_host_lb_config->child_config()->name(), "grpclb");
} }
TEST(XdsOverrideHostConfigParsingTest, ReportsMissingChildPolicyField) { TEST(XdsOverrideHostConfigParsingTest, ReportsMissingChildPolicyField) {
@ -177,6 +126,7 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsMissingChildPolicyField) {
"{\n" "{\n"
" \"loadBalancingConfig\":[{\n" " \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n" " \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\"\n"
" }\n" " }\n"
" }]\n" " }]\n"
"}\n"; "}\n";
@ -195,6 +145,7 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsChildPolicyShouldBeArray) {
"{\n" "{\n"
" \"loadBalancingConfig\":[{\n" " \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n" " \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":{\n" " \"childPolicy\":{\n"
" \"grpclb\":{}\n" " \"grpclb\":{}\n"
" }\n" " }\n"
@ -216,6 +167,7 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsEmptyChildPolicyArray) {
"{\n" "{\n"
" \"loadBalancingConfig\":[{\n" " \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n" " \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":[\n" " \"childPolicy\":[\n"
" ]\n" " ]\n"
" }\n" " }\n"
@ -231,29 +183,6 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsEmptyChildPolicyArray) {
"[field:childPolicy error:No known policies in list: ]]")); "[field:childPolicy error:No known policies in list: ]]"));
} }
TEST(XdsOverrideHostConfigParsingTest, UnrecognizedHostStatus) {
const char* service_config_json =
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"childPolicy\":[\n"
" {\"grpclb\":{}}\n"
" ],\n"
" \"overrideHostStatus\": [\n"
" \"NOTASTATUS\""
" ]"
" }\n"
" }]\n"
"}\n";
auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
ASSERT_FALSE(service_config.ok()) << service_config.status();
EXPECT_EQ(service_config.status(),
absl::InvalidArgumentError(
"errors validating service config: [field:loadBalancingConfig "
"error:errors validating xds_override_host LB policy config: "
"[field:overrideHostStatus[0] error:invalid host status]]"));
}
} // namespace } // namespace
} // namespace testing } // namespace testing
} // namespace grpc_core } // namespace grpc_core

@ -37,6 +37,7 @@
#include <grpc/support/json.h> #include <grpc/support/json.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h"
#include "src/core/ext/filters/stateful_session/stateful_session_filter.h" #include "src/core/ext/filters/stateful_session/stateful_session_filter.h"
#include "src/core/ext/xds/xds_health_status.h" #include "src/core/ext/xds/xds_health_status.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
@ -57,31 +58,59 @@ class XdsOverrideHostTest : public LoadBalancingPolicyTest {
XdsOverrideHostTest() XdsOverrideHostTest()
: LoadBalancingPolicyTest("xds_override_host_experimental") {} : LoadBalancingPolicyTest("xds_override_host_experimental") {}
static RefCountedPtr<LoadBalancingPolicy::Config> MakeXdsOverrideHostConfig( static RefCountedPtr<const XdsDependencyManager::XdsConfig> MakeXdsConfig(
absl::Span<const absl::string_view> override_host_status = {"UNKNOWN", absl::Span<const absl::string_view> override_host_statuses = {"UNKNOWN",
"HEALTHY"}, "HEALTHY"},
std::string child_policy = "round_robin") { std::string cluster_name = "cluster_name") {
Json child_policy_config = auto cluster_resource = std::make_shared<XdsClusterResource>();
Json::FromObject({{child_policy, Json::FromObject({})}}); for (const absl::string_view host_status : override_host_statuses) {
Json::Array override_host_status_array; cluster_resource->override_host_statuses.Add(
for (const absl::string_view host_status : override_host_status) { XdsHealthStatus::FromString(host_status).value());
override_host_status_array.push_back(
Json::FromString(std::string(host_status)));
} }
return MakeConfig(Json::FromArray({Json::FromObject( auto xds_config = MakeRefCounted<XdsDependencyManager::XdsConfig>();
xds_config->clusters[cluster_name].emplace(
cluster_name, std::move(cluster_resource), nullptr, "");
return xds_config;
}
absl::Status UpdateXdsOverrideHostPolicy(
absl::Span<const EndpointAddresses> endpoints,
absl::Span<const absl::string_view> override_host_statuses = {"UNKNOWN",
"HEALTHY"},
std::string cluster_name = "cluster_name",
std::string child_policy = "round_robin") {
auto config = MakeConfig(Json::FromArray({Json::FromObject(
{{"xds_override_host_experimental", {{"xds_override_host_experimental",
Json::FromObject( Json::FromObject(
{{"childPolicy", Json::FromArray({child_policy_config})}, {{"clusterName", Json::FromString(cluster_name)},
{"overrideHostStatus", {"childPolicy",
Json::FromArray(override_host_status_array)}})}})})); Json::FromArray({Json::FromObject(
{{child_policy, Json::FromObject({})}})})}})}})}));
auto xds_config = MakeXdsConfig(override_host_statuses, cluster_name);
return ApplyUpdate(
BuildUpdate(endpoints, std::move(config),
ChannelArgs().SetObject(std::move(xds_config))),
lb_policy());
}
absl::Status UpdateXdsOverrideHostPolicy(
absl::Span<const absl::string_view> addresses,
absl::Span<const absl::string_view> override_host_statuses = {"UNKNOWN",
"HEALTHY"},
std::string cluster_name = "cluster_name",
std::string child_policy = "round_robin") {
return UpdateXdsOverrideHostPolicy(
MakeEndpointAddressesListFromAddressList(addresses),
override_host_statuses, std::move(cluster_name),
std::move(child_policy));
} }
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> RefCountedPtr<LoadBalancingPolicy::SubchannelPicker>
ExpectStartupWithRoundRobin(absl::Span<const absl::string_view> addresses) { ExpectStartupWithRoundRobin(absl::Span<const absl::string_view> addresses,
EXPECT_EQ(ApplyUpdate(BuildUpdate(addresses, MakeXdsOverrideHostConfig()), SourceLocation location = SourceLocation()) {
lb_policy()), EXPECT_EQ(UpdateXdsOverrideHostPolicy(addresses), absl::OkStatus())
absl::OkStatus()); << location.file() << ":" << location.line();
return ExpectRoundRobinStartup(addresses); return ExpectRoundRobinStartup(addresses, location);
} }
EndpointAddresses MakeAddressWithHealthStatus( EndpointAddresses MakeAddressWithHealthStatus(
@ -97,16 +126,13 @@ class XdsOverrideHostTest : public LoadBalancingPolicyTest {
addresses_and_statuses, addresses_and_statuses,
absl::Span<const absl::string_view> override_host_status = {"UNKNOWN", absl::Span<const absl::string_view> override_host_status = {"UNKNOWN",
"HEALTHY"}) { "HEALTHY"}) {
LoadBalancingPolicy::UpdateArgs update;
update.config = MakeXdsOverrideHostConfig(override_host_status);
EndpointAddressesList endpoints; EndpointAddressesList endpoints;
for (auto address_and_status : addresses_and_statuses) { for (auto address_and_status : addresses_and_statuses) {
endpoints.push_back(MakeAddressWithHealthStatus( endpoints.push_back(MakeAddressWithHealthStatus(
address_and_status.first, address_and_status.second)); address_and_status.first, address_and_status.second));
} }
update.addresses = EXPECT_EQ(UpdateXdsOverrideHostPolicy(endpoints, override_host_status),
std::make_shared<EndpointAddressesListIterator>(std::move(endpoints)); absl::OkStatus());
EXPECT_EQ(ApplyUpdate(update, lb_policy()), absl::OkStatus());
} }
struct OverrideHostAttributeStorage { struct OverrideHostAttributeStorage {
@ -233,9 +259,7 @@ TEST_F(XdsOverrideHostTest, SubchannelsComeAndGo) {
auto* address1_attribute = MakeOverrideHostAttribute(kAddresses[1]); auto* address1_attribute = MakeOverrideHostAttribute(kAddresses[1]);
ExpectOverridePicks(picker.get(), address1_attribute, kAddresses[1]); ExpectOverridePicks(picker.get(), address1_attribute, kAddresses[1]);
// The override address is removed. // The override address is removed.
EXPECT_EQ(ApplyUpdate(BuildUpdate({kAddresses[0], kAddresses[2]}, EXPECT_EQ(UpdateXdsOverrideHostPolicy({kAddresses[0], kAddresses[2]}),
MakeXdsOverrideHostConfig()),
lb_policy()),
absl::OkStatus()); absl::OkStatus());
picker = picker =
WaitForRoundRobinListChange(kAddresses, {kAddresses[0], kAddresses[2]}); WaitForRoundRobinListChange(kAddresses, {kAddresses[0], kAddresses[2]});
@ -244,9 +268,7 @@ TEST_F(XdsOverrideHostTest, SubchannelsComeAndGo) {
ExpectRoundRobinPicksWithAttribute(picker.get(), address1_attribute, ExpectRoundRobinPicksWithAttribute(picker.get(), address1_attribute,
{kAddresses[0], kAddresses[2]}); {kAddresses[0], kAddresses[2]});
// The override address comes back. // The override address comes back.
EXPECT_EQ(ApplyUpdate(BuildUpdate({kAddresses[1], kAddresses[2]}, EXPECT_EQ(UpdateXdsOverrideHostPolicy({kAddresses[1], kAddresses[2]}),
MakeXdsOverrideHostConfig()),
lb_policy()),
absl::OkStatus()); absl::OkStatus());
picker = WaitForRoundRobinListChange({kAddresses[0], kAddresses[2]}, picker = WaitForRoundRobinListChange({kAddresses[0], kAddresses[2]},
{kAddresses[1], kAddresses[2]}); {kAddresses[1], kAddresses[2]});
@ -475,9 +497,7 @@ TEST_F(XdsOverrideHostTest, MultipleAddressesPerEndpoint) {
MakeEndpointAddresses(kEndpoint1Addresses), MakeEndpointAddresses(kEndpoint1Addresses),
MakeEndpointAddresses(kEndpoint2Addresses), MakeEndpointAddresses(kEndpoint2Addresses),
MakeEndpointAddresses(kEndpoint3Addresses)}; MakeEndpointAddresses(kEndpoint3Addresses)};
EXPECT_EQ(ApplyUpdate(BuildUpdate(kEndpoints, MakeXdsOverrideHostConfig()), EXPECT_EQ(UpdateXdsOverrideHostPolicy(kEndpoints), absl::OkStatus());
lb_policy()),
absl::OkStatus());
auto picker = ExpectRoundRobinStartup(kEndpoints); auto picker = ExpectRoundRobinStartup(kEndpoints);
ASSERT_NE(picker, nullptr); ASSERT_NE(picker, nullptr);
// Check that the host is overridden. // Check that the host is overridden.

@ -75,7 +75,7 @@ TEST(TlsCredentialsOptionsComparatorTest, DifferentCertificateVerifier) {
auto* options_1 = grpc_tls_credentials_options_create(); auto* options_1 = grpc_tls_credentials_options_create();
auto* options_2 = grpc_tls_credentials_options_create(); auto* options_2 = grpc_tls_credentials_options_create();
options_1->set_certificate_verifier(MakeRefCounted<HostNameCertificateVerifier>()); options_1->set_certificate_verifier(MakeRefCounted<HostNameCertificateVerifier>());
options_2->set_certificate_verifier(MakeRefCounted<XdsCertificateVerifier>(nullptr, "")); options_2->set_certificate_verifier(MakeRefCounted<XdsCertificateVerifier>(nullptr));
EXPECT_FALSE(*options_1 == *options_2); EXPECT_FALSE(*options_1 == *options_2);
EXPECT_FALSE(*options_2 == *options_1); EXPECT_FALSE(*options_2 == *options_1);
delete options_1; delete options_1;

@ -290,24 +290,17 @@ TEST(XdsSanMatchingTest, RegexMatch) {
} }
TEST(XdsCertificateVerifierTest, CompareSuccess) { TEST(XdsCertificateVerifierTest, CompareSuccess) {
XdsCertificateVerifier verifier_1(nullptr, ""); XdsCertificateVerifier verifier_1(nullptr);
XdsCertificateVerifier verifier_2(nullptr, ""); XdsCertificateVerifier verifier_2(nullptr);
EXPECT_EQ(verifier_1.Compare(&verifier_2), 0); EXPECT_EQ(verifier_1.Compare(&verifier_2), 0);
EXPECT_EQ(verifier_2.Compare(&verifier_1), 0); EXPECT_EQ(verifier_2.Compare(&verifier_1), 0);
} }
TEST(XdsCertificateVerifierTest, CompareFailureDifferentCertificateProviders) { TEST(XdsCertificateVerifierTest, CompareFailureDifferentCertificateProviders) {
XdsCertificateVerifier verifier_1(MakeRefCounted<XdsCertificateProvider>(), XdsCertificateVerifier verifier_1(
""); MakeRefCounted<XdsCertificateProvider>(nullptr, "", nullptr, "", false));
XdsCertificateVerifier verifier_2(MakeRefCounted<XdsCertificateProvider>(), XdsCertificateVerifier verifier_2(
""); MakeRefCounted<XdsCertificateProvider>(nullptr, "", nullptr, "", false));
EXPECT_NE(verifier_1.Compare(&verifier_2), 0);
EXPECT_NE(verifier_2.Compare(&verifier_1), 0);
}
TEST(XdsCertificateVerifierTest, CompareFailureDifferentClusterNames) {
XdsCertificateVerifier verifier_1(nullptr, "cluster1");
XdsCertificateVerifier verifier_2(nullptr, "cluster2");
EXPECT_NE(verifier_1.Compare(&verifier_2), 0); EXPECT_NE(verifier_1.Compare(&verifier_2), 0);
EXPECT_NE(verifier_2.Compare(&verifier_1), 0); EXPECT_NE(verifier_2.Compare(&verifier_1), 0);
} }

@ -25,6 +25,7 @@
#include <grpc/grpc.h> #include <grpc/grpc.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/status_helper.h" #include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/error.h"
#include "src/core/lib/security/security_connector/ssl_utils.h" #include "src/core/lib/security/security_connector/ssl_utils.h"
@ -52,6 +53,28 @@ PemKeyCertPairList MakeKeyCertPairsType2() {
return MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2); return MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2);
} }
class TestCertProvider : public grpc_tls_certificate_provider {
public:
TestCertProvider()
: distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {}
UniqueTypeName type() const override {
static UniqueTypeName::Factory kFactory("Xds");
return kFactory.Create();
}
RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
return distributor_;
}
private:
int CompareImpl(const grpc_tls_certificate_provider* other) const override {
return QsortCompare(this, static_cast<const TestCertProvider*>(other));
}
RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
};
class TestCertificatesWatcher class TestCertificatesWatcher
: public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface { : public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
public: public:
@ -102,14 +125,10 @@ class TestCertificatesWatcher
TEST( TEST(
XdsCertificateProviderTest, XdsCertificateProviderTest,
RootCertDistributorDifferentFromIdentityCertDistributorDifferentCertNames) { RootCertDistributorDifferentFromIdentityCertDistributorDifferentCertNames) {
auto root_cert_distributor = auto root_provider = MakeRefCounted<TestCertProvider>();
MakeRefCounted<grpc_tls_certificate_distributor>(); auto identity_provider = MakeRefCounted<TestCertProvider>();
auto identity_cert_distributor = XdsCertificateProvider provider(root_provider, "root", identity_provider,
MakeRefCounted<grpc_tls_certificate_distributor>(); "identity", {});
XdsCertificateProvider provider;
provider.UpdateRootCertNameAndDistributor("", "root", root_cert_distributor);
provider.UpdateIdentityCertNameAndDistributor("", "identity",
identity_cert_distributor);
auto* watcher = new TestCertificatesWatcher; auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates( provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", ""); std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -118,15 +137,16 @@ TEST(
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Update both root certs and identity certs // Update both root certs and identity certs
root_cert_distributor->SetKeyMaterials("root", kRootCert1, absl::nullopt); root_provider->distributor()->SetKeyMaterials("root", kRootCert1,
identity_cert_distributor->SetKeyMaterials("identity", absl::nullopt, absl::nullopt);
MakeKeyCertPairsType1()); identity_provider->distributor()->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1); EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Second update for just root certs // Second update for just root certs
root_cert_distributor->SetKeyMaterials( root_provider->distributor()->SetKeyMaterials(
"root", kRootCert2, "root", kRootCert2,
MakeKeyCertPairsType2() /* does not have an effect */); MakeKeyCertPairsType2() /* does not have an effect */);
EXPECT_EQ(watcher->root_certs(), kRootCert2); EXPECT_EQ(watcher->root_certs(), kRootCert2);
@ -134,7 +154,7 @@ TEST(
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Second update for identity certs // Second update for identity certs
identity_cert_distributor->SetKeyMaterials( identity_provider->distributor()->SetKeyMaterials(
"identity", kRootCert1 /* does not have an effect */, "identity", kRootCert1 /* does not have an effect */,
MakeKeyCertPairsType2()); MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_certs(), kRootCert2); EXPECT_EQ(watcher->root_certs(), kRootCert2);
@ -142,9 +162,9 @@ TEST(
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Set error for both root and identity // Set error for both root and identity
root_cert_distributor->SetErrorForCert( root_provider->distributor()->SetErrorForCert(
"root", GRPC_ERROR_CREATE(kRootErrorMessage), absl::nullopt); "root", GRPC_ERROR_CREATE(kRootErrorMessage), absl::nullopt);
identity_cert_distributor->SetErrorForCert( identity_provider->distributor()->SetErrorForCert(
"identity", absl::nullopt, GRPC_ERROR_CREATE(kIdentityErrorMessage)); "identity", absl::nullopt, GRPC_ERROR_CREATE(kIdentityErrorMessage));
EXPECT_EQ(watcher->root_certs(), kRootCert2); EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
@ -153,7 +173,8 @@ TEST(
EXPECT_THAT(StatusToString(watcher->identity_cert_error()), EXPECT_THAT(StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(kIdentityErrorMessage)); ::testing::HasSubstr(kIdentityErrorMessage));
// Send an update for root certs. Test that the root cert error is reset. // Send an update for root certs. Test that the root cert error is reset.
root_cert_distributor->SetKeyMaterials("root", kRootCert1, absl::nullopt); root_provider->distributor()->SetKeyMaterials("root", kRootCert1,
absl::nullopt);
EXPECT_EQ(watcher->root_certs(), kRootCert1); EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
@ -161,8 +182,8 @@ TEST(
::testing::HasSubstr(kIdentityErrorMessage)); ::testing::HasSubstr(kIdentityErrorMessage));
// Send an update for identity certs. Test that the identity cert error is // Send an update for identity certs. Test that the identity cert error is
// reset. // reset.
identity_cert_distributor->SetKeyMaterials("identity", absl::nullopt, identity_provider->distributor()->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1()); MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1); EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
@ -171,14 +192,10 @@ TEST(
TEST(XdsCertificateProviderTest, TEST(XdsCertificateProviderTest,
RootCertDistributorDifferentFromIdentityCertDistributorSameCertNames) { RootCertDistributorDifferentFromIdentityCertDistributorSameCertNames) {
auto root_cert_distributor = auto root_provider = MakeRefCounted<TestCertProvider>();
MakeRefCounted<grpc_tls_certificate_distributor>(); auto identity_provider = MakeRefCounted<TestCertProvider>();
auto identity_cert_distributor = XdsCertificateProvider provider(root_provider, "test", identity_provider,
MakeRefCounted<grpc_tls_certificate_distributor>(); "test", {});
XdsCertificateProvider provider;
provider.UpdateRootCertNameAndDistributor("", "test", root_cert_distributor);
provider.UpdateIdentityCertNameAndDistributor("", "test",
identity_cert_distributor);
auto* watcher = new TestCertificatesWatcher; auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates( provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", ""); std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -187,30 +204,32 @@ TEST(XdsCertificateProviderTest,
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Update both root certs and identity certs // Update both root certs and identity certs
root_cert_distributor->SetKeyMaterials("test", kRootCert1, absl::nullopt); root_provider->distributor()->SetKeyMaterials("test", kRootCert1,
identity_cert_distributor->SetKeyMaterials("test", absl::nullopt, absl::nullopt);
MakeKeyCertPairsType1()); identity_provider->distributor()->SetKeyMaterials("test", absl::nullopt,
MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1); EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Second update for just root certs // Second update for just root certs
root_cert_distributor->SetKeyMaterials("test", kRootCert2, absl::nullopt); root_provider->distributor()->SetKeyMaterials("test", kRootCert2,
absl::nullopt);
EXPECT_EQ(watcher->root_certs(), kRootCert2); EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Second update for identity certs // Second update for identity certs
identity_cert_distributor->SetKeyMaterials("test", absl::nullopt, identity_provider->distributor()->SetKeyMaterials("test", absl::nullopt,
MakeKeyCertPairsType2()); MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_certs(), kRootCert2); EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Set error for both root and identity // Set error for both root and identity
root_cert_distributor->SetErrorForCert( root_provider->distributor()->SetErrorForCert(
"test", GRPC_ERROR_CREATE(kRootErrorMessage), absl::nullopt); "test", GRPC_ERROR_CREATE(kRootErrorMessage), absl::nullopt);
identity_cert_distributor->SetErrorForCert( identity_provider->distributor()->SetErrorForCert(
"test", absl::nullopt, GRPC_ERROR_CREATE(kIdentityErrorMessage)); "test", absl::nullopt, GRPC_ERROR_CREATE(kIdentityErrorMessage));
EXPECT_EQ(watcher->root_certs(), kRootCert2); EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
@ -219,7 +238,8 @@ TEST(XdsCertificateProviderTest,
EXPECT_THAT(StatusToString(watcher->identity_cert_error()), EXPECT_THAT(StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(kIdentityErrorMessage)); ::testing::HasSubstr(kIdentityErrorMessage));
// Send an update for root certs. Test that the root cert error is reset. // Send an update for root certs. Test that the root cert error is reset.
root_cert_distributor->SetKeyMaterials("test", kRootCert1, absl::nullopt); root_provider->distributor()->SetKeyMaterials("test", kRootCert1,
absl::nullopt);
EXPECT_EQ(watcher->root_certs(), kRootCert1); EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
@ -227,25 +247,25 @@ TEST(XdsCertificateProviderTest,
::testing::HasSubstr(kIdentityErrorMessage)); ::testing::HasSubstr(kIdentityErrorMessage));
// Send an update for identity certs. Test that the identity cert error is // Send an update for identity certs. Test that the identity cert error is
// reset. // reset.
identity_cert_distributor->SetKeyMaterials("test", absl::nullopt, identity_provider->distributor()->SetKeyMaterials("test", absl::nullopt,
MakeKeyCertPairsType1()); MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1); EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1()); EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Test update on unwatched cert name // Test update on unwatched cert name
identity_cert_distributor->SetKeyMaterials("identity", kRootCert2, identity_provider->distributor()->SetKeyMaterials("identity", kRootCert2,
MakeKeyCertPairsType2()); MakeKeyCertPairsType2());
root_cert_distributor->SetKeyMaterials("root", kRootCert1, root_provider->distributor()->SetKeyMaterials("root", kRootCert1,
MakeKeyCertPairsType1()); MakeKeyCertPairsType1());
} }
TEST(XdsCertificateProviderTest, TEST(XdsCertificateProviderTest,
RootCertDistributorSameAsIdentityCertDistributorDifferentCertNames) { RootCertDistributorSameAsIdentityCertDistributorDifferentCertNames) {
auto distributor = MakeRefCounted<grpc_tls_certificate_distributor>(); auto root_and_identity_provider = MakeRefCounted<TestCertProvider>();
XdsCertificateProvider provider; auto distributor = root_and_identity_provider->distributor();
provider.UpdateRootCertNameAndDistributor("", "root", distributor); XdsCertificateProvider provider(root_and_identity_provider, "root",
provider.UpdateIdentityCertNameAndDistributor("", "identity", distributor); root_and_identity_provider, "identity", {});
auto* watcher = new TestCertificatesWatcher; auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates( provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", ""); std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -306,10 +326,10 @@ TEST(XdsCertificateProviderTest,
TEST(XdsCertificateProviderTest, TEST(XdsCertificateProviderTest,
RootCertDistributorSameAsIdentityCertDistributorSameCertNames) { RootCertDistributorSameAsIdentityCertDistributorSameCertNames) {
auto distributor = MakeRefCounted<grpc_tls_certificate_distributor>(); auto root_and_identity_provider = MakeRefCounted<TestCertProvider>();
XdsCertificateProvider provider; auto distributor = root_and_identity_provider->distributor();
provider.UpdateRootCertNameAndDistributor("", "", distributor); XdsCertificateProvider provider(root_and_identity_provider, "",
provider.UpdateIdentityCertNameAndDistributor("", "", distributor); root_and_identity_provider, "", {});
auto* watcher = new TestCertificatesWatcher; auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates( provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", ""); std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -367,186 +387,8 @@ TEST(XdsCertificateProviderTest,
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus()); EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
} }
TEST(XdsCertificateProviderTest, SwapOutDistributorsMultipleTimes) {
auto distributor = MakeRefCounted<grpc_tls_certificate_distributor>();
distributor->SetKeyMaterials("", kRootCert1, MakeKeyCertPairsType1());
XdsCertificateProvider provider;
auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
// Initially there are no certificate providers.
EXPECT_EQ(watcher->root_certs(), absl::nullopt);
EXPECT_EQ(watcher->key_cert_pairs(), absl::nullopt);
EXPECT_THAT(StatusToString(watcher->root_cert_error()),
::testing::HasSubstr(
"No certificate provider available for root certificates"));
EXPECT_THAT(
StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(
"No certificate provider available for identity certificates"));
// Update root cert distributor.
provider.UpdateRootCertNameAndDistributor("", "", distributor);
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), absl::nullopt);
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_THAT(
StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(
"No certificate provider available for identity certificates"));
// Update identity cert distributor
provider.UpdateIdentityCertNameAndDistributor("", "", distributor);
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Update both root and identity certs
distributor->SetKeyMaterials("", kRootCert2, MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Set error for both root and identity
distributor->SetErrorForCert("", GRPC_ERROR_CREATE(kRootErrorMessage),
GRPC_ERROR_CREATE(kIdentityErrorMessage));
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_THAT(StatusToString(watcher->root_cert_error()),
::testing::HasSubstr(kRootErrorMessage));
EXPECT_THAT(StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(kIdentityErrorMessage));
// Send an update again
distributor->SetKeyMaterials("", kRootCert1, MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Remove root cert provider
provider.UpdateRootCertNameAndDistributor("", "", nullptr);
distributor->SetKeyMaterials("", kRootCert2, MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_certs(), kRootCert1); // not updated
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_THAT(StatusToString(watcher->root_cert_error()),
::testing::HasSubstr(
"No certificate provider available for root certificates"));
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Remove identity cert provider too
provider.UpdateIdentityCertNameAndDistributor("", "", nullptr);
distributor->SetKeyMaterials("", kRootCert1, MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2()); // not updated
EXPECT_THAT(StatusToString(watcher->root_cert_error()),
::testing::HasSubstr(
"No certificate provider available for root certificates"));
EXPECT_THAT(
StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(
"No certificate provider available for identity certificates"));
// Change certificate names being watched, without any certificate updates.
provider.UpdateRootCertNameAndDistributor("", "root", distributor);
provider.UpdateIdentityCertNameAndDistributor("", "identity", distributor);
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_THAT(StatusToString(watcher->root_cert_error()),
::testing::HasSubstr(
"No certificate provider available for root certificates"));
EXPECT_THAT(
StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(
"No certificate provider available for identity certificates"));
// Send out certificate updates.
distributor->SetKeyMaterials("root", kRootCert2, absl::nullopt);
distributor->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Swap in new certificate distributors with different certificate names and
// existing updates.
auto root_cert_distributor =
MakeRefCounted<grpc_tls_certificate_distributor>();
auto identity_cert_distributor =
MakeRefCounted<grpc_tls_certificate_distributor>();
provider.UpdateRootCertNameAndDistributor("", "root", root_cert_distributor);
provider.UpdateIdentityCertNameAndDistributor("", "identity",
identity_cert_distributor);
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Change certificate names without any certificate updates.
provider.UpdateRootCertNameAndDistributor("", "test", root_cert_distributor);
provider.UpdateIdentityCertNameAndDistributor("", "test",
identity_cert_distributor);
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Send out certificate updates.
root_cert_distributor->SetKeyMaterials("test", kRootCert1,
MakeKeyCertPairsType1());
identity_cert_distributor->SetKeyMaterials("test", kRootCert2,
MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
}
TEST(XdsCertificateProviderTest, MultipleCertNames) {
XdsCertificateProvider provider;
// Start watch for "test1". There are no underlying distributors for
// that cert name, so it will return an error.
auto* watcher1 = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher1), "test1", "test1");
EXPECT_EQ(watcher1->root_certs(), absl::nullopt);
EXPECT_EQ(watcher1->key_cert_pairs(), absl::nullopt);
EXPECT_THAT(StatusToString(watcher1->root_cert_error()),
::testing::HasSubstr(
"No certificate provider available for root certificates"));
EXPECT_THAT(
StatusToString(watcher1->identity_cert_error()),
::testing::HasSubstr(
"No certificate provider available for identity certificates"));
// Add distributor for "test1". This will return data to the watcher.
auto cert_distributor1 = MakeRefCounted<grpc_tls_certificate_distributor>();
cert_distributor1->SetKeyMaterials("root", kRootCert1, absl::nullopt);
cert_distributor1->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1());
provider.UpdateRootCertNameAndDistributor("test1", "root", cert_distributor1);
provider.UpdateIdentityCertNameAndDistributor("test1", "identity",
cert_distributor1);
EXPECT_EQ(watcher1->root_certs(), kRootCert1);
EXPECT_EQ(watcher1->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher1->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher1->identity_cert_error(), absl::OkStatus());
// Add distributor for "test2".
auto cert_distributor2 = MakeRefCounted<grpc_tls_certificate_distributor>();
cert_distributor2->SetKeyMaterials("root2", kRootCert2, absl::nullopt);
cert_distributor2->SetKeyMaterials("identity2", absl::nullopt,
MakeKeyCertPairsType2());
provider.UpdateRootCertNameAndDistributor("test2", "root2",
cert_distributor2);
provider.UpdateIdentityCertNameAndDistributor("test2", "identity2",
cert_distributor2);
// Add watcher for "test2". This one should return data immediately.
auto* watcher2 = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher2), "test2", "test2");
EXPECT_EQ(watcher2->root_certs(), kRootCert2);
EXPECT_EQ(watcher2->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher2->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher2->identity_cert_error(), absl::OkStatus());
// The presence of "test2" should not affect "test1".
EXPECT_EQ(watcher1->root_certs(), kRootCert1);
EXPECT_EQ(watcher1->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher1->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher1->identity_cert_error(), absl::OkStatus());
}
TEST(XdsCertificateProviderTest, UnknownCertName) { TEST(XdsCertificateProviderTest, UnknownCertName) {
XdsCertificateProvider provider; XdsCertificateProvider provider(nullptr, "", nullptr, "", {});
auto* watcher = new TestCertificatesWatcher; auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates( provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "test", "test"); std::unique_ptr<TestCertificatesWatcher>(watcher), "test", "test");

@ -1347,11 +1347,66 @@ TEST_F(HostOverrideStatusTest, PassesOnRelevantHealthStatuses) {
EXPECT_EQ(*decode_result.name, "foo"); EXPECT_EQ(*decode_result.name, "foo");
auto& resource = auto& resource =
static_cast<const XdsClusterResource&>(**decode_result.resource); static_cast<const XdsClusterResource&>(**decode_result.resource);
EXPECT_THAT(resource.override_host_statuses, EXPECT_EQ(resource.override_host_statuses.ToString(),
::testing::UnorderedElementsAre( "{UNKNOWN, HEALTHY, DRAINING}");
XdsHealthStatus(XdsHealthStatus::kUnknown), }
XdsHealthStatus(XdsHealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::kDraining))); TEST_F(HostOverrideStatusTest,
DefaultsToUnknownAndHealthyWithoutCommonLbConfig) {
Cluster cluster;
cluster.set_name("foo");
cluster.set_type(cluster.EDS);
cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
std::string serialized_resource;
ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
auto* resource_type = XdsClusterResourceType::Get();
auto decode_result =
resource_type->Decode(decode_context_, serialized_resource);
ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
ASSERT_TRUE(decode_result.name.has_value());
EXPECT_EQ(*decode_result.name, "foo");
auto& resource =
static_cast<const XdsClusterResource&>(**decode_result.resource);
EXPECT_EQ(resource.override_host_statuses.ToString(), "{UNKNOWN, HEALTHY}");
}
TEST_F(HostOverrideStatusTest,
DefaultsToUnknownAndHealthyWithoutOverrideHostStatus) {
Cluster cluster;
cluster.set_name("foo");
cluster.set_type(cluster.EDS);
cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
cluster.mutable_common_lb_config();
std::string serialized_resource;
ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
auto* resource_type = XdsClusterResourceType::Get();
auto decode_result =
resource_type->Decode(decode_context_, serialized_resource);
ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
ASSERT_TRUE(decode_result.name.has_value());
EXPECT_EQ(*decode_result.name, "foo");
auto& resource =
static_cast<const XdsClusterResource&>(**decode_result.resource);
EXPECT_EQ(resource.override_host_statuses.ToString(), "{UNKNOWN, HEALTHY}");
}
TEST_F(HostOverrideStatusTest, CanExplicitlySetToEmpty) {
Cluster cluster;
cluster.set_name("foo");
cluster.set_type(cluster.EDS);
cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_self();
cluster.mutable_common_lb_config()->mutable_override_host_status();
std::string serialized_resource;
ASSERT_TRUE(cluster.SerializeToString(&serialized_resource));
auto* resource_type = XdsClusterResourceType::Get();
auto decode_result =
resource_type->Decode(decode_context_, serialized_resource);
ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
ASSERT_TRUE(decode_result.name.has_value());
EXPECT_EQ(*decode_result.name, "foo");
auto& resource =
static_cast<const XdsClusterResource&>(**decode_result.resource);
EXPECT_EQ(resource.override_host_statuses.ToString(), "{}");
} }
} // namespace } // namespace

@ -1749,7 +1749,7 @@ TEST_F(RlsTest, Basic) {
::testing::ElementsAre(::testing::Pair( ::testing::ElementsAre(::testing::Pair(
"rls", "rls",
"[{\"rls_experimental\":{" "[{\"rls_experimental\":{"
"\"childPolicy\":[{\"cds_experimental\":{}}]," "\"childPolicy\":[{\"cds_experimental\":{\"isDynamic\":true}}],"
"\"childPolicyConfigTargetFieldName\":\"cluster\"," "\"childPolicyConfigTargetFieldName\":\"cluster\","
"\"routeLookupConfig\":{" "\"routeLookupConfig\":{"
"\"cacheSizeBytes\":\"1024\"," "\"cacheSizeBytes\":\"1024\","
@ -1852,7 +1852,7 @@ TEST_F(RlsTest, NotUsedInAllVirtualHosts) {
::testing::ElementsAre(::testing::Pair( ::testing::ElementsAre(::testing::Pair(
"rls", "rls",
"[{\"rls_experimental\":{" "[{\"rls_experimental\":{"
"\"childPolicy\":[{\"cds_experimental\":{}}]," "\"childPolicy\":[{\"cds_experimental\":{\"isDynamic\":true}}],"
"\"childPolicyConfigTargetFieldName\":\"cluster\"," "\"childPolicyConfigTargetFieldName\":\"cluster\","
"\"routeLookupConfig\":{" "\"routeLookupConfig\":{"
"\"cacheSizeBytes\":\"1024\"," "\"cacheSizeBytes\":\"1024\","

@ -330,9 +330,9 @@ TEST_P(CdsDeletionTest, ClusterDeleted) {
SendRpcsUntil(DEBUG_LOCATION, [](const RpcResult& result) { SendRpcsUntil(DEBUG_LOCATION, [](const RpcResult& result) {
if (result.status.ok()) return true; // Keep going. if (result.status.ok()) return true; // Keep going.
EXPECT_EQ(StatusCode::UNAVAILABLE, result.status.error_code()); EXPECT_EQ(StatusCode::UNAVAILABLE, result.status.error_code());
EXPECT_EQ(absl::StrCat("CDS resource \"", kDefaultClusterName, EXPECT_EQ(
"\" does not exist"), absl::StrCat("CDS resource ", kDefaultClusterName, " does not exist"),
result.status.error_message()); result.status.error_message());
return false; return false;
}); });
// Make sure we ACK'ed the update. // Make sure we ACK'ed the update.

@ -425,8 +425,8 @@ TEST_P(AggregateClusterTest, ReconfigEdsWhileLogicalDnsChildFails) {
} }
// When an RPC fails, we know the channel has seen the update. // When an RPC fails, we know the channel has seen the update.
constexpr char kErrorMessage[] = constexpr char kErrorMessage[] =
"empty address list: DNS resolution failed for server.example.com:443 " "empty address list: DNS resolution failed for server.example.com:443: "
"\\(UNAVAILABLE: injected error\\)"; "UNAVAILABLE: injected error";
CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE, kErrorMessage); CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE, kErrorMessage);
// Send an EDS update that moves locality1 to priority 0. // Send an EDS update that moves locality1 to priority 0.
args1 = EdsResourceArgs({ args1 = EdsResourceArgs({
@ -613,7 +613,7 @@ TEST_P(AggregateClusterTest, DependencyLoopWithNoLeafClusters) {
cluster_config.add_clusters(kNewClusterName1); cluster_config.add_clusters(kNewClusterName1);
custom_cluster->mutable_typed_config()->PackFrom(cluster_config); custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
balancer_->ads_service()->SetCdsResource(cluster); balancer_->ads_service()->SetCdsResource(cluster);
// kDefaultClusterName points to the default cluster. // kNewClusterName1 points to the default cluster.
cluster.set_name(kNewClusterName1); cluster.set_name(kNewClusterName1);
cluster_config.Clear(); cluster_config.Clear();
cluster_config.add_clusters(kDefaultClusterName); cluster_config.add_clusters(kDefaultClusterName);
@ -621,8 +621,8 @@ TEST_P(AggregateClusterTest, DependencyLoopWithNoLeafClusters) {
balancer_->ads_service()->SetCdsResource(cluster); balancer_->ads_service()->SetCdsResource(cluster);
// RPCs should fail. // RPCs should fail.
CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE, CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE,
"new_cluster_1: FAILED_PRECONDITION: " "aggregate cluster dependency graph for cluster_name "
"aggregate cluster graph has no leaf clusters"); "has no leaf clusters");
} }
TEST_P(AggregateClusterTest, DependencyLoopWithLeafClusters) { TEST_P(AggregateClusterTest, DependencyLoopWithLeafClusters) {

@ -429,7 +429,7 @@ TEST_P(TimeoutTest, CdsServerIgnoresRequest) {
balancer_->ads_service()->IgnoreResourceType(kCdsTypeUrl); balancer_->ads_service()->IgnoreResourceType(kCdsTypeUrl);
CheckRpcSendFailure( CheckRpcSendFailure(
DEBUG_LOCATION, StatusCode::UNAVAILABLE, DEBUG_LOCATION, StatusCode::UNAVAILABLE,
absl::StrCat("CDS resource \"", kDefaultClusterName, "\" does not exist"), absl::StrCat("CDS resource ", kDefaultClusterName, " does not exist"),
RpcOptions().set_timeout_ms(4000)); RpcOptions().set_timeout_ms(4000));
} }
@ -437,7 +437,7 @@ TEST_P(TimeoutTest, CdsResourceNotPresentInRequest) {
balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName); balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
CheckRpcSendFailure( CheckRpcSendFailure(
DEBUG_LOCATION, StatusCode::UNAVAILABLE, DEBUG_LOCATION, StatusCode::UNAVAILABLE,
absl::StrCat("CDS resource \"", kDefaultClusterName, "\" does not exist"), absl::StrCat("CDS resource ", kDefaultClusterName, " does not exist"),
RpcOptions().set_timeout_ms(4000)); RpcOptions().set_timeout_ms(4000));
} }
@ -461,9 +461,9 @@ TEST_P(TimeoutTest, CdsSecondResourceNotPresentInRequest) {
[&](const RpcResult& result) { [&](const RpcResult& result) {
if (result.status.ok()) return true; // Keep going. if (result.status.ok()) return true; // Keep going.
EXPECT_EQ(StatusCode::UNAVAILABLE, result.status.error_code()); EXPECT_EQ(StatusCode::UNAVAILABLE, result.status.error_code());
EXPECT_EQ(absl::StrCat("CDS resource \"", kNewClusterName, EXPECT_EQ(
"\" does not exist"), absl::StrCat("CDS resource ", kNewClusterName, " does not exist"),
result.status.error_message()); result.status.error_message());
return false; return false;
}, },
/*timeout_ms=*/30000, RpcOptions().set_timeout_ms(4000)); /*timeout_ms=*/30000, RpcOptions().set_timeout_ms(4000));
@ -912,10 +912,9 @@ TEST_P(XdsFederationTest, CdsResourceNameAuthorityUnknown) {
grpc::Status status = stub2->Echo(&context, request, &response); grpc::Status status = stub2->Echo(&context, request, &response);
EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE); EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE);
EXPECT_EQ(status.error_message(), EXPECT_EQ(status.error_message(),
absl::StrCat( absl::StrCat(kNewClusterName,
kNewClusterName, ": authority \"xds.unknown.com\" not present in "
": UNAVAILABLE: authority \"xds.unknown.com\" not present in " "bootstrap config"));
"bootstrap config"));
ASSERT_EQ(GRPC_CHANNEL_TRANSIENT_FAILURE, channel2->GetState(false)); ASSERT_EQ(GRPC_CHANNEL_TRANSIENT_FAILURE, channel2->GetState(false));
} }
@ -972,10 +971,10 @@ TEST_P(XdsFederationTest, EdsResourceNameAuthorityUnknown) {
EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE); EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE);
EXPECT_EQ( EXPECT_EQ(
status.error_message(), status.error_message(),
"no children in weighted_target policy: EDS watcher error for resource " "no children in weighted_target policy: EDS resource "
"xdstp://xds.unknown.com/envoy.config.endpoint.v3.ClusterLoadAssignment/" "xdstp://xds.unknown.com/envoy.config.endpoint.v3.ClusterLoadAssignment/"
"edsservice_name (UNAVAILABLE: authority \"xds.unknown.com\" not " "edsservice_name: UNAVAILABLE: authority \"xds.unknown.com\" not "
"present in bootstrap config)"); "present in bootstrap config");
ASSERT_EQ(GRPC_CHANNEL_TRANSIENT_FAILURE, channel2->GetState(false)); ASSERT_EQ(GRPC_CHANNEL_TRANSIENT_FAILURE, channel2->GetState(false));
} }

@ -680,7 +680,7 @@ TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpClusterDoesNotExist) {
balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName); balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
CheckRpcSendFailure( CheckRpcSendFailure(
DEBUG_LOCATION, StatusCode::UNAVAILABLE, DEBUG_LOCATION, StatusCode::UNAVAILABLE,
absl::StrCat("CDS resource \"", kDefaultClusterName, "\" does not exist"), absl::StrCat("CDS resource ", kDefaultClusterName, " does not exist"),
RpcOptions().set_timeout_ms(kTimeoutMillisecond)); RpcOptions().set_timeout_ms(kTimeoutMillisecond));
auto csds_response = FetchCsdsResponse(); auto csds_response = FetchCsdsResponse();
EXPECT_THAT(csds_response.config(0).generic_xds_configs(), EXPECT_THAT(csds_response.config(0).generic_xds_configs(),

@ -107,6 +107,9 @@ INSTANTIATE_TEST_SUITE_P(
// Test to ensure the most basic fault injection config works. // Test to ensure the most basic fault injection config works.
TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysAbort) { TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysAbort) {
const uint32_t kAbortPercentagePerHundred = 100; const uint32_t kAbortPercentagePerHundred = 100;
// Create an EDS resource
EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
// Construct the fault injection filter config // Construct the fault injection filter config
HTTPFault http_fault; HTTPFault http_fault;
auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage(); auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();

@ -470,6 +470,8 @@ TEST_P(LdsRdsTest, ChooseLastRoute) {
} }
TEST_P(LdsRdsTest, NoMatchingRoute) { TEST_P(LdsRdsTest, NoMatchingRoute) {
EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
RouteConfiguration route_config = default_route_config_; RouteConfiguration route_config = default_route_config_;
route_config.mutable_virtual_hosts(0) route_config.mutable_virtual_hosts(0)
->mutable_routes(0) ->mutable_routes(0)
@ -527,6 +529,8 @@ TEST_P(LdsRdsTest, NacksInvalidRouteConfig) {
// Tests that LDS client should fail RPCs with UNAVAILABLE status code if the // Tests that LDS client should fail RPCs with UNAVAILABLE status code if the
// matching route has an action other than RouteAction. // matching route has an action other than RouteAction.
TEST_P(LdsRdsTest, MatchingRouteHasNoRouteAction) { TEST_P(LdsRdsTest, MatchingRouteHasNoRouteAction) {
EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
RouteConfiguration route_config = default_route_config_; RouteConfiguration route_config = default_route_config_;
// Set a route with an inappropriate route action // Set a route with an inappropriate route action
auto* vhost = route_config.mutable_virtual_hosts(0); auto* vhost = route_config.mutable_virtual_hosts(0);

@ -101,7 +101,7 @@ _DATA_MEMBERS = [
), ),
test_name="DifferentCertificateVerifier", test_name="DifferentCertificateVerifier",
test_value_1="MakeRefCounted<HostNameCertificateVerifier>()", test_value_1="MakeRefCounted<HostNameCertificateVerifier>()",
test_value_2='MakeRefCounted<XdsCertificateVerifier>(nullptr, "")', test_value_2="MakeRefCounted<XdsCertificateVerifier>(nullptr)",
), ),
DataMember( DataMember(
name="check_call_host", name="check_call_host",

@ -1155,7 +1155,6 @@ src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h \
src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \
@ -1185,8 +1184,12 @@ src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \
src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/polling_resolver.h \ src/core/ext/filters/client_channel/resolver/polling_resolver.h \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_filter.h \ src/core/ext/filters/client_channel/retry_filter.h \
src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \ src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \

@ -960,7 +960,6 @@ src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc \
src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h \ src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h \
src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \ src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc \
@ -994,8 +993,12 @@ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/polling_resolver.h \ src/core/ext/filters/client_channel/resolver/polling_resolver.h \
src/core/ext/filters/client_channel/resolver/sockaddr/README.md \ src/core/ext/filters/client_channel/resolver/sockaddr/README.md \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_filter.h \ src/core/ext/filters/client_channel/retry_filter.h \
src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \ src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \

Loading…
Cancel
Save