[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_xds_cluster_impl",
"//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_wrr_locality",
"//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/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_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_wrr_locality.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/polling_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_trace.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_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/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_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_wrr_locality.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/polling_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_trace.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_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/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_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_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/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_trace.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/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_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_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.h",
"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.h",
"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.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.h",
"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/fake/fake_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_legacy_call_data.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/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_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_wrr_locality.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/polling_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_trace.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_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/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_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_wrr_locality.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/polling_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_trace.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_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\\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_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_wrr_locality.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\\polling_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_trace.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_service_config.cc " +

@ -102,7 +102,6 @@ some configuration as environment variables that can be set.
- xds_client - traces xds client
- xds_cluster_manager_lb - traces cluster manager 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
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/fake/fake_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_legacy_call_data.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/fake/fake_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_legacy_call_data.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_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_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.h',
'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.h',
'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.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.h',
'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/fake/fake_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_legacy_call_data.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_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_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.h )
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.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/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.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.h )
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/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_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_wrr_locality.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/polling_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_trace.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_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_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_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.h" 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.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/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.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.h" 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_fwd",
"context",
"grpc_resolver_xds_header",
"grpc_resolver_xds_attributes",
"grpc_service_config",
"json",
"json_args",
@ -4710,9 +4710,9 @@ grpc_cc_library(
deps = [
"channel_args",
"delegating_helper",
"grpc_matchers",
"grpc_lb_address_filtering",
"grpc_lb_xds_channel_args",
"grpc_outlier_detection_header",
"grpc_tls_credentials",
"grpc_xds_client",
"json",
"json_args",
@ -4725,6 +4725,7 @@ grpc_cc_library(
"pollset_set",
"time",
"unique_type_name",
"xds_dependency_manager",
"//:config",
"//:debug_location",
"//: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(
name = "grpc_lb_policy_xds_cluster_impl",
srcs = [
@ -4829,6 +4782,7 @@ grpc_cc_library(
"resolved_address",
"subchannel_interface",
"validation_errors",
"xds_dependency_manager",
"//:config",
"//:debug_location",
"//:endpoint_addresses",
@ -4857,7 +4811,7 @@ grpc_cc_library(
deps = [
"channel_args",
"delegating_helper",
"grpc_resolver_xds_header",
"grpc_resolver_xds_attributes",
"json",
"json_args",
"json_object_loader",
@ -5449,6 +5403,7 @@ grpc_cc_library(
"resolved_address",
"subchannel_interface",
"validation_errors",
"xds_dependency_manager",
"//:config",
"//:debug_location",
"//:endpoint_addresses",
@ -5758,9 +5713,9 @@ grpc_cc_library(
)
grpc_cc_library(
name = "grpc_resolver_xds_header",
name = "grpc_resolver_xds_attributes",
hdrs = [
"ext/filters/client_channel/resolver/xds/xds_resolver.h",
"ext/filters/client_channel/resolver/xds/xds_resolver_attributes.h",
],
external_deps = ["absl/strings"],
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(
name = "grpc_resolver_xds",
srcs = [
@ -5797,7 +5794,8 @@ grpc_cc_library(
"dual_ref_counted",
"experiments",
"grpc_lb_policy_ring_hash",
"grpc_resolver_xds_header",
"grpc_resolver_xds_attributes",
"grpc_resolver_xds_trace",
"grpc_service_config",
"grpc_xds_client",
"iomgr_fwd",
@ -5806,6 +5804,7 @@ grpc_cc_library(
"ref_counted",
"slice",
"time",
"xds_dependency_manager",
"xxhash_inline",
"//:channel_arg_names",
"//: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/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/resolver/xds/xds_dependency_manager.h"
#include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/ext/xds/xds_bootstrap_grpc.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/subchannel_interface.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"
namespace grpc_core {
@ -74,6 +76,8 @@ TraceFlag grpc_xds_cluster_impl_lb_trace(false, "xds_cluster_impl_lb");
namespace {
using XdsConfig = XdsDependencyManager::XdsConfig;
//
// global circuit breaker atomic map
//
@ -156,37 +160,24 @@ class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
absl::string_view name() const override { return kXdsClusterImpl; }
const std::string& cluster_name() const { return cluster_name_; }
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
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&);
void JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors);
private:
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
std::string cluster_name_;
std::string eds_service_name_;
absl::optional<GrpcXdsBootstrap::GrpcXdsServer> lrs_load_reporting_server_;
uint32_t max_concurrent_requests_;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
};
// xDS Cluster Impl LB policy.
class XdsClusterImplLb : public LoadBalancingPolicy {
public:
XdsClusterImplLb(RefCountedPtr<XdsClient> xds_client, Args args);
XdsClusterImplLb(RefCountedPtr<GrpcXdsClient> xds_client, Args args);
absl::string_view name() const override { return kXdsClusterImpl; }
@ -247,16 +238,25 @@ class XdsClusterImplLb : public LoadBalancingPolicy {
void ShutdownLocked() override;
void ResetState();
void ReportTransientFailure(absl::Status status);
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
const ChannelArgs& args);
absl::Status UpdateChildPolicyLocked(
absl::StatusOr<std::shared_ptr<EndpointAddressesIterator>> addresses,
std::string resolution_note, const ChannelArgs& args);
absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
MaybeCreateCertificateProviderLocked(
const XdsClusterResource& cluster_resource) const;
void MaybeUpdatePickerLocked();
// Current config from the resolver.
RefCountedPtr<XdsClusterImplLbConfig> config_;
std::shared_ptr<const XdsClusterResource> cluster_resource_;
RefCountedPtr<XdsEndpointResource::DropConfig> drop_config_;
// Current concurrent number of requests.
RefCountedPtr<CircuitBreakerCallCounterMap::CallCounter> call_counter_;
@ -265,7 +265,7 @@ class XdsClusterImplLb : public LoadBalancingPolicy {
bool shutting_down_ = false;
// The xds client.
RefCountedPtr<XdsClient> xds_client_;
RefCountedPtr<GrpcXdsClient> xds_client_;
// The stats for client-side load reporting.
RefCountedPtr<XdsClusterDropStats> drop_stats_;
@ -357,8 +357,8 @@ XdsClusterImplLb::Picker::Picker(XdsClusterImplLb* xds_cluster_impl_lb,
RefCountedPtr<SubchannelPicker> picker)
: call_counter_(xds_cluster_impl_lb->call_counter_),
max_concurrent_requests_(
xds_cluster_impl_lb->config_->max_concurrent_requests()),
drop_config_(xds_cluster_impl_lb->config_->drop_config()),
xds_cluster_impl_lb->cluster_resource_->max_concurrent_requests),
drop_config_(xds_cluster_impl_lb->drop_config_),
drop_stats_(xds_cluster_impl_lb->drop_stats_),
picker_(std::move(picker)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
@ -423,7 +423,7 @@ LoadBalancingPolicy::PickResult XdsClusterImplLb::Picker::Pick(
// XdsClusterImplLb
//
XdsClusterImplLb::XdsClusterImplLb(RefCountedPtr<XdsClient> xds_client,
XdsClusterImplLb::XdsClusterImplLb(RefCountedPtr<GrpcXdsClient> xds_client,
Args args)
: LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) {
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);
}
shutting_down_ = true;
ResetState();
xds_client_.reset(DEBUG_LOCATION, "XdsClusterImpl");
}
void XdsClusterImplLb::ResetState() {
// Remove the child policy's interested_parties pollset_set from the
// xDS policy.
if (child_policy_ != nullptr) {
@ -456,7 +461,18 @@ void XdsClusterImplLb::ShutdownLocked() {
// the child.
picker_.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() {
@ -469,56 +485,174 @@ void XdsClusterImplLb::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) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
gpr_log(GPR_INFO, "[xds_cluster_impl_lb %p] Received update", this);
}
// Update config.
const bool is_initial_update = config_ == nullptr;
auto old_config = std::move(config_);
config_ = args.config.TakeAsSubclass<XdsClusterImplLbConfig>();
// On initial update, create drop stats.
if (is_initial_update) {
if (config_->lrs_load_reporting_server().has_value()) {
drop_stats_ = xds_client_->AddClusterDropStats(
config_->lrs_load_reporting_server().value(), config_->cluster_name(),
config_->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,
config_->lrs_load_reporting_server()->server_uri().c_str(),
config_->cluster_name().c_str(),
config_->eds_service_name().c_str());
}
// Grab new LB policy config.
auto new_config = args.config.TakeAsSubclass<XdsClusterImplLbConfig>();
// Cluster name should never change, because the cds policy will assign a
// different priority child name if that happens, which means that this
// policy instance will get replaced instead of being updated.
if (config_ != nullptr) {
GPR_ASSERT(config_->cluster_name() == new_config->cluster_name());
}
// Get xDS config.
auto new_xds_config = args.args.GetObjectRef<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;
}
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.
return UpdateChildPolicyLocked(std::move(args.addresses),
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() {
// If we're dropping all calls, report READY, regardless of what (or
// 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_);
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_impl_lb_trace)) {
gpr_log(GPR_INFO,
@ -601,28 +735,30 @@ RefCountedPtr<SubchannelInterface> XdsClusterImplLb::Helper::CreateSubchannel(
if (parent()->shutting_down_) return nullptr;
// If load reporting is enabled, wrap the subchannel such that it
// 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>();
RefCountedPtr<XdsClusterLocalityStats> locality_stats =
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_->eds_service_name(), std::move(locality_name));
GetEdsResourceName(*parent()->cluster_resource_),
std::move(locality_name));
if (locality_stats != nullptr) {
return MakeRefCounted<StatsSubchannelWrapper>(
parent()->channel_control_helper()->CreateSubchannel(
address, per_address_args, args),
std::move(locality_stats));
}
gpr_log(
GPR_ERROR,
"[xds_cluster_impl_lb %p] Failed to get locality stats object for "
"LRS server %s, cluster %s, EDS service name %s; load reports will "
"not be generated (not wrapping subchannel)",
parent(),
parent()->config_->lrs_load_reporting_server()->server_uri().c_str(),
parent()->config_->cluster_name().c_str(),
parent()->config_->eds_service_name().c_str());
gpr_log(GPR_ERROR,
"[xds_cluster_impl_lb %p] Failed to get locality stats object for "
"LRS server %s, cluster %s, EDS service name %s; load reports will "
"not be generated (not wrapping subchannel)",
parent(),
parent()
->cluster_resource_->lrs_load_reporting_server->server_uri()
.c_str(),
parent()->config_->cluster_name().c_str(),
GetEdsResourceName(*parent()->cluster_resource_).c_str());
}
// Load reporting not enabled, so don't wrap the subchannel.
return parent()->channel_control_helper()->CreateSubchannel(
@ -652,67 +788,31 @@ void XdsClusterImplLb::Helper::UpdateState(
// 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&) {
static const auto* loader =
JsonObjectLoader<XdsClusterImplLbConfig>()
// Note: Some fields require custom processing, so they are
// handled in JsonPostLoad() instead.
.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();
return loader;
}
void XdsClusterImplLbConfig::JsonPostLoad(const Json& json,
const JsonArgs& args,
void XdsClusterImplLbConfig::JsonPostLoad(const Json& json, const JsonArgs&,
ValidationErrors* errors) {
// Parse "childPolicy" field.
{
ValidationErrors::ScopedField field(errors, ".childPolicy");
auto it = json.object().find("childPolicy");
if (it == json.object().end()) {
errors->AddError("field not present");
ValidationErrors::ScopedField field(errors, ".childPolicy");
auto it = json.object().find("childPolicy");
if (it == json.object().end()) {
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 {
auto lb_config = CoreConfiguration::Get()
.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);
}
child_policy_ = std::move(*lb_config);
}
}
}

@ -40,7 +40,7 @@
#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/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/config/core_configuration.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/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/xds/xds_health_status.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
@ -349,6 +350,9 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
void ShutdownLocked() override;
void ResetState();
void ReportTransientFailure(absl::Status status);
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
const ChannelArgs& args);
@ -361,7 +365,7 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
RefCountedPtr<SubchannelInterface> subchannel);
// Current config from the resolver.
RefCountedPtr<XdsOverrideHostLbConfig> config_;
XdsHealthStatusSet override_host_status_set_;
// Internal state.
bool shutting_down_ = false;
@ -526,6 +530,10 @@ void XdsOverrideHostLb::ShutdownLocked() {
gpr_log(GPR_INFO, "[xds_override_host_lb %p] shutting down", this);
}
shutting_down_ = true;
ResetState();
}
void XdsOverrideHostLb::ResetState() {
{
// Drop subchannel refs after releasing the lock to avoid deadlock.
std::vector<SubchannelEntry::SubchannelPtr> subchannel_refs_to_drop;
@ -551,6 +559,18 @@ void XdsOverrideHostLb::ShutdownLocked() {
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() {
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)) {
gpr_log(GPR_INFO, "[xds_override_host_lb %p] Received update", this);
}
auto old_config = std::move(config_);
// Update config.
config_ = args.config.TakeAsSubclass<XdsOverrideHostLbConfig>();
if (config_ == nullptr) {
// Grab new LB policy config.
if (args.config == nullptr) {
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.
if (args.addresses.ok()) {
UpdateAddressMap(**args.addresses);
@ -615,7 +658,7 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
UpdateArgs update_args;
update_args.addresses = std::move(args.addresses);
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);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO,
@ -627,9 +670,8 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
void XdsOverrideHostLb::MaybeUpdatePickerLocked() {
if (picker_ != nullptr) {
auto xds_override_host_picker =
MakeRefCounted<Picker>(RefAsSubclass<XdsOverrideHostLb>(), picker_,
config_->override_host_status_set());
auto xds_override_host_picker = MakeRefCounted<Picker>(
RefAsSubclass<XdsOverrideHostLb>(), picker_, override_host_status_set_);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
gpr_log(GPR_INFO,
"[xds_override_host_lb %p] updating connectivity: state=%s "
@ -679,7 +721,7 @@ void XdsOverrideHostLb::UpdateAddressMap(
XdsHealthStatus status = GetEndpointHealthStatus(endpoint);
// Skip draining hosts if not in the override status set.
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)) {
gpr_log(GPR_INFO,
"[xds_override_host_lb %p] endpoint %s: draining but not in "
@ -795,6 +837,14 @@ XdsOverrideHostLb::AdoptSubchannel(
RefCountedPtr<SubchannelInterface> XdsOverrideHostLb::Helper::CreateSubchannel(
const grpc_resolved_address& address, const ChannelArgs& per_address_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(
address, per_address_args, args);
return parent()->AdoptSubchannel(address, std::move(subchannel));
@ -921,50 +971,25 @@ const JsonLoaderInterface* XdsOverrideHostLbConfig::JsonLoader(
static const auto kJsonLoader =
JsonObjectLoader<XdsOverrideHostLbConfig>()
// Child policy config is parsed in JsonPostLoad
.Field("clusterName", &XdsOverrideHostLbConfig::cluster_name_)
.Finish();
return kJsonLoader;
}
void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json,
const JsonArgs& args,
void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json, const JsonArgs&,
ValidationErrors* errors) {
{
ValidationErrors::ScopedField field(errors, ".childPolicy");
auto it = json.object().find("childPolicy");
if (it == json.object().end()) {
errors->AddError("field not present");
} else {
auto child_policy_config = CoreConfiguration::Get()
.lb_policy_registry()
.ParseLoadBalancingConfig(it->second);
if (!child_policy_config.ok()) {
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);
}
}
ValidationErrors::ScopedField field(errors, ".childPolicy");
auto it = json.object().find("childPolicy");
if (it == json.object().end()) {
errors->AddError("field not present");
} else {
auto child_policy_config =
CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig(
it->second);
if (!child_policy_config.ok()) {
errors->AddError(child_policy_config.status().message());
} else {
override_host_status_set_ = XdsHealthStatusSet(
{XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown)});
child_config_ = std::move(*child_policy_config);
}
}
}

@ -21,7 +21,6 @@
#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/validation_errors.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(); }
const std::string& cluster_name() const { return cluster_name_; }
RefCountedPtr<LoadBalancingPolicy::Config> child_config() const {
return child_config_;
}
XdsHealthStatusSet override_host_status_set() const {
return override_host_status_set_;
}
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
void JsonPostLoad(const Json& json, const JsonArgs&,
ValidationErrors* errors);
private:
std::string cluster_name_;
RefCountedPtr<LoadBalancingPolicy::Config> child_config_;
XdsHealthStatusSet override_host_status_set_;
};
} // 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 "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h"
#include <stdint.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/config_selector.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_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_http_filters.h"
#include "src/core/ext/xds/xds_listener.h"
@ -96,12 +96,8 @@
namespace grpc_core {
TraceFlag grpc_xds_resolver_trace(false, "xds_resolver");
namespace {
using ReadDelayHandle = XdsClient::ReadDelayHandle;
//
// XdsResolver
//
@ -139,87 +135,22 @@ class XdsResolver : public Resolver {
}
private:
class ListenerWatcher : public XdsListenerResourceType::WatcherInterface {
class XdsWatcher : public XdsDependencyManager::Watcher {
public:
explicit ListenerWatcher(RefCountedPtr<XdsResolver> resolver)
explicit XdsWatcher(RefCountedPtr<XdsResolver> 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
: public XdsRouteConfigResourceType::WatcherInterface {
public:
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 OnUpdate(
RefCountedPtr<const XdsDependencyManager::XdsConfig> config) override {
resolver_->OnUpdate(std::move(config));
}
void OnError(absl::Status status,
RefCountedPtr<ReadDelayHandle> read_delay_handle) override {
resolver_->work_serializer_->Run(
[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 OnError(absl::string_view context, absl::Status status) override {
resolver_->OnError(context, std::move(status));
}
void OnResourceDoesNotExist(
RefCountedPtr<ReadDelayHandle> read_delay_handle) override {
resolver_->work_serializer_->Run(
[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);
void OnResourceDoesNotExist(std::string context) override {
resolver_->OnResourceDoesNotExist(std::move(context));
}
private:
@ -235,8 +166,12 @@ class XdsResolver : public Resolver {
class ClusterRef : public DualRefCounted<ClusterRef> {
public:
ClusterRef(RefCountedPtr<XdsResolver> resolver,
absl::string_view cluster_name)
: resolver_(std::move(resolver)), cluster_name_(cluster_name) {}
RefCountedPtr<XdsDependencyManager::ClusterSubscription>
cluster_subscription,
absl::string_view cluster_key)
: resolver_(std::move(resolver)),
cluster_subscription_(std::move(cluster_subscription)),
cluster_key_(cluster_key) {}
void Orphan() override {
XdsResolver* resolver_ptr = resolver_.get();
@ -245,13 +180,16 @@ class XdsResolver : public Resolver {
resolver->MaybeRemoveUnusedClusters();
},
DEBUG_LOCATION);
cluster_subscription_.reset();
}
const std::string& cluster_name() const { return cluster_name_; }
const std::string& cluster_key() const { return cluster_key_; }
private:
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
@ -288,9 +226,7 @@ class XdsResolver : public Resolver {
};
static absl::StatusOr<RefCountedPtr<RouteConfigData>> Create(
XdsResolver* resolver,
const std::vector<XdsRouteConfigResource::Route>& routes,
const Duration& default_max_stream_duration);
XdsResolver* resolver, const Duration& default_max_stream_duration);
bool operator==(const RouteConfigData& other) const {
return clusters_ == other.clusters_ && routes_ == other.routes_;
@ -322,9 +258,9 @@ class XdsResolver : public Resolver {
return sc1->json_string() == sc2->json_string();
}
absl::Status AddRouteEntry(const XdsRouteConfigResource::Route& route,
const Duration& default_max_stream_duration,
XdsResolver* resolver);
absl::Status AddRouteEntry(XdsResolver* resolver,
const XdsRouteConfigResource::Route& route,
const Duration& default_max_stream_duration);
std::map<absl::string_view, RefCountedPtr<ClusterRef>> clusters_;
std::vector<RouteEntry> routes_;
@ -397,27 +333,31 @@ class XdsResolver : public Resolver {
};
RefCountedPtr<ClusterRef> GetOrCreateClusterRef(
absl::string_view cluster_name) {
auto it = cluster_ref_map_.find(cluster_name);
absl::string_view cluster_key, absl::string_view cluster_name) {
auto it = cluster_ref_map_.find(cluster_key);
if (it == cluster_ref_map_.end()) {
auto cluster = MakeRefCounted<ClusterRef>(RefAsSubclass<XdsResolver>(),
cluster_name);
cluster_ref_map_.emplace(cluster->cluster_name(), cluster->WeakRef());
RefCountedPtr<XdsDependencyManager::ClusterSubscription> subscription;
if (!cluster_name.empty()) {
// 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 it->second->Ref();
}
void OnListenerUpdate(std::shared_ptr<const XdsListenerResource> listener);
void OnRouteConfigUpdate(
std::shared_ptr<const XdsRouteConfigResource> rds_update);
void OnUpdate(RefCountedPtr<const XdsDependencyManager::XdsConfig> config);
void OnError(absl::string_view context, absl::Status status);
void OnResourceDoesNotExist(std::string context);
absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateServiceConfig();
void GenerateResult();
void MaybeRemoveUnusedClusters();
uint64_t channel_id() const { return channel_id_; }
std::shared_ptr<WorkSerializer> work_serializer_;
std::unique_ptr<ResultHandler> result_handler_;
@ -427,17 +367,10 @@ class XdsResolver : public Resolver {
RefCountedPtr<GrpcXdsClient> xds_client_;
std::string lds_resource_name_;
std::string data_plane_authority_;
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;
const uint64_t channel_id_;
OrphanablePtr<XdsDependencyManager> dependency_mgr_;
RefCountedPtr<const XdsDependencyManager::XdsConfig> current_config_;
std::map<absl::string_view, WeakRefCountedPtr<ClusterRef>> cluster_ref_map_;
};
@ -470,19 +403,17 @@ class XdsResolver::RouteConfigData::RouteListIterator
absl::StatusOr<RefCountedPtr<XdsResolver::RouteConfigData>>
XdsResolver::RouteConfigData::Create(
XdsResolver* resolver,
const std::vector<XdsRouteConfigResource::Route>& routes,
const Duration& default_max_stream_duration) {
XdsResolver* resolver, const Duration& default_max_stream_duration) {
auto data = MakeRefCounted<RouteConfigData>();
// Reserve the necessary entries up-front to avoid reallocation as we add
// 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
// moving the entry in a reallocation will cause the string_view to point to
// invalid data.
data->routes_.reserve(routes.size());
for (auto& route : routes) {
data->routes_.reserve(resolver->current_config_->virtual_host->routes.size());
for (auto& route : resolver->current_config_->virtual_host->routes) {
absl::Status status =
data->AddRouteEntry(route, default_max_stream_duration, resolver);
data->AddRouteEntry(resolver, route, default_max_stream_duration);
if (!status.ok()) {
return status;
}
@ -555,12 +486,12 @@ XdsResolver::RouteConfigData::CreateMethodConfig(
}
// Handle xDS HTTP filters.
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
resolver->current_listener_->listener);
resolver->current_config_->listener->listener);
auto result = XdsRouting::GeneratePerHTTPFilterConfigs(
static_cast<const GrpcXdsBootstrap&>(resolver->xds_client_->bootstrap())
.http_filter_registry(),
hcm.http_filters, *resolver->current_virtual_host_, route, cluster_weight,
resolver->args_);
hcm.http_filters, *resolver->current_config_->virtual_host, route,
cluster_weight, resolver->args_);
if (!result.ok()) return result.status();
for (const auto& p : result->per_filter_configs) {
fields.emplace_back(absl::StrCat(" \"", p.first, "\": [\n",
@ -585,19 +516,21 @@ XdsResolver::RouteConfigData::CreateMethodConfig(
}
absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
const XdsRouteConfigResource::Route& route,
const Duration& default_max_stream_duration, XdsResolver* resolver) {
XdsResolver* resolver, const XdsRouteConfigResource::Route& route,
const Duration& default_max_stream_duration) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] XdsConfigSelector %p: route: %s",
resolver, this, route.ToString().c_str());
}
routes_.emplace_back(route);
auto* route_entry = &routes_.back();
auto maybe_add_cluster = [&](absl::string_view cluster_name) {
if (clusters_.find(cluster_name) != clusters_.end()) return;
auto cluster_state = resolver->GetOrCreateClusterRef(cluster_name);
absl::string_view name = cluster_state->cluster_name();
clusters_.emplace(name, std::move(cluster_state));
auto maybe_add_cluster = [&](absl::string_view cluster_key,
absl::string_view cluster_name) {
if (clusters_.find(cluster_key) != clusters_.end()) return;
auto 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>(
&route_entry->route.action);
@ -618,8 +551,8 @@ absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
return result.status();
}
route_entry->method_config = std::move(*result);
maybe_add_cluster(
absl::StrCat("cluster:", cluster_name.cluster_name));
maybe_add_cluster(absl::StrCat("cluster:", cluster_name.cluster_name),
cluster_name.cluster_name);
return absl::OkStatus();
},
// WeightedClusters
@ -640,7 +573,8 @@ absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
cluster_weight_state.cluster = weighted_cluster.name;
route_entry->weighted_cluster_state.push_back(
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();
},
@ -653,9 +587,11 @@ absl::Status XdsResolver::RouteConfigData::AddRouteEntry(
return result.status();
}
route_entry->method_config = std::move(*result);
maybe_add_cluster(absl::StrCat(
"cluster_specifier_plugin:",
cluster_specifier_plugin_name.cluster_specifier_plugin_name));
maybe_add_cluster(
absl::StrCat(
"cluster_specifier_plugin:",
cluster_specifier_plugin_name.cluster_specifier_plugin_name),
/*subscription_name=*/"");
return absl::OkStatus();
});
if (!status.ok()) {
@ -683,7 +619,7 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector(
static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap())
.http_filter_registry();
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
resolver_->current_listener_->listener);
resolver_->current_config_->listener->listener);
for (const auto& http_filter : hcm.http_filters) {
// Find filter. This is guaranteed to succeed, because it's checked
// at config validation time in the XdsApi code.
@ -814,7 +750,7 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig(
},
[&](const XdsRouteConfigResource::Route::RouteAction::HashPolicy::
ChannelId&) -> absl::optional<uint64_t> {
return resolver_->channel_id();
return resolver_->channel_id_;
});
if (new_hash.has_value()) {
// Rotating the old value prevents duplicate hash rules from cancelling
@ -840,7 +776,7 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig(
parsed_method_configs);
}
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.arena->New<RequestHashAttribute>(*hash));
args.service_config_call_data->SetCallAttribute(
@ -944,6 +880,9 @@ void XdsResolver::StartLocked() {
return;
}
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(), "/"));
if (!uri_.authority().empty()) {
// 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.",
this, lds_resource_name_.c_str());
}
grpc_pollset_set_add_pollset_set(
static_cast<GrpcXdsClient*>(xds_client_.get())->interested_parties(),
interested_parties_);
auto watcher = MakeRefCounted<ListenerWatcher>(RefAsSubclass<XdsResolver>());
listener_watcher_ = watcher.get();
XdsListenerResourceType::StartWatch(xds_client_.get(), lds_resource_name_,
std::move(watcher));
// Start watch for xDS config.
dependency_mgr_ = MakeOrphanable<XdsDependencyManager>(
xds_client_, work_serializer_,
std::make_unique<XdsWatcher>(RefAsSubclass<XdsResolver>()),
data_plane_authority_, lds_resource_name_, args_, interested_parties_);
}
void XdsResolver::ShutdownLocked() {
@ -1003,122 +940,20 @@ void XdsResolver::ShutdownLocked() {
gpr_log(GPR_INFO, "[xds_resolver %p] shutting down", this);
}
if (xds_client_ != nullptr) {
if (listener_watcher_ != nullptr) {
XdsListenerResourceType::CancelWatch(
xds_client_.get(), lds_resource_name_, listener_watcher_,
/*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_);
dependency_mgr_.reset();
grpc_pollset_set_del_pollset_set(xds_client_->interested_parties(),
interested_parties_);
xds_client_.reset(DEBUG_LOCATION, "xds resolver");
}
}
void XdsResolver::OnListenerUpdate(
std::shared_ptr<const XdsListenerResource> listener) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
gpr_log(GPR_INFO, "[xds_resolver %p] received updated listener data", this);
}
if (xds_client_ == nullptr) return;
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) {
void XdsResolver::OnUpdate(
RefCountedPtr<const XdsDependencyManager::XdsConfig> config) {
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;
// Find the relevant VirtualHost from the RouteConfiguration.
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.
current_config_ = std::move(config);
GenerateResult();
}
@ -1142,7 +977,7 @@ void XdsResolver::OnResourceDoesNotExist(std::string context) {
"update and returning empty service config",
this);
if (xds_client_ == nullptr) return;
current_virtual_host_ = nullptr;
current_config_.reset();
Result result;
result.addresses.emplace();
result.service_config = ServiceConfigImpl::Create(args_, "{}");
@ -1163,7 +998,7 @@ XdsResolver::CreateServiceConfig() {
" \"childPolicy\": %s\n"
" }",
cluster.first,
current_route_config_->cluster_specifier_plugin_map.at(
current_config_->route_config->cluster_specifier_plugin_map.at(
std::string(child_name))));
} else {
absl::ConsumePrefix(&child_name, "cluster:");
@ -1195,13 +1030,13 @@ XdsResolver::CreateServiceConfig() {
}
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
// state map, and then CreateServiceConfig for LB policies.
// state map.
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
current_listener_->listener);
auto route_config_data = RouteConfigData::Create(
this, current_virtual_host_->routes, hcm.http_max_stream_duration);
current_config_->listener->listener);
auto route_config_data =
RouteConfigData::Create(this, hcm.http_max_stream_duration);
if (!route_config_data.ok()) {
OnError("could not create ConfigSelector",
absl::UnavailableError(route_config_data.status().message()));
@ -1209,6 +1044,7 @@ void XdsResolver::GenerateResult() {
}
auto config_selector = MakeRefCounted<XdsConfigSelector>(
RefAsSubclass<XdsResolver>(), std::move(*route_config_data));
// Now create the service config.
Result result;
result.addresses.emplace();
result.service_config = CreateServiceConfig();
@ -1220,7 +1056,9 @@ void XdsResolver::GenerateResult() {
}
result.args =
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));
}
@ -1235,10 +1073,7 @@ void XdsResolver::MaybeRemoveUnusedClusters() {
it = cluster_ref_map_.erase(it);
}
}
if (update_needed && xds_client_ != nullptr) {
// Send a new result to the channel.
GenerateResult();
}
if (update_needed) GenerateResult();
}
//

@ -14,8 +14,8 @@
// limitations under the License.
//
#ifndef GRPC_SRC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_XDS_XDS_RESOLVER_H
#define 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_ATTRIBUTES_H
#include <grpc/support/port_platform.h>
@ -49,13 +49,14 @@ class XdsRouteStateAttribute
: public ServiceConfigCallData::CallAttributeInterface {
public:
static UniqueTypeName TypeName() {
static UniqueTypeName::Factory factory("xds_cluster_lb_data");
static UniqueTypeName::Factory factory("xds_route_state");
return factory.Create();
}
virtual bool HasClusterForRoute(absl::string_view cluster_name) const = 0;
UniqueTypeName type() const override { return TypeName(); }
};
} // 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 "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/lib/channel/channel_stack.h"
#include "src/core/lib/channel/context.h"

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

@ -43,16 +43,15 @@ class RootCertificatesWatcher
// presently, the watcher is immediately deleted when
// CancelTlsCertificatesWatch() is called, but that can potentially change in
// the future.
RootCertificatesWatcher(
RefCountedPtr<grpc_tls_certificate_distributor> parent,
std::string cert_name)
: parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
explicit RootCertificatesWatcher(
RefCountedPtr<grpc_tls_certificate_distributor> parent)
: parent_(std::move(parent)) {}
void OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
absl::optional<PemKeyCertPairList>
/* key_cert_pairs */) override {
if (root_certs.has_value()) {
parent_->SetKeyMaterials(cert_name_, std::string(root_certs.value()),
parent_->SetKeyMaterials("", std::string(root_certs.value()),
absl::nullopt);
}
}
@ -60,14 +59,13 @@ class RootCertificatesWatcher
void OnError(grpc_error_handle root_cert_error,
grpc_error_handle /*identity_cert_error*/) override {
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);
}
}
private:
RefCountedPtr<grpc_tls_certificate_distributor> parent_;
std::string cert_name_;
};
class IdentityCertificatesWatcher
@ -78,300 +76,142 @@ class IdentityCertificatesWatcher
// presently, the watcher is immediately deleted when
// CancelTlsCertificatesWatch() is called, but that can potentially change in
// the future.
IdentityCertificatesWatcher(
RefCountedPtr<grpc_tls_certificate_distributor> parent,
std::string cert_name)
: parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
explicit IdentityCertificatesWatcher(
RefCountedPtr<grpc_tls_certificate_distributor> parent)
: parent_(std::move(parent)) {}
void OnCertificatesChanged(
absl::optional<absl::string_view> /* root_certs */,
absl::optional<PemKeyCertPairList> key_cert_pairs) override {
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*/,
grpc_error_handle identity_cert_error) override {
if (!identity_cert_error.ok()) {
parent_->SetErrorForCert(cert_name_, absl::nullopt,
parent_->SetErrorForCert("", absl::nullopt,
identity_cert_error /* pass the ref */);
}
}
private:
RefCountedPtr<grpc_tls_certificate_distributor> parent_;
std::string cert_name_;
};
} // namespace
//
// XdsCertificateProvider::ClusterCertificateState
// XdsCertificateProvider
//
XdsCertificateProvider::ClusterCertificateState::~ClusterCertificateState() {
if (root_cert_watcher_ != nullptr) {
root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
}
if (identity_cert_watcher_ != nullptr) {
identity_cert_distributor_->CancelTlsCertificatesWatch(
identity_cert_watcher_);
}
XdsCertificateProvider::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)
: 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 {
return !watching_root_certs_ && !watching_identity_certs_ &&
root_cert_distributor_ == nullptr &&
identity_cert_distributor_ == nullptr;
XdsCertificateProvider::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)
: 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::
UpdateRootCertNameAndDistributor(
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 &&
root_cert_distributor_ == root_cert_distributor) {
return;
}
root_cert_name_ = std::string(root_cert_name);
if (watching_root_certs_) {
// The root certificates are being watched. Swap out the watcher.
if (root_cert_distributor_ != nullptr) {
root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
}
if (root_cert_distributor != nullptr) {
UpdateRootCertWatcher(cert_name, root_cert_distributor.get());
} else {
root_cert_watcher_ = nullptr;
xds_certificate_provider_->distributor_->SetErrorForCert(
"",
XdsCertificateProvider::~XdsCertificateProvider() {
distributor_->SetWatchStatusCallback(nullptr);
}
UniqueTypeName XdsCertificateProvider::type() const {
static UniqueTypeName::Factory kFactory("Xds");
return kFactory.Create();
}
void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
bool root_being_watched,
bool identity_being_watched) {
if (!cert_name.empty()) {
if (root_being_watched) {
distributor_->SetErrorForCert(
cert_name,
GRPC_ERROR_CREATE(
"No certificate provider available for root certificates"),
absl::nullopt);
}
}
// Swap out the root certificate distributor
root_cert_distributor_ = std::move(root_cert_distributor);
}
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,
if (identity_being_watched) {
distributor_->SetErrorForCert(
cert_name, absl::nullopt,
GRPC_ERROR_CREATE(
"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
// as identity_cert_distributor. Always using two separate watchers
// 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
// on the number of callbacks.
if (root_being_watched && !watching_root_certs_) {
// We need to start watching root certs.
watching_root_certs_ = true;
if (root_cert_distributor_ == nullptr) {
xds_certificate_provider_->distributor_->SetErrorForCert(
if (root_being_watched && root_cert_watcher_ == nullptr) {
// Start watching root cert.
if (root_cert_provider_ == nullptr) {
distributor_->SetErrorForCert(
cert_name,
GRPC_ERROR_CREATE(
"No certificate provider available for root certificates"),
absl::nullopt);
} else {
UpdateRootCertWatcher(cert_name, root_cert_distributor_.get());
}
} else if (!root_being_watched && watching_root_certs_) {
// We need to cancel root certs watch.
watching_root_certs_ = false;
if (root_cert_distributor_ != nullptr) {
root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
root_cert_watcher_ = nullptr;
auto watcher = std::make_unique<RootCertificatesWatcher>(distributor_);
root_cert_watcher_ = watcher.get();
root_cert_provider_->distributor()->WatchTlsCertificates(
std::move(watcher), root_cert_name_, absl::nullopt);
}
GPR_ASSERT(root_cert_watcher_ == nullptr);
}
if (identity_being_watched && !watching_identity_certs_) {
watching_identity_certs_ = true;
if (identity_cert_distributor_ == nullptr) {
xds_certificate_provider_->distributor_->SetErrorForCert(
} else if (!root_being_watched && root_cert_watcher_ != nullptr) {
// Cancel root cert watch.
GPR_ASSERT(root_cert_provider_ != nullptr);
root_cert_provider_->distributor()->CancelTlsCertificatesWatch(
root_cert_watcher_);
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,
GRPC_ERROR_CREATE(
"No certificate provider available for identity certificates"));
} else {
UpdateIdentityCertWatcher(cert_name, identity_cert_distributor_.get());
}
} else if (!identity_being_watched && watching_identity_certs_) {
watching_identity_certs_ = false;
if (identity_cert_distributor_ != nullptr) {
identity_cert_distributor_->CancelTlsCertificatesWatch(
identity_cert_watcher_);
identity_cert_watcher_ = nullptr;
auto watcher =
std::make_unique<IdentityCertificatesWatcher>(distributor_);
identity_cert_watcher_ = watcher.get();
identity_cert_provider_->distributor()->WatchTlsCertificates(
std::move(watcher), absl::nullopt, identity_cert_name_);
}
GPR_ASSERT(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;
} 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;
}
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

@ -44,7 +44,21 @@ namespace grpc_core {
class XdsCertificateProvider : public grpc_tls_certificate_provider {
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;
RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
@ -53,94 +67,27 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
UniqueTypeName type() const override;
bool ProvidesRootCerts(const std::string& cert_name);
void UpdateRootCertNameAndDistributor(
const std::string& cert_name, absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor);
bool ProvidesIdentityCerts(const std::string& cert_name);
void UpdateIdentityCertNameAndDistributor(
const std::string& cert_name, absl::string_view identity_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor>
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);
bool ProvidesRootCerts() const { return root_cert_provider_ != nullptr; }
bool ProvidesIdentityCerts() const {
return identity_cert_provider_ != nullptr;
}
bool require_client_certificate() const {
return require_client_certificate_;
}
const std::vector<StringMatcher>& san_matchers() const {
return san_matchers_;
}
static absl::string_view ChannelArgName() {
return "grpc.internal.xds_certificate_provider";
}
static int ChannelArgsCompare(const XdsCertificateProvider* a,
const XdsCertificateProvider* b) {
if (a == nullptr || b == nullptr) return QsortCompare(a, b);
return a->Compare(b);
}
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 {
// TODO(yashykt): Maybe do something better here.
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);
RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
Mutex mu_;
std::map<std::string /*cert_name*/, std::unique_ptr<ClusterCertificateState>>
certificate_state_map_ ABSL_GUARDED_BY(mu_);
// Use a separate mutex for san_matchers_ to avoid deadlocks since
// 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
// deadlock cycle is formed as -
// WatchStatusCallback() -> SetKeyMaterials() ->
// TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnCertificatesChanged()
// -> 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_);
RefCountedPtr<grpc_tls_certificate_provider> root_cert_provider_;
std::string root_cert_name_;
RefCountedPtr<grpc_tls_certificate_provider> identity_cert_provider_;
std::string identity_cert_name_;
std::vector<StringMatcher> san_matchers_;
bool require_client_certificate_ = false;
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
root_cert_watcher_ = nullptr;
grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
identity_cert_watcher_ = nullptr;
};
} // namespace grpc_core

@ -107,15 +107,8 @@ std::string XdsClusterResource::ToString() const {
}
contents.push_back(
absl::StrCat("max_concurrent_requests=", max_concurrent_requests));
if (!override_host_statuses.empty()) {
std::vector<const char*> statuses;
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, ", "), "}"));
}
contents.push_back(absl::StrCat("override_host_statuses=",
override_host_statuses.ToString()));
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
@ -625,6 +618,7 @@ absl::StatusOr<std::shared_ptr<const XdsClusterResource>> CdsResourceParse(
// Validate override host status.
const auto* common_lb_config =
envoy_config_cluster_v3_Cluster_common_lb_config(cluster);
bool override_host_status_found = false;
if (common_lb_config != nullptr) {
ValidationErrors::ScopedField field(&errors, ".common_lb_config");
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) {
auto status = XdsHealthStatus::FromUpb(statuses[i]);
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.
if (!errors.ok()) {
return errors.status(absl::StatusCode::kInvalidArgument,

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

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

@ -20,6 +20,8 @@
#include <string>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "envoy/config/core/v3/health_check.upb.h"
namespace grpc_core {
@ -58,8 +60,16 @@ const char* XdsHealthStatus::ToString() const {
}
}
bool operator<(const XdsHealthStatus& hs1, const XdsHealthStatus& hs2) {
return hs1.status() < hs2.status();
std::string XdsHealthStatusSet::ToString() const {
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

@ -70,6 +70,8 @@ class XdsHealthStatusSet {
return status_mask_ == other.status_mask_;
}
bool Empty() const { return status_mask_ == 0; }
void Clear() { status_mask_ = 0; }
void Add(XdsHealthStatus status) { status_mask_ |= (0x1 << status.status()); }
@ -78,12 +80,12 @@ class XdsHealthStatusSet {
return status_mask_ & (0x1 << status.status());
}
std::string ToString() const;
private:
int status_mask_ = 0;
};
bool operator<(const XdsHealthStatus& hs1, const XdsHealthStatus& hs2);
} // namespace grpc_core
#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");
}
//
// 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
//
std::string XdsRouteConfigResource::ToString() const {
std::vector<std::string> parts;
parts.reserve(virtual_hosts.size());
for (const VirtualHost& vhost : virtual_hosts) {
parts.push_back(
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(vhost.ToString());
}
parts.push_back("cluster_specifier_plugins={\n");
for (const auto& it : cluster_specifier_plugin_map) {

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

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

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

@ -46,9 +46,8 @@ namespace grpc_core {
class XdsCertificateVerifier : public grpc_tls_certificate_verifier {
public:
XdsCertificateVerifier(
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider,
std::string cluster_name);
explicit XdsCertificateVerifier(
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider);
bool Verify(grpc_tls_custom_verification_check_request* request,
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;
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider_;
std::string cluster_name_;
};
class XdsCredentials final : public grpc_channel_credentials {

@ -34,8 +34,6 @@ extern void RegisterXdsClusterManagerLbPolicy(
CoreConfiguration::Builder* builder);
extern void RegisterXdsClusterImplLbPolicy(CoreConfiguration::Builder* builder);
extern void RegisterCdsLbPolicy(CoreConfiguration::Builder* builder);
extern void RegisterXdsClusterResolverLbPolicy(
CoreConfiguration::Builder* builder);
extern void RegisterXdsOverrideHostLbPolicy(
CoreConfiguration::Builder* builder);
extern void RegisterXdsWrrLocalityLbPolicy(CoreConfiguration::Builder* builder);
@ -58,7 +56,6 @@ void RegisterExtraFilters(CoreConfiguration::Builder* builder) {
RegisterXdsClusterManagerLbPolicy(builder);
RegisterXdsClusterImplLbPolicy(builder);
RegisterCdsLbPolicy(builder);
RegisterXdsClusterResolverLbPolicy(builder);
RegisterXdsOverrideHostLbPolicy(builder);
RegisterXdsWrrLocalityLbPolicy(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/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_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_wrr_locality.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/polling_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_trace.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_service_config.cc',

@ -83,29 +83,6 @@ TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
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) {
const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
@ -163,15 +140,15 @@ TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
<< service_config.status();
}
TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) {
const char* test_json =
"{\"loadBalancingPolicy\":\"xds_cluster_resolver_experimental\"}";
TEST_F(ClientChannelParserTest,
LegacyLoadBalancingPolicySpecifiesPolicyThatRequiresConfig) {
const char* test_json = "{\"loadBalancingPolicy\":\"rls_experimental\"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingPolicy error:LB policy "
"\"xds_cluster_resolver_experimental\" requires a config. Please "
"\"rls_experimental\" requires a config. Please "
"use loadBalancingConfig instead.]")
<< service_config.status();
}

@ -542,7 +542,8 @@ class LoadBalancingPolicyTest : public ::testing::Test {
const ChannelArgs& /*per_address_args*/,
const ChannelArgs& args) override {
// 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);
if (it == test_->subchannel_pool_.end()) {
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.
LoadBalancingPolicy::UpdateArgs BuildUpdate(
absl::Span<const EndpointAddresses> endpoints,
RefCountedPtr<LoadBalancingPolicy::Config> config) {
RefCountedPtr<LoadBalancingPolicy::Config> config,
ChannelArgs args = ChannelArgs()) {
LoadBalancingPolicy::UpdateArgs update;
update.addresses = std::make_shared<EndpointAddressesListIterator>(
EndpointAddressesList(endpoints.begin(), endpoints.end()));
update.config = std::move(config);
update.args = std::move(args);
return update;
}
@ -791,9 +794,10 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// Convenient overload that takes a flat address list.
LoadBalancingPolicy::UpdateArgs BuildUpdate(
absl::Span<const absl::string_view> addresses,
RefCountedPtr<LoadBalancingPolicy::Config> config) {
RefCountedPtr<LoadBalancingPolicy::Config> config,
ChannelArgs args = ChannelArgs()) {
return BuildUpdate(MakeEndpointAddressesListFromAddressList(addresses),
std::move(config));
std::move(config), std::move(args));
}
// 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.
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> ExpectRoundRobinStartup(
absl::Span<const EndpointAddresses> endpoints) {
absl::Span<const EndpointAddresses> endpoints,
SourceLocation location = SourceLocation()) {
GPR_ASSERT(!endpoints.empty());
// There should be a subchannel for every address.
// 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];
std::string address_str = grpc_sockaddr_to_uri(&address).value();
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;
endpoint_subchannels.back().push_back(subchannel);
if (i == 0) {
@ -1190,16 +1197,19 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// We should request a connection to the first address of each endpoint,
// and not to any of the subsequent addresses.
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) {
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
// CONNECTING state.
for (size_t i = 0; i < endpoint_subchannels.size(); ++i) {
endpoint_subchannels[i][0]->SetConnectivityState(GRPC_CHANNEL_CONNECTING);
if (i == 0) ExpectConnectingUpdate();
if (i == 0) ExpectConnectingUpdate(location);
}
// The connection attempts should succeed.
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> picker;
@ -1209,8 +1219,9 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// When the first subchannel becomes READY, accept any number of
// CONNECTING updates with a picker that queues followed by a READY
// update with a picker that repeatedly returns only the first address.
picker = WaitForConnected();
ExpectRoundRobinPicks(picker.get(), {chosen_addresses[0]});
picker = WaitForConnected(location);
ExpectRoundRobinPicks(picker.get(), {chosen_addresses[0]}, {}, 3,
location);
} else {
// When each subsequent subchannel becomes READY, we accept any number
// of READY updates where the picker returns only the previously
@ -1219,7 +1230,8 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// connected subchannel.
picker = WaitForRoundRobinListChange(
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;
@ -1228,9 +1240,10 @@ class LoadBalancingPolicyTest : public ::testing::Test {
// A convenient override that takes a flat list of addresses, one per
// endpoint.
RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> ExpectRoundRobinStartup(
absl::Span<const absl::string_view> addresses) {
absl::Span<const absl::string_view> addresses,
SourceLocation location = SourceLocation()) {
return ExpectRoundRobinStartup(
MakeEndpointAddressesListFromAddressList(addresses));
MakeEndpointAddressesListFromAddressList(addresses), location);
}
// Expects zero or more picker updates, each of which returns

@ -43,12 +43,10 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfig) {
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":[\n"
" {\"grpclb\":{}}\n"
" ],\n"
" \"overrideHostStatus\": [\n"
" \"DRAINING\", \"HEALTHY\", \"UNKNOWN\""
" ]"
" ]\n"
" }\n"
" }]\n"
"}\n";
@ -64,16 +62,11 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfig) {
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::kDraining),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown),
}));
auto* override_host_lb_config =
static_cast<XdsOverrideHostLbConfig*>(lb_config.get());
EXPECT_EQ(override_host_lb_config->cluster_name(), "foo");
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) {
@ -81,6 +74,7 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfigWithRR) {
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":[\n"
" {\"round_robin\":{}}\n"
" ]\n"
@ -99,77 +93,32 @@ TEST(XdsOverrideHostConfigParsingTest, ValidConfigWithRR) {
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>();
ASSERT_NE(override_host_lb_config->child_config(), nullptr);
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)}));
auto* override_host_lb_config =
static_cast<XdsOverrideHostLbConfig*>(lb_config.get());
EXPECT_EQ(override_host_lb_config->cluster_name(), "foo");
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 =
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"childPolicy\":[\n"
" {\"grpclb\":{}}\n"
" ]"
" {\"round_robin\":{}}\n"
" ]\n"
" }\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<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(0));
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);
EXPECT_EQ(override_host_lb_config->child_config()->name(), "grpclb");
ASSERT_FALSE(service_config.ok());
EXPECT_EQ(service_config.status(),
absl::InvalidArgumentError(
"errors validating service config: [field:loadBalancingConfig "
"error:errors validating xds_override_host LB policy config: "
"[field:clusterName error:field not present]]"));
}
TEST(XdsOverrideHostConfigParsingTest, ReportsMissingChildPolicyField) {
@ -177,6 +126,7 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsMissingChildPolicyField) {
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\"\n"
" }\n"
" }]\n"
"}\n";
@ -195,6 +145,7 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsChildPolicyShouldBeArray) {
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":{\n"
" \"grpclb\":{}\n"
" }\n"
@ -216,6 +167,7 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsEmptyChildPolicyArray) {
"{\n"
" \"loadBalancingConfig\":[{\n"
" \"xds_override_host_experimental\":{\n"
" \"clusterName\": \"foo\",\n"
" \"childPolicy\":[\n"
" ]\n"
" }\n"
@ -231,29 +183,6 @@ TEST(XdsOverrideHostConfigParsingTest, ReportsEmptyChildPolicyArray) {
"[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 testing
} // namespace grpc_core

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

@ -75,7 +75,7 @@ TEST(TlsCredentialsOptionsComparatorTest, DifferentCertificateVerifier) {
auto* options_1 = grpc_tls_credentials_options_create();
auto* options_2 = grpc_tls_credentials_options_create();
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_2 == *options_1);
delete options_1;

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

@ -25,6 +25,7 @@
#include <grpc/grpc.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
@ -52,6 +53,28 @@ PemKeyCertPairList MakeKeyCertPairsType2() {
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
: public grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface {
public:
@ -102,14 +125,10 @@ class TestCertificatesWatcher
TEST(
XdsCertificateProviderTest,
RootCertDistributorDifferentFromIdentityCertDistributorDifferentCertNames) {
auto root_cert_distributor =
MakeRefCounted<grpc_tls_certificate_distributor>();
auto identity_cert_distributor =
MakeRefCounted<grpc_tls_certificate_distributor>();
XdsCertificateProvider provider;
provider.UpdateRootCertNameAndDistributor("", "root", root_cert_distributor);
provider.UpdateIdentityCertNameAndDistributor("", "identity",
identity_cert_distributor);
auto root_provider = MakeRefCounted<TestCertProvider>();
auto identity_provider = MakeRefCounted<TestCertProvider>();
XdsCertificateProvider provider(root_provider, "root", identity_provider,
"identity", {});
auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -118,15 +137,16 @@ TEST(
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Update both root certs and identity certs
root_cert_distributor->SetKeyMaterials("root", kRootCert1, absl::nullopt);
identity_cert_distributor->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1());
root_provider->distributor()->SetKeyMaterials("root", kRootCert1,
absl::nullopt);
identity_provider->distributor()->SetKeyMaterials("identity", absl::nullopt,
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());
// Second update for just root certs
root_cert_distributor->SetKeyMaterials(
root_provider->distributor()->SetKeyMaterials(
"root", kRootCert2,
MakeKeyCertPairsType2() /* does not have an effect */);
EXPECT_EQ(watcher->root_certs(), kRootCert2);
@ -134,7 +154,7 @@ TEST(
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Second update for identity certs
identity_cert_distributor->SetKeyMaterials(
identity_provider->distributor()->SetKeyMaterials(
"identity", kRootCert1 /* does not have an effect */,
MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_certs(), kRootCert2);
@ -142,9 +162,9 @@ TEST(
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Set error for both root and identity
root_cert_distributor->SetErrorForCert(
root_provider->distributor()->SetErrorForCert(
"root", GRPC_ERROR_CREATE(kRootErrorMessage), absl::nullopt);
identity_cert_distributor->SetErrorForCert(
identity_provider->distributor()->SetErrorForCert(
"identity", absl::nullopt, GRPC_ERROR_CREATE(kIdentityErrorMessage));
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
@ -153,7 +173,8 @@ TEST(
EXPECT_THAT(StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(kIdentityErrorMessage));
// 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->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
@ -161,8 +182,8 @@ TEST(
::testing::HasSubstr(kIdentityErrorMessage));
// Send an update for identity certs. Test that the identity cert error is
// reset.
identity_cert_distributor->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1());
identity_provider->distributor()->SetKeyMaterials("identity", absl::nullopt,
MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_certs(), kRootCert1);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
@ -171,14 +192,10 @@ TEST(
TEST(XdsCertificateProviderTest,
RootCertDistributorDifferentFromIdentityCertDistributorSameCertNames) {
auto root_cert_distributor =
MakeRefCounted<grpc_tls_certificate_distributor>();
auto identity_cert_distributor =
MakeRefCounted<grpc_tls_certificate_distributor>();
XdsCertificateProvider provider;
provider.UpdateRootCertNameAndDistributor("", "test", root_cert_distributor);
provider.UpdateIdentityCertNameAndDistributor("", "test",
identity_cert_distributor);
auto root_provider = MakeRefCounted<TestCertProvider>();
auto identity_provider = MakeRefCounted<TestCertProvider>();
XdsCertificateProvider provider(root_provider, "test", identity_provider,
"test", {});
auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -187,30 +204,32 @@ TEST(XdsCertificateProviderTest,
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Update both root certs and identity certs
root_cert_distributor->SetKeyMaterials("test", kRootCert1, absl::nullopt);
identity_cert_distributor->SetKeyMaterials("test", absl::nullopt,
MakeKeyCertPairsType1());
root_provider->distributor()->SetKeyMaterials("test", kRootCert1,
absl::nullopt);
identity_provider->distributor()->SetKeyMaterials("test", absl::nullopt,
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());
// 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->key_cert_pairs(), MakeKeyCertPairsType1());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
EXPECT_EQ(watcher->identity_cert_error(), absl::OkStatus());
// Second update for identity certs
identity_cert_distributor->SetKeyMaterials("test", absl::nullopt,
MakeKeyCertPairsType2());
identity_provider->distributor()->SetKeyMaterials("test", absl::nullopt,
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
root_cert_distributor->SetErrorForCert(
root_provider->distributor()->SetErrorForCert(
"test", GRPC_ERROR_CREATE(kRootErrorMessage), absl::nullopt);
identity_cert_distributor->SetErrorForCert(
identity_provider->distributor()->SetErrorForCert(
"test", absl::nullopt, GRPC_ERROR_CREATE(kIdentityErrorMessage));
EXPECT_EQ(watcher->root_certs(), kRootCert2);
EXPECT_EQ(watcher->key_cert_pairs(), MakeKeyCertPairsType2());
@ -219,7 +238,8 @@ TEST(XdsCertificateProviderTest,
EXPECT_THAT(StatusToString(watcher->identity_cert_error()),
::testing::HasSubstr(kIdentityErrorMessage));
// 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->key_cert_pairs(), MakeKeyCertPairsType2());
EXPECT_EQ(watcher->root_cert_error(), absl::OkStatus());
@ -227,25 +247,25 @@ TEST(XdsCertificateProviderTest,
::testing::HasSubstr(kIdentityErrorMessage));
// Send an update for identity certs. Test that the identity cert error is
// reset.
identity_cert_distributor->SetKeyMaterials("test", absl::nullopt,
MakeKeyCertPairsType1());
identity_provider->distributor()->SetKeyMaterials("test", absl::nullopt,
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());
// Test update on unwatched cert name
identity_cert_distributor->SetKeyMaterials("identity", kRootCert2,
MakeKeyCertPairsType2());
root_cert_distributor->SetKeyMaterials("root", kRootCert1,
MakeKeyCertPairsType1());
identity_provider->distributor()->SetKeyMaterials("identity", kRootCert2,
MakeKeyCertPairsType2());
root_provider->distributor()->SetKeyMaterials("root", kRootCert1,
MakeKeyCertPairsType1());
}
TEST(XdsCertificateProviderTest,
RootCertDistributorSameAsIdentityCertDistributorDifferentCertNames) {
auto distributor = MakeRefCounted<grpc_tls_certificate_distributor>();
XdsCertificateProvider provider;
provider.UpdateRootCertNameAndDistributor("", "root", distributor);
provider.UpdateIdentityCertNameAndDistributor("", "identity", distributor);
auto root_and_identity_provider = MakeRefCounted<TestCertProvider>();
auto distributor = root_and_identity_provider->distributor();
XdsCertificateProvider provider(root_and_identity_provider, "root",
root_and_identity_provider, "identity", {});
auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -306,10 +326,10 @@ TEST(XdsCertificateProviderTest,
TEST(XdsCertificateProviderTest,
RootCertDistributorSameAsIdentityCertDistributorSameCertNames) {
auto distributor = MakeRefCounted<grpc_tls_certificate_distributor>();
XdsCertificateProvider provider;
provider.UpdateRootCertNameAndDistributor("", "", distributor);
provider.UpdateIdentityCertNameAndDistributor("", "", distributor);
auto root_and_identity_provider = MakeRefCounted<TestCertProvider>();
auto distributor = root_and_identity_provider->distributor();
XdsCertificateProvider provider(root_and_identity_provider, "",
root_and_identity_provider, "", {});
auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "", "");
@ -367,186 +387,8 @@ TEST(XdsCertificateProviderTest,
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) {
XdsCertificateProvider provider;
XdsCertificateProvider provider(nullptr, "", nullptr, "", {});
auto* watcher = new TestCertificatesWatcher;
provider.distributor()->WatchTlsCertificates(
std::unique_ptr<TestCertificatesWatcher>(watcher), "test", "test");

@ -1347,11 +1347,66 @@ TEST_F(HostOverrideStatusTest, PassesOnRelevantHealthStatuses) {
EXPECT_EQ(*decode_result.name, "foo");
auto& resource =
static_cast<const XdsClusterResource&>(**decode_result.resource);
EXPECT_THAT(resource.override_host_statuses,
::testing::UnorderedElementsAre(
XdsHealthStatus(XdsHealthStatus::kUnknown),
XdsHealthStatus(XdsHealthStatus::kHealthy),
XdsHealthStatus(XdsHealthStatus::kDraining)));
EXPECT_EQ(resource.override_host_statuses.ToString(),
"{UNKNOWN, HEALTHY, DRAINING}");
}
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

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

@ -330,9 +330,9 @@ TEST_P(CdsDeletionTest, ClusterDeleted) {
SendRpcsUntil(DEBUG_LOCATION, [](const RpcResult& result) {
if (result.status.ok()) return true; // Keep going.
EXPECT_EQ(StatusCode::UNAVAILABLE, result.status.error_code());
EXPECT_EQ(absl::StrCat("CDS resource \"", kDefaultClusterName,
"\" does not exist"),
result.status.error_message());
EXPECT_EQ(
absl::StrCat("CDS resource ", kDefaultClusterName, " does not exist"),
result.status.error_message());
return false;
});
// 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.
constexpr char kErrorMessage[] =
"empty address list: DNS resolution failed for server.example.com:443 "
"\\(UNAVAILABLE: injected error\\)";
"empty address list: DNS resolution failed for server.example.com:443: "
"UNAVAILABLE: injected error";
CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE, kErrorMessage);
// Send an EDS update that moves locality1 to priority 0.
args1 = EdsResourceArgs({
@ -613,7 +613,7 @@ TEST_P(AggregateClusterTest, DependencyLoopWithNoLeafClusters) {
cluster_config.add_clusters(kNewClusterName1);
custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
balancer_->ads_service()->SetCdsResource(cluster);
// kDefaultClusterName points to the default cluster.
// kNewClusterName1 points to the default cluster.
cluster.set_name(kNewClusterName1);
cluster_config.Clear();
cluster_config.add_clusters(kDefaultClusterName);
@ -621,8 +621,8 @@ TEST_P(AggregateClusterTest, DependencyLoopWithNoLeafClusters) {
balancer_->ads_service()->SetCdsResource(cluster);
// RPCs should fail.
CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE,
"new_cluster_1: FAILED_PRECONDITION: "
"aggregate cluster graph has no leaf clusters");
"aggregate cluster dependency graph for cluster_name "
"has no leaf clusters");
}
TEST_P(AggregateClusterTest, DependencyLoopWithLeafClusters) {

@ -429,7 +429,7 @@ TEST_P(TimeoutTest, CdsServerIgnoresRequest) {
balancer_->ads_service()->IgnoreResourceType(kCdsTypeUrl);
CheckRpcSendFailure(
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));
}
@ -437,7 +437,7 @@ TEST_P(TimeoutTest, CdsResourceNotPresentInRequest) {
balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
CheckRpcSendFailure(
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));
}
@ -461,9 +461,9 @@ TEST_P(TimeoutTest, CdsSecondResourceNotPresentInRequest) {
[&](const RpcResult& result) {
if (result.status.ok()) return true; // Keep going.
EXPECT_EQ(StatusCode::UNAVAILABLE, result.status.error_code());
EXPECT_EQ(absl::StrCat("CDS resource \"", kNewClusterName,
"\" does not exist"),
result.status.error_message());
EXPECT_EQ(
absl::StrCat("CDS resource ", kNewClusterName, " does not exist"),
result.status.error_message());
return false;
},
/*timeout_ms=*/30000, RpcOptions().set_timeout_ms(4000));
@ -912,10 +912,9 @@ TEST_P(XdsFederationTest, CdsResourceNameAuthorityUnknown) {
grpc::Status status = stub2->Echo(&context, request, &response);
EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE);
EXPECT_EQ(status.error_message(),
absl::StrCat(
kNewClusterName,
": UNAVAILABLE: authority \"xds.unknown.com\" not present in "
"bootstrap config"));
absl::StrCat(kNewClusterName,
": authority \"xds.unknown.com\" not present in "
"bootstrap config"));
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_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/"
"edsservice_name (UNAVAILABLE: authority \"xds.unknown.com\" not "
"present in bootstrap config)");
"edsservice_name: UNAVAILABLE: authority \"xds.unknown.com\" not "
"present in bootstrap config");
ASSERT_EQ(GRPC_CHANNEL_TRANSIENT_FAILURE, channel2->GetState(false));
}

@ -680,7 +680,7 @@ TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpClusterDoesNotExist) {
balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
CheckRpcSendFailure(
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));
auto csds_response = FetchCsdsResponse();
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_P(FaultInjectionTest, XdsFaultInjectionAlwaysAbort) {
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
HTTPFault http_fault;
auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();

@ -470,6 +470,8 @@ TEST_P(LdsRdsTest, ChooseLastRoute) {
}
TEST_P(LdsRdsTest, NoMatchingRoute) {
EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
RouteConfiguration route_config = default_route_config_;
route_config.mutable_virtual_hosts(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
// matching route has an action other than RouteAction.
TEST_P(LdsRdsTest, MatchingRouteHasNoRouteAction) {
EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
RouteConfiguration route_config = default_route_config_;
// Set a route with an inappropriate route action
auto* vhost = route_config.mutable_virtual_hosts(0);

@ -101,7 +101,7 @@ _DATA_MEMBERS = [
),
test_name="DifferentCertificateVerifier",
test_value_1="MakeRefCounted<HostNameCertificateVerifier>()",
test_value_2='MakeRefCounted<XdsCertificateVerifier>(nullptr, "")',
test_value_2="MakeRefCounted<XdsCertificateVerifier>(nullptr)",
),
DataMember(
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_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_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.h \
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.h \
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.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.h \
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_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_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.h \
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/sockaddr/README.md \
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.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.h \
src/core/ext/filters/client_channel/retry_filter_legacy_call_data.cc \

Loading…
Cancel
Save