XdsBootstrap: split interface from implementation (#30759)

* create XdsBootstrapInterface

* move gRPC-specific bootstrap code into its own module

* move LookupAuthority() back to base class

* share constants

* clang-format

* Automated change: Fix sanity tests

* fix xds_bootstrap_test

* clang-format

Co-authored-by: markdroth <markdroth@users.noreply.github.com>
pull/30767/head
Mark D. Roth 3 years ago committed by GitHub
parent 5a5adfb1b9
commit 0e30264a5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      BUILD
  2. 1
      CMakeLists.txt
  3. 2
      Makefile
  4. 2
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 2
      gRPC-C++.podspec
  8. 3
      gRPC-Core.podspec
  9. 2
      grpc.gemspec
  10. 1
      grpc.gyp
  11. 2
      package.xml
  12. 6
      src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
  13. 3
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
  14. 6
      src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
  15. 500
      src/core/ext/xds/xds_bootstrap.cc
  16. 91
      src/core/ext/xds/xds_bootstrap.h
  17. 521
      src/core/ext/xds/xds_bootstrap_grpc.cc
  18. 111
      src/core/ext/xds/xds_bootstrap_grpc.h
  19. 7
      src/core/ext/xds/xds_client_grpc.cc
  20. 1
      src/core/ext/xds/xds_client_grpc.h
  21. 10
      src/core/ext/xds/xds_common_types.cc
  22. 2
      src/core/ext/xds/xds_resource_type.h
  23. 1
      src/python/grpcio/grpc_core_dependencies.py
  24. 2
      test/core/xds/BUILD
  25. 56
      test/core/xds/xds_bootstrap_test.cc
  26. 2
      tools/doxygen/Doxyfile.c++.internal
  27. 2
      tools/doxygen/Doxyfile.core.internal

@ -4141,6 +4141,7 @@ grpc_cc_library(
"src/core/ext/xds/file_watcher_certificate_provider_factory.cc",
"src/core/ext/xds/xds_api.cc",
"src/core/ext/xds/xds_bootstrap.cc",
"src/core/ext/xds/xds_bootstrap_grpc.cc",
"src/core/ext/xds/xds_certificate_provider.cc",
"src/core/ext/xds/xds_client.cc",
"src/core/ext/xds/xds_client_grpc.cc",
@ -4168,6 +4169,7 @@ grpc_cc_library(
"src/core/ext/xds/upb_utils.h",
"src/core/ext/xds/xds_api.h",
"src/core/ext/xds/xds_bootstrap.h",
"src/core/ext/xds/xds_bootstrap_grpc.h",
"src/core/ext/xds/xds_certificate_provider.h",
"src/core/ext/xds/xds_channel_args.h",
"src/core/ext/xds/xds_client.h",

1
CMakeLists.txt generated

@ -2056,6 +2056,7 @@ add_library(grpc
src/core/ext/xds/file_watcher_certificate_provider_factory.cc
src/core/ext/xds/xds_api.cc
src/core/ext/xds/xds_bootstrap.cc
src/core/ext/xds/xds_bootstrap_grpc.cc
src/core/ext/xds/xds_certificate_provider.cc
src/core/ext/xds/xds_channel_stack_modifier.cc
src/core/ext/xds/xds_client.cc

2
Makefile generated

@ -1410,6 +1410,7 @@ LIBGRPC_SRC = \
src/core/ext/xds/file_watcher_certificate_provider_factory.cc \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_bootstrap_grpc.cc \
src/core/ext/xds/xds_certificate_provider.cc \
src/core/ext/xds/xds_channel_stack_modifier.cc \
src/core/ext/xds/xds_client.cc \
@ -3175,6 +3176,7 @@ src/core/ext/xds/certificate_provider_store.cc: $(OPENSSL_DEP)
src/core/ext/xds/file_watcher_certificate_provider_factory.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_api.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_bootstrap.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_bootstrap_grpc.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_certificate_provider.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_channel_stack_modifier.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_client.cc: $(OPENSSL_DEP)

@ -715,6 +715,7 @@ libs:
- src/core/ext/xds/upb_utils.h
- src/core/ext/xds/xds_api.h
- src/core/ext/xds/xds_bootstrap.h
- src/core/ext/xds/xds_bootstrap_grpc.h
- src/core/ext/xds/xds_certificate_provider.h
- src/core/ext/xds/xds_channel_args.h
- src/core/ext/xds/xds_channel_stack_modifier.h
@ -1420,6 +1421,7 @@ libs:
- src/core/ext/xds/file_watcher_certificate_provider_factory.cc
- src/core/ext/xds/xds_api.cc
- src/core/ext/xds/xds_bootstrap.cc
- src/core/ext/xds/xds_bootstrap_grpc.cc
- src/core/ext/xds/xds_certificate_provider.cc
- src/core/ext/xds/xds_channel_stack_modifier.cc
- src/core/ext/xds/xds_client.cc

1
config.m4 generated

@ -428,6 +428,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/xds/file_watcher_certificate_provider_factory.cc \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_bootstrap_grpc.cc \
src/core/ext/xds/xds_certificate_provider.cc \
src/core/ext/xds/xds_channel_stack_modifier.cc \
src/core/ext/xds/xds_client.cc \

1
config.w32 generated

@ -394,6 +394,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\xds\\file_watcher_certificate_provider_factory.cc " +
"src\\core\\ext\\xds\\xds_api.cc " +
"src\\core\\ext\\xds\\xds_bootstrap.cc " +
"src\\core\\ext\\xds\\xds_bootstrap_grpc.cc " +
"src\\core\\ext\\xds\\xds_certificate_provider.cc " +
"src\\core\\ext\\xds\\xds_channel_stack_modifier.cc " +
"src\\core\\ext\\xds\\xds_client.cc " +

2
gRPC-C++.podspec generated

@ -633,6 +633,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_bootstrap_grpc.h',
'src/core/ext/xds/xds_certificate_provider.h',
'src/core/ext/xds/xds_channel_args.h',
'src/core/ext/xds/xds_channel_stack_modifier.h',
@ -1488,6 +1489,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_bootstrap_grpc.h',
'src/core/ext/xds/xds_certificate_provider.h',
'src/core/ext/xds/xds_channel_args.h',
'src/core/ext/xds/xds_channel_stack_modifier.h',

3
gRPC-Core.podspec generated

@ -959,6 +959,8 @@ Pod::Spec.new do |s|
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_bootstrap_grpc.cc',
'src/core/ext/xds/xds_bootstrap_grpc.h',
'src/core/ext/xds/xds_certificate_provider.cc',
'src/core/ext/xds/xds_certificate_provider.h',
'src/core/ext/xds/xds_channel_args.h',
@ -2111,6 +2113,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/upb_utils.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_bootstrap_grpc.h',
'src/core/ext/xds/xds_certificate_provider.h',
'src/core/ext/xds/xds_channel_args.h',
'src/core/ext/xds/xds_channel_stack_modifier.h',

2
grpc.gemspec generated

@ -872,6 +872,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/xds/xds_api.h )
s.files += %w( src/core/ext/xds/xds_bootstrap.cc )
s.files += %w( src/core/ext/xds/xds_bootstrap.h )
s.files += %w( src/core/ext/xds/xds_bootstrap_grpc.cc )
s.files += %w( src/core/ext/xds/xds_bootstrap_grpc.h )
s.files += %w( src/core/ext/xds/xds_certificate_provider.cc )
s.files += %w( src/core/ext/xds/xds_certificate_provider.h )
s.files += %w( src/core/ext/xds/xds_channel_args.h )

1
grpc.gyp generated

@ -761,6 +761,7 @@
'src/core/ext/xds/file_watcher_certificate_provider_factory.cc',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_bootstrap_grpc.cc',
'src/core/ext/xds/xds_certificate_provider.cc',
'src/core/ext/xds/xds_channel_stack_modifier.cc',
'src/core/ext/xds/xds_client.cc',

2
package.xml generated

@ -854,6 +854,8 @@
<file baseinstalldir="/" name="src/core/ext/xds/xds_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_bootstrap.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_bootstrap.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_bootstrap_grpc.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_bootstrap_grpc.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_certificate_provider.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_certificate_provider.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/xds/xds_channel_args.h" role="src" />

@ -39,7 +39,7 @@
#include "src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.h"
#include "src/core/ext/xds/certificate_provider_store.h"
#include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/ext/xds/xds_bootstrap_grpc.h"
#include "src/core/ext/xds/xds_certificate_provider.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/ext/xds/xds_client_grpc.h"
@ -444,8 +444,8 @@ absl::StatusOr<bool> CdsLb::GenerateDiscoveryMechanismForCluster(
break;
}
if (state.update->lrs_load_reporting_server.has_value()) {
mechanism["lrsLoadReportingServer"] =
state.update->lrs_load_reporting_server->ToJson();
mechanism["lrsLoadReportingServer"] = GrpcXdsBootstrap::XdsServerToJson(
*state.update->lrs_load_reporting_server);
}
discovery_mechanisms->emplace_back(std::move(mechanism));
return true;

@ -44,6 +44,7 @@
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds.h"
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.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_client_stats.h"
@ -761,7 +762,7 @@ class XdsClusterImplLbFactory : public LoadBalancingPolicyFactory {
"field:lrsLoadReportingServer error:type should be object");
} else {
grpc_error_handle parser_error;
lrs_load_reporting_server = XdsBootstrap::XdsServer::Parse(
lrs_load_reporting_server = GrpcXdsBootstrap::XdsServerParse(
it->second.object_value(), &parser_error);
if (!GRPC_ERROR_IS_NONE(parser_error)) {
errors.emplace_back(

@ -47,6 +47,7 @@
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h"
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.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_client_stats.h"
@ -925,7 +926,8 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() {
}
if (discovery_config.lrs_load_reporting_server.has_value()) {
xds_cluster_impl_config["lrsLoadReportingServer"] =
discovery_config.lrs_load_reporting_server->ToJson();
GrpcXdsBootstrap::XdsServerToJson(
*discovery_config.lrs_load_reporting_server);
}
Json locality_picking_policy;
if (XdsOutlierDetectionEnabled()) {
@ -1191,7 +1193,7 @@ class XdsClusterResolverLbFactory : public LoadBalancingPolicyFactory {
} else {
grpc_error_handle parse_error;
discovery_mechanism->lrs_load_reporting_server.emplace(
XdsBootstrap::XdsServer::Parse(it->second, &parse_error));
GrpcXdsBootstrap::XdsServerParse(it->second, &parse_error));
if (!GRPC_ERROR_IS_NONE(parse_error)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("errors parsing lrs_load_reporting_server")));

@ -18,28 +18,16 @@
#include "src/core/ext/xds/xds_bootstrap.h"
#include <stdlib.h>
#include <set>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include <grpc/support/alloc.h>
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/json/json_util.h"
#include "src/core/lib/security/credentials/channel_creds_registry.h"
#include "src/core/lib/transport/error_utils.h"
namespace grpc_core {
@ -53,115 +41,13 @@ bool XdsFederationEnabled() {
return parse_succeeded && parsed_value;
}
namespace {
const absl::string_view kServerFeatureXdsV3 = "xds_v3";
const absl::string_view kServerFeatureIgnoreResourceDeletion =
"ignore_resource_deletion";
grpc_error_handle ParseChannelCreds(const Json::Object& json, size_t idx,
XdsBootstrap::XdsServer* server) {
std::vector<grpc_error_handle> error_list;
std::string type;
ParseJsonObjectField(json, "type", &type, &error_list);
const Json::Object* config_ptr = nullptr;
ParseJsonObjectField(json, "config", &config_ptr, &error_list,
/*required=*/false);
// Select the first channel creds type that we support.
if (server->channel_creds_type.empty() &&
CoreConfiguration::Get().channel_creds_registry().IsSupported(type)) {
Json config;
if (config_ptr != nullptr) config = *config_ptr;
if (!CoreConfiguration::Get().channel_creds_registry().IsValidConfig(
type, config)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"invalid config for channel creds type \"", type, "\"")));
}
server->channel_creds_type = std::move(type);
server->channel_creds_config = std::move(config);
}
return GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("errors parsing index ", idx), &error_list);
}
grpc_error_handle ParseChannelCredsArray(const Json::Array& json,
XdsBootstrap::XdsServer* server) {
std::vector<grpc_error_handle> error_list;
for (size_t i = 0; i < json.size(); ++i) {
const Json& child = json.at(i);
if (child.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("array element ", i, " is not an object")));
} else {
grpc_error_handle parse_error =
ParseChannelCreds(child.object_value(), i, server);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
if (server->channel_creds_type.empty()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"no known creds type found in \"channel_creds\""));
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"channel_creds\" array",
&error_list);
}
} // namespace
//
// XdsBootstrap::XdsServer
//
XdsBootstrap::XdsServer XdsBootstrap::XdsServer::Parse(
const Json& json, grpc_error_handle* error) {
std::vector<grpc_error_handle> error_list;
XdsServer server;
ParseJsonObjectField(json.object_value(), "server_uri", &server.server_uri,
&error_list);
const Json::Array* creds_array = nullptr;
ParseJsonObjectField(json.object_value(), "channel_creds", &creds_array,
&error_list);
if (creds_array != nullptr) {
grpc_error_handle parse_error =
ParseChannelCredsArray(*creds_array, &server);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
const Json::Array* server_features_array = nullptr;
ParseJsonObjectField(json.object_value(), "server_features",
&server_features_array, &error_list, /*required=*/false);
if (server_features_array != nullptr) {
for (const Json& feature_json : *server_features_array) {
if (feature_json.type() == Json::Type::STRING &&
(feature_json.string_value() == kServerFeatureXdsV3 ||
feature_json.string_value() ==
kServerFeatureIgnoreResourceDeletion)) {
server.server_features.insert(feature_json.string_value());
}
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
"errors parsing xds server", &error_list);
return server;
}
Json::Object XdsBootstrap::XdsServer::ToJson() const {
Json::Object channel_creds_json{{"type", channel_creds_type}};
if (channel_creds_config.type() != Json::Type::JSON_NULL) {
channel_creds_json["config"] = channel_creds_config;
}
Json::Object json{
{"server_uri", server_uri},
{"channel_creds", Json::Array{std::move(channel_creds_json)}},
};
if (!server_features.empty()) {
Json::Array server_features_json;
for (auto& feature : server_features) {
server_features_json.emplace_back(feature);
}
json["server_features"] = std::move(server_features_json);
}
return json;
}
constexpr absl::string_view XdsBootstrap::XdsServer::kServerFeatureXdsV3;
constexpr absl::string_view
XdsBootstrap::XdsServer::kServerFeatureIgnoreResourceDeletion;
bool XdsBootstrap::XdsServer::ShouldUseV3() const {
return server_features.find(std::string(kServerFeatureXdsV3)) !=
@ -177,107 +63,10 @@ bool XdsBootstrap::XdsServer::IgnoreResourceDeletion() const {
// XdsBootstrap
//
std::unique_ptr<XdsBootstrap> XdsBootstrap::Create(
absl::string_view json_string,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error) {
auto json = Json::Parse(json_string);
if (!json.ok()) {
*error = GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"Failed to parse bootstrap JSON string: ", json.status().ToString()));
return nullptr;
}
return absl::make_unique<XdsBootstrap>(
std::move(*json), std::move(certificate_provider_plugin_map), error);
}
XdsBootstrap::XdsBootstrap(
Json json,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error)
: certificate_provider_plugin_map_(
std::move(certificate_provider_plugin_map)) {
if (json.type() != Json::Type::OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"malformed JSON in bootstrap file");
return;
}
std::vector<grpc_error_handle> error_list;
auto it = json.mutable_object()->find("xds_servers");
if (it == json.mutable_object()->end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_servers\" field not present"));
} else if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_servers\" field is not an array"));
} else {
grpc_error_handle parse_error = ParseXdsServerList(&it->second, &servers_);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
it = json.mutable_object()->find("node");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"node\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseNode(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
if (XdsFederationEnabled()) {
it = json.mutable_object()->find("authorities");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"authorities\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseAuthorities(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
it = json.mutable_object()->find(
"client_default_listener_resource_name_template");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"client_default_listener_resource_name_template\" field is not a "
"string"));
} else {
client_default_listener_resource_name_template_ =
std::move(*it->second.mutable_string_value());
}
}
}
it = json.mutable_object()->find("server_listener_resource_name_template");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"server_listener_resource_name_template\" field is not a string"));
} else {
server_listener_resource_name_template_ =
std::move(*it->second.mutable_string_value());
}
}
it = json.mutable_object()->find("certificate_providers");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"certificate_providers\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseCertificateProviders(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing xds bootstrap file",
&error_list);
}
const XdsBootstrap::Authority* XdsBootstrap::LookupAuthority(
const std::string& name) const {
auto it = authorities_.find(name);
if (it != authorities_.end()) {
auto it = authorities().find(name);
if (it != authorities().end()) {
return &it->second;
}
return nullptr;
@ -285,8 +74,8 @@ const XdsBootstrap::Authority* XdsBootstrap::LookupAuthority(
bool XdsBootstrap::XdsServerExists(
const XdsBootstrap::XdsServer& server) const {
if (server == servers_[0]) return true;
for (auto& authority : authorities_) {
if (server == this->server()) return true;
for (auto& authority : authorities()) {
for (auto& xds_server : authority.second.xds_servers) {
if (server == xds_server) return true;
}
@ -294,277 +83,4 @@ bool XdsBootstrap::XdsServerExists(
return false;
}
grpc_error_handle XdsBootstrap::ParseXdsServerList(
Json* json, std::vector<XdsServer>* servers) {
std::vector<grpc_error_handle> error_list;
for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
Json& child = json->mutable_array()->at(i);
if (child.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("array element ", i, " is not an object")));
} else {
grpc_error_handle parse_error;
servers->emplace_back(XdsServer::Parse(child, &parse_error));
if (!GRPC_ERROR_IS_NONE(parse_error)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("errors parsing index ", i)));
error_list.push_back(parse_error);
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"xds_servers\" array",
&error_list);
}
grpc_error_handle XdsBootstrap::ParseAuthorities(Json* json) {
std::vector<grpc_error_handle> error_list;
for (auto& p : *(json->mutable_object())) {
if (p.second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
"field:authorities element error: element is not a object"));
continue;
}
grpc_error_handle parse_error = ParseAuthority(&p.second, p.first);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"authorities\"",
&error_list);
}
grpc_error_handle XdsBootstrap::ParseAuthority(Json* json,
const std::string& name) {
std::vector<grpc_error_handle> error_list;
Authority authority;
auto it =
json->mutable_object()->find("client_listener_resource_name_template");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"client_listener_resource_name_template\" field is not a string"));
} else {
std::string expected_prefix = absl::StrCat("xdstp://", name, "/");
if (!absl::StartsWith(it->second.string_value(), expected_prefix)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("\"client_listener_resource_name_template\" field "
"must begin with \"",
expected_prefix, "\"")));
} else {
authority.client_listener_resource_name_template =
std::move(*it->second.mutable_string_value());
}
}
}
it = json->mutable_object()->find("xds_servers");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_servers\" field is not an array"));
} else {
grpc_error_handle parse_error =
ParseXdsServerList(&it->second, &authority.xds_servers);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
if (error_list.empty()) {
authorities_[name] = std::move(authority);
}
return GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("errors parsing authority ", name), &error_list);
}
grpc_error_handle XdsBootstrap::ParseNode(Json* json) {
std::vector<grpc_error_handle> error_list;
node_ = absl::make_unique<Node>();
auto it = json->mutable_object()->find("id");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("\"id\" field is not a string"));
} else {
node_->id = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("cluster");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"cluster\" field is not a string"));
} else {
node_->cluster = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("locality");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"locality\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseLocality(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
it = json->mutable_object()->find("metadata");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"metadata\" field is not an object"));
} else {
node_->metadata = std::move(it->second);
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"node\" object",
&error_list);
}
grpc_error_handle XdsBootstrap::ParseLocality(Json* json) {
std::vector<grpc_error_handle> error_list;
auto it = json->mutable_object()->find("region");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"region\" field is not a string"));
} else {
node_->locality_region = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("zone");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"zone\" field is not a string"));
} else {
node_->locality_zone = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("sub_zone");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"sub_zone\" field is not a string"));
} else {
node_->locality_sub_zone = std::move(*it->second.mutable_string_value());
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"locality\" object",
&error_list);
}
grpc_error_handle XdsBootstrap::ParseCertificateProviders(Json* json) {
std::vector<grpc_error_handle> error_list;
for (auto& certificate_provider : *(json->mutable_object())) {
if (certificate_provider.second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"element \"", certificate_provider.first, "\" is not an object")));
} else {
grpc_error_handle parse_error = ParseCertificateProvider(
certificate_provider.first, &certificate_provider.second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR(
"errors parsing \"certificate_providers\" object", &error_list);
}
grpc_error_handle XdsBootstrap::ParseCertificateProvider(
const std::string& instance_name, Json* certificate_provider_json) {
std::vector<grpc_error_handle> error_list;
auto it = certificate_provider_json->mutable_object()->find("plugin_name");
if (it == certificate_provider_json->mutable_object()->end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"plugin_name\" field not present"));
} else if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"plugin_name\" field is not a string"));
} else {
std::string plugin_name = std::move(*(it->second.mutable_string_value()));
it = certificate_provider_json->mutable_object()->find("config");
if (it != certificate_provider_json->mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"config\" field is not an object"));
} else {
absl::Status status = certificate_provider_plugin_map_->AddPlugin(
instance_name, plugin_name, it->second);
if (!status.ok()) {
error_list.push_back(absl_status_to_grpc_error(status));
}
}
} else {
// "config" is an optional field, so create an empty JSON object.
absl::Status status = certificate_provider_plugin_map_->AddPlugin(
instance_name, plugin_name, Json::Object());
if (!status.ok()) {
error_list.push_back(absl_status_to_grpc_error(status));
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("errors parsing element \"", instance_name, "\""),
&error_list);
}
std::string XdsBootstrap::ToString() const {
std::vector<std::string> parts;
if (node_ != nullptr) {
parts.push_back(absl::StrFormat(
"node={\n"
" id=\"%s\",\n"
" cluster=\"%s\",\n"
" locality={\n"
" region=\"%s\",\n"
" zone=\"%s\",\n"
" sub_zone=\"%s\"\n"
" },\n"
" metadata=%s,\n"
"},\n",
node_->id, node_->cluster, node_->locality_region, node_->locality_zone,
node_->locality_sub_zone, node_->metadata.Dump()));
}
parts.push_back(
absl::StrFormat("servers=[\n"
" {\n"
" uri=\"%s\",\n"
" creds_type=%s,\n",
server().server_uri, server().channel_creds_type));
if (server().channel_creds_config.type() != Json::Type::JSON_NULL) {
parts.push_back(absl::StrFormat(" creds_config=%s,",
server().channel_creds_config.Dump()));
}
if (!server().server_features.empty()) {
parts.push_back(absl::StrCat(" server_features=[",
absl::StrJoin(server().server_features, ", "),
"],\n"));
}
parts.push_back(" }\n],\n");
if (!client_default_listener_resource_name_template_.empty()) {
parts.push_back(absl::StrFormat(
"client_default_listener_resource_name_template=\"%s\",\n",
client_default_listener_resource_name_template_));
}
if (!server_listener_resource_name_template_.empty()) {
parts.push_back(
absl::StrFormat("server_listener_resource_name_template=\"%s\",\n",
server_listener_resource_name_template_));
}
parts.push_back("authorities={\n");
for (const auto& entry : authorities_) {
parts.push_back(absl::StrFormat(" %s={\n", entry.first));
parts.push_back(
absl::StrFormat(" client_listener_resource_name_template=\"%s\",\n",
entry.second.client_listener_resource_name_template));
parts.push_back(
absl::StrFormat(" servers=[\n"
" {\n"
" uri=\"%s\",\n"
" creds_type=%s,\n",
entry.second.xds_servers[0].server_uri,
entry.second.xds_servers[0].channel_creds_type));
parts.push_back(" },\n");
}
parts.push_back("}");
parts.push_back("certificate_providers=");
parts.push_back(certificate_provider_plugin_map_->ToString());
return absl::StrJoin(parts, "");
}
} // namespace grpc_core

@ -19,38 +19,19 @@
#include <grpc/support/port_platform.h>
#include <algorithm>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h"
namespace grpc_core {
bool XdsFederationEnabled();
class XdsClient;
class XdsCertificateProviderPluginMapInterface {
public:
virtual ~XdsCertificateProviderPluginMapInterface() = default;
virtual absl::Status AddPlugin(const std::string& instance_name,
const std::string& plugin_name,
const Json& config) = 0;
virtual bool HasPlugin(const std::string& instance_name) const = 0;
virtual std::string ToString() const = 0;
};
class XdsBootstrap {
public:
struct Node {
@ -63,13 +44,15 @@ class XdsBootstrap {
};
struct XdsServer {
static constexpr absl::string_view kServerFeatureXdsV3 = "xds_v3";
static constexpr absl::string_view kServerFeatureIgnoreResourceDeletion =
"ignore_resource_deletion";
std::string server_uri;
std::string channel_creds_type;
Json channel_creds_config;
std::set<std::string> server_features;
static XdsServer Parse(const Json& json, grpc_error_handle* error);
bool operator==(const XdsServer& other) const {
return (server_uri == other.server_uri &&
channel_creds_type == other.channel_creds_type &&
@ -87,8 +70,6 @@ class XdsBootstrap {
return false;
}
Json::Object ToJson() const;
bool ShouldUseV3() const;
bool IgnoreResourceDeletion() const;
};
@ -98,62 +79,26 @@ class XdsBootstrap {
std::vector<XdsServer> xds_servers;
};
// Creates bootstrap object from json_string.
// If *error is not GRPC_ERROR_NONE after returning, then there was an
// error parsing the contents.
static std::unique_ptr<XdsBootstrap> Create(
absl::string_view json_string,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error);
// Do not instantiate directly -- use Create() above instead.
XdsBootstrap(Json json,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error);
virtual ~XdsBootstrap() = default;
std::string ToString() const;
virtual std::string ToString() const = 0;
// TODO(roth): We currently support only one server. Fix this when we
// add support for fallback for the xds channel.
const XdsServer& server() const { return servers_[0]; }
const Node* node() const { return node_.get(); }
const std::string& client_default_listener_resource_name_template() const {
return client_default_listener_resource_name_template_;
}
const std::string& server_listener_resource_name_template() const {
return server_listener_resource_name_template_;
}
const std::map<std::string, Authority>& authorities() const {
return authorities_;
}
virtual const XdsServer& server() const = 0;
virtual const Node* node() const = 0;
virtual const std::string& client_default_listener_resource_name_template()
const = 0;
virtual const std::string& server_listener_resource_name_template() const = 0;
virtual const std::map<std::string, Authority>& authorities() const = 0;
// Returns a pointer to the specified authority, or null if it does
// not exist in this bootstrap config.
const Authority* LookupAuthority(const std::string& name) const;
const XdsCertificateProviderPluginMapInterface*
certificate_provider_plugin_map() const {
return certificate_provider_plugin_map_.get();
}
// A util method to check that an xds server exists in this bootstrap file.
bool XdsServerExists(const XdsServer& server) const;
private:
grpc_error_handle ParseXdsServerList(Json* json,
std::vector<XdsServer>* servers);
grpc_error_handle ParseAuthorities(Json* json);
grpc_error_handle ParseAuthority(Json* json, const std::string& name);
grpc_error_handle ParseNode(Json* json);
grpc_error_handle ParseLocality(Json* json);
grpc_error_handle ParseCertificateProviders(Json* json);
grpc_error_handle ParseCertificateProvider(const std::string& instance_name,
Json* certificate_provider_json);
std::vector<XdsServer> servers_;
std::unique_ptr<Node> node_;
std::string client_default_listener_resource_name_template_;
std::string server_listener_resource_name_template_;
std::map<std::string, Authority> authorities_;
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map_;
// A utility method to check that an xDS server exists in this
// bootstrap config.
bool XdsServerExists(const XdsServer& server) const;
};
} // namespace grpc_core

@ -0,0 +1,521 @@
//
// 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/xds/xds_bootstrap_grpc.h"
#include <stdlib.h>
#include <algorithm>
#include <set>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/json/json_util.h"
#include "src/core/lib/security/credentials/channel_creds_registry.h"
#include "src/core/lib/transport/error_utils.h"
namespace grpc_core {
namespace {
grpc_error_handle ParseChannelCreds(const Json::Object& json, size_t idx,
XdsBootstrap::XdsServer* server) {
std::vector<grpc_error_handle> error_list;
std::string type;
ParseJsonObjectField(json, "type", &type, &error_list);
const Json::Object* config_ptr = nullptr;
ParseJsonObjectField(json, "config", &config_ptr, &error_list,
/*required=*/false);
// Select the first channel creds type that we support.
if (server->channel_creds_type.empty() &&
CoreConfiguration::Get().channel_creds_registry().IsSupported(type)) {
Json config;
if (config_ptr != nullptr) config = *config_ptr;
if (!CoreConfiguration::Get().channel_creds_registry().IsValidConfig(
type, config)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"invalid config for channel creds type \"", type, "\"")));
}
server->channel_creds_type = std::move(type);
server->channel_creds_config = std::move(config);
}
return GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("errors parsing index ", idx), &error_list);
}
grpc_error_handle ParseChannelCredsArray(const Json::Array& json,
XdsBootstrap::XdsServer* server) {
std::vector<grpc_error_handle> error_list;
for (size_t i = 0; i < json.size(); ++i) {
const Json& child = json.at(i);
if (child.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("array element ", i, " is not an object")));
} else {
grpc_error_handle parse_error =
ParseChannelCreds(child.object_value(), i, server);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
if (server->channel_creds_type.empty()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"no known creds type found in \"channel_creds\""));
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"channel_creds\" array",
&error_list);
}
} // namespace
//
// GrpcXdsBootstrap
//
std::unique_ptr<GrpcXdsBootstrap> GrpcXdsBootstrap::Create(
absl::string_view json_string,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error) {
auto json = Json::Parse(json_string);
if (!json.ok()) {
*error = GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"Failed to parse bootstrap JSON string: ", json.status().ToString()));
return nullptr;
}
return absl::make_unique<GrpcXdsBootstrap>(
std::move(*json), std::move(certificate_provider_plugin_map), error);
}
GrpcXdsBootstrap::GrpcXdsBootstrap(
Json json,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error)
: certificate_provider_plugin_map_(
std::move(certificate_provider_plugin_map)) {
if (json.type() != Json::Type::OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"malformed JSON in bootstrap file");
return;
}
std::vector<grpc_error_handle> error_list;
auto it = json.mutable_object()->find("xds_servers");
if (it == json.mutable_object()->end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_servers\" field not present"));
} else if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_servers\" field is not an array"));
} else {
grpc_error_handle parse_error = ParseXdsServerList(&it->second, &servers_);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
it = json.mutable_object()->find("node");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"node\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseNode(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
if (XdsFederationEnabled()) {
it = json.mutable_object()->find("authorities");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"authorities\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseAuthorities(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
it = json.mutable_object()->find(
"client_default_listener_resource_name_template");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"client_default_listener_resource_name_template\" field is not a "
"string"));
} else {
client_default_listener_resource_name_template_ =
std::move(*it->second.mutable_string_value());
}
}
}
it = json.mutable_object()->find("server_listener_resource_name_template");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"server_listener_resource_name_template\" field is not a string"));
} else {
server_listener_resource_name_template_ =
std::move(*it->second.mutable_string_value());
}
}
it = json.mutable_object()->find("certificate_providers");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"certificate_providers\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseCertificateProviders(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing xds bootstrap file",
&error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseXdsServerList(
Json* json, std::vector<XdsServer>* servers) {
std::vector<grpc_error_handle> error_list;
for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
Json& child = json->mutable_array()->at(i);
if (child.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("array element ", i, " is not an object")));
} else {
grpc_error_handle parse_error;
servers->emplace_back(XdsServerParse(child, &parse_error));
if (!GRPC_ERROR_IS_NONE(parse_error)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("errors parsing index ", i)));
error_list.push_back(parse_error);
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"xds_servers\" array",
&error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseAuthorities(Json* json) {
std::vector<grpc_error_handle> error_list;
for (auto& p : *(json->mutable_object())) {
if (p.second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
"field:authorities element error: element is not a object"));
continue;
}
grpc_error_handle parse_error = ParseAuthority(&p.second, p.first);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"authorities\"",
&error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseAuthority(Json* json,
const std::string& name) {
std::vector<grpc_error_handle> error_list;
Authority authority;
auto it =
json->mutable_object()->find("client_listener_resource_name_template");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"client_listener_resource_name_template\" field is not a string"));
} else {
std::string expected_prefix = absl::StrCat("xdstp://", name, "/");
if (!absl::StartsWith(it->second.string_value(), expected_prefix)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrCat("\"client_listener_resource_name_template\" field "
"must begin with \"",
expected_prefix, "\"")));
} else {
authority.client_listener_resource_name_template =
std::move(*it->second.mutable_string_value());
}
}
}
it = json->mutable_object()->find("xds_servers");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"xds_servers\" field is not an array"));
} else {
grpc_error_handle parse_error =
ParseXdsServerList(&it->second, &authority.xds_servers);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
if (error_list.empty()) {
authorities_[name] = std::move(authority);
}
return GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("errors parsing authority ", name), &error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseNode(Json* json) {
std::vector<grpc_error_handle> error_list;
node_ = absl::make_unique<Node>();
auto it = json->mutable_object()->find("id");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("\"id\" field is not a string"));
} else {
node_->id = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("cluster");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"cluster\" field is not a string"));
} else {
node_->cluster = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("locality");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"locality\" field is not an object"));
} else {
grpc_error_handle parse_error = ParseLocality(&it->second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
it = json->mutable_object()->find("metadata");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"metadata\" field is not an object"));
} else {
node_->metadata = std::move(it->second);
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"node\" object",
&error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseLocality(Json* json) {
std::vector<grpc_error_handle> error_list;
auto it = json->mutable_object()->find("region");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"region\" field is not a string"));
} else {
node_->locality_region = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("zone");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"zone\" field is not a string"));
} else {
node_->locality_zone = std::move(*it->second.mutable_string_value());
}
}
it = json->mutable_object()->find("sub_zone");
if (it != json->mutable_object()->end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"sub_zone\" field is not a string"));
} else {
node_->locality_sub_zone = std::move(*it->second.mutable_string_value());
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"locality\" object",
&error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseCertificateProviders(Json* json) {
std::vector<grpc_error_handle> error_list;
for (auto& certificate_provider : *(json->mutable_object())) {
if (certificate_provider.second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"element \"", certificate_provider.first, "\" is not an object")));
} else {
grpc_error_handle parse_error = ParseCertificateProvider(
certificate_provider.first, &certificate_provider.second);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR(
"errors parsing \"certificate_providers\" object", &error_list);
}
grpc_error_handle GrpcXdsBootstrap::ParseCertificateProvider(
const std::string& instance_name, Json* certificate_provider_json) {
std::vector<grpc_error_handle> error_list;
auto it = certificate_provider_json->mutable_object()->find("plugin_name");
if (it == certificate_provider_json->mutable_object()->end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"plugin_name\" field not present"));
} else if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"plugin_name\" field is not a string"));
} else {
std::string plugin_name = std::move(*(it->second.mutable_string_value()));
it = certificate_provider_json->mutable_object()->find("config");
if (it != certificate_provider_json->mutable_object()->end()) {
if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"\"config\" field is not an object"));
} else {
absl::Status status = certificate_provider_plugin_map_->AddPlugin(
instance_name, plugin_name, it->second);
if (!status.ok()) {
error_list.push_back(absl_status_to_grpc_error(status));
}
}
} else {
// "config" is an optional field, so create an empty JSON object.
absl::Status status = certificate_provider_plugin_map_->AddPlugin(
instance_name, plugin_name, Json::Object());
if (!status.ok()) {
error_list.push_back(absl_status_to_grpc_error(status));
}
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
absl::StrCat("errors parsing element \"", instance_name, "\""),
&error_list);
}
std::string GrpcXdsBootstrap::ToString() const {
std::vector<std::string> parts;
if (node_ != nullptr) {
parts.push_back(absl::StrFormat(
"node={\n"
" id=\"%s\",\n"
" cluster=\"%s\",\n"
" locality={\n"
" region=\"%s\",\n"
" zone=\"%s\",\n"
" sub_zone=\"%s\"\n"
" },\n"
" metadata=%s,\n"
"},\n",
node_->id, node_->cluster, node_->locality_region, node_->locality_zone,
node_->locality_sub_zone, node_->metadata.Dump()));
}
parts.push_back(
absl::StrFormat("servers=[\n"
" {\n"
" uri=\"%s\",\n"
" creds_type=%s,\n",
server().server_uri, server().channel_creds_type));
if (server().channel_creds_config.type() != Json::Type::JSON_NULL) {
parts.push_back(absl::StrFormat(" creds_config=%s,",
server().channel_creds_config.Dump()));
}
if (!server().server_features.empty()) {
parts.push_back(absl::StrCat(" server_features=[",
absl::StrJoin(server().server_features, ", "),
"],\n"));
}
parts.push_back(" }\n],\n");
if (!client_default_listener_resource_name_template_.empty()) {
parts.push_back(absl::StrFormat(
"client_default_listener_resource_name_template=\"%s\",\n",
client_default_listener_resource_name_template_));
}
if (!server_listener_resource_name_template_.empty()) {
parts.push_back(
absl::StrFormat("server_listener_resource_name_template=\"%s\",\n",
server_listener_resource_name_template_));
}
parts.push_back("authorities={\n");
for (const auto& entry : authorities_) {
parts.push_back(absl::StrFormat(" %s={\n", entry.first));
parts.push_back(
absl::StrFormat(" client_listener_resource_name_template=\"%s\",\n",
entry.second.client_listener_resource_name_template));
parts.push_back(
absl::StrFormat(" servers=[\n"
" {\n"
" uri=\"%s\",\n"
" creds_type=%s,\n",
entry.second.xds_servers[0].server_uri,
entry.second.xds_servers[0].channel_creds_type));
parts.push_back(" },\n");
}
parts.push_back("}");
parts.push_back("certificate_providers=");
parts.push_back(certificate_provider_plugin_map_->ToString());
return absl::StrJoin(parts, "");
}
XdsBootstrap::XdsServer GrpcXdsBootstrap::XdsServerParse(
const Json& json, grpc_error_handle* error) {
std::vector<grpc_error_handle> error_list;
XdsServer server;
ParseJsonObjectField(json.object_value(), "server_uri", &server.server_uri,
&error_list);
const Json::Array* creds_array = nullptr;
ParseJsonObjectField(json.object_value(), "channel_creds", &creds_array,
&error_list);
if (creds_array != nullptr) {
grpc_error_handle parse_error =
ParseChannelCredsArray(*creds_array, &server);
if (!GRPC_ERROR_IS_NONE(parse_error)) error_list.push_back(parse_error);
}
const Json::Array* server_features_array = nullptr;
ParseJsonObjectField(json.object_value(), "server_features",
&server_features_array, &error_list, /*required=*/false);
if (server_features_array != nullptr) {
for (const Json& feature_json : *server_features_array) {
if (feature_json.type() == Json::Type::STRING &&
(feature_json.string_value() ==
XdsBootstrap::XdsServer::kServerFeatureXdsV3 ||
feature_json.string_value() ==
XdsBootstrap::XdsServer::kServerFeatureIgnoreResourceDeletion)) {
server.server_features.insert(feature_json.string_value());
}
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR_AND_CPP_STRING(
"errors parsing xds server", &error_list);
return server;
}
Json::Object GrpcXdsBootstrap::XdsServerToJson(const XdsServer& server) {
Json::Object channel_creds_json{{"type", server.channel_creds_type}};
if (server.channel_creds_config.type() != Json::Type::JSON_NULL) {
channel_creds_json["config"] = server.channel_creds_config;
}
Json::Object json{
{"server_uri", server.server_uri},
{"channel_creds", Json::Array{std::move(channel_creds_json)}},
};
if (!server.server_features.empty()) {
Json::Array server_features_json;
for (auto& feature : server.server_features) {
server_features_json.emplace_back(feature);
}
json["server_features"] = std::move(server_features_json);
}
return json;
}
} // namespace grpc_core

@ -0,0 +1,111 @@
//
// 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_CORE_EXT_XDS_XDS_BOOTSTRAP_GRPC_H
#define GRPC_CORE_EXT_XDS_XDS_BOOTSTRAP_GRPC_H
#include <grpc/support/port_platform.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h"
namespace grpc_core {
class XdsCertificateProviderPluginMapInterface {
public:
virtual ~XdsCertificateProviderPluginMapInterface() = default;
virtual absl::Status AddPlugin(const std::string& instance_name,
const std::string& plugin_name,
const Json& config) = 0;
virtual bool HasPlugin(const std::string& instance_name) const = 0;
virtual std::string ToString() const = 0;
};
class GrpcXdsBootstrap : public XdsBootstrap {
public:
// Creates bootstrap object from json_string.
// If *error is not GRPC_ERROR_NONE after returning, then there was an
// error parsing the contents.
static std::unique_ptr<GrpcXdsBootstrap> Create(
absl::string_view json_string,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error);
// Do not instantiate directly -- use Create() above instead.
GrpcXdsBootstrap(Json json,
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map,
grpc_error_handle* error);
std::string ToString() const override;
const XdsServer& server() const override { return servers_[0]; }
const Node* node() const override { return node_.get(); }
const std::string& client_default_listener_resource_name_template()
const override {
return client_default_listener_resource_name_template_;
}
const std::string& server_listener_resource_name_template() const override {
return server_listener_resource_name_template_;
}
const std::map<std::string, Authority>& authorities() const override {
return authorities_;
}
const XdsCertificateProviderPluginMapInterface*
certificate_provider_plugin_map() const {
return certificate_provider_plugin_map_.get();
}
static XdsServer XdsServerParse(const Json& json, grpc_error_handle* error);
static Json::Object XdsServerToJson(const XdsServer& server);
private:
grpc_error_handle ParseXdsServerList(Json* json,
std::vector<XdsServer>* servers);
grpc_error_handle ParseAuthorities(Json* json);
grpc_error_handle ParseAuthority(Json* json, const std::string& name);
grpc_error_handle ParseNode(Json* json);
grpc_error_handle ParseLocality(Json* json);
grpc_error_handle ParseCertificateProviders(Json* json);
grpc_error_handle ParseCertificateProvider(const std::string& instance_name,
Json* certificate_provider_json);
std::vector<XdsServer> servers_;
std::unique_ptr<Node> node_;
std::string client_default_listener_resource_name_template_;
std::string server_listener_resource_name_template_;
std::map<std::string, Authority> authorities_;
std::unique_ptr<XdsCertificateProviderPluginMapInterface>
certificate_provider_plugin_map_;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_XDS_XDS_BOOTSTRAP_GRPC_H

@ -153,7 +153,7 @@ absl::StatusOr<RefCountedPtr<GrpcXdsClient>> GrpcXdsClient::GetOrCreate(
GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG);
if (bootstrap_config.has_value()) {
grpc_error_handle error = GRPC_ERROR_NONE;
std::unique_ptr<XdsBootstrap> bootstrap = XdsBootstrap::Create(
std::unique_ptr<GrpcXdsBootstrap> bootstrap = GrpcXdsBootstrap::Create(
*bootstrap_config, std::move(certificate_provider_plugin_map), &error);
if (!GRPC_ERROR_IS_NONE(error)) return grpc_error_to_absl_status(error);
grpc_channel_args* xds_channel_args = args.GetPointer<grpc_channel_args>(
@ -176,7 +176,7 @@ absl::StatusOr<RefCountedPtr<GrpcXdsClient>> GrpcXdsClient::GetOrCreate(
}
// Parse bootstrap.
grpc_error_handle error = GRPC_ERROR_NONE;
std::unique_ptr<XdsBootstrap> bootstrap = XdsBootstrap::Create(
std::unique_ptr<GrpcXdsBootstrap> bootstrap = GrpcXdsBootstrap::Create(
*bootstrap_contents, std::move(certificate_provider_plugin_map), &error);
if (!GRPC_ERROR_IS_NONE(error)) return grpc_error_to_absl_status(error);
// Instantiate XdsClient.
@ -196,7 +196,8 @@ GrpcXdsClient::GrpcXdsClient(std::unique_ptr<XdsBootstrap> bootstrap,
.value_or(Duration::Seconds(15)))),
certificate_provider_store_(MakeOrphanable<CertificateProviderStore>(
static_cast<const GrpcXdsCertificateProviderPluginMap*>(
this->bootstrap().certificate_provider_plugin_map())
static_cast<const GrpcXdsBootstrap&>(this->bootstrap())
.certificate_provider_plugin_map())
->plugin_map())) {}
GrpcXdsClient::~GrpcXdsClient() {

@ -30,6 +30,7 @@
#include "src/core/ext/xds/certificate_provider_store.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/lib/channel/channel_args.h"
#include "src/core/lib/gpr/useful.h"

@ -38,7 +38,7 @@
#include "xds/type/v3/typed_struct.upb.h"
#include "src/core/ext/xds/upb_utils.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"
namespace grpc_core {
@ -125,7 +125,9 @@ CertificateProviderInstanceParse(
UpbStringToStdString(
envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance_certificate_name(
certificate_provider_instance_proto))};
if (!context.client->bootstrap().certificate_provider_plugin_map()->HasPlugin(
const auto& bootstrap =
static_cast<const GrpcXdsBootstrap&>(context.client->bootstrap());
if (!bootstrap.certificate_provider_plugin_map()->HasPlugin(
certificate_provider_plugin_instance.instance_name)) {
return absl::InvalidArgumentError(
absl::StrCat("Unrecognized certificate provider instance name: ",
@ -147,7 +149,9 @@ CertificateProviderPluginInstanceParse(
UpbStringToStdString(
envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance_certificate_name(
certificate_provider_plugin_instance_proto))};
if (!context.client->bootstrap().certificate_provider_plugin_map()->HasPlugin(
const auto& bootstrap =
static_cast<const GrpcXdsBootstrap&>(context.client->bootstrap());
if (!bootstrap.certificate_provider_plugin_map()->HasPlugin(
certificate_provider_plugin_instance.instance_name)) {
return absl::InvalidArgumentError(
absl::StrCat("Unrecognized certificate provider instance name: ",

@ -31,6 +31,8 @@
namespace grpc_core {
class XdsClient;
// Interface for an xDS resource type.
// Used to inject type-specific logic into XdsClient.
class XdsResourceType {

@ -403,6 +403,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/xds/file_watcher_certificate_provider_factory.cc',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_bootstrap_grpc.cc',
'src/core/ext/xds/xds_certificate_provider.cc',
'src/core/ext/xds/xds_channel_stack_modifier.cc',
'src/core/ext/xds/xds_client.cc',

@ -27,7 +27,7 @@ grpc_cc_test(
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc_xds_client",
"//test/core/util:grpc_test_util",
],
)

@ -14,20 +14,14 @@
// limitations under the License.
//
#include "src/core/ext/xds/xds_bootstrap.h"
#include <regex>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/strings/numbers.h"
#include "absl/strings/str_format.h"
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include "src/core/ext/xds/certificate_provider_registry.h"
#include "src/core/ext/xds/xds_bootstrap_grpc.h"
#include "src/core/ext/xds/xds_client_grpc.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/tmpfile.h"
@ -121,7 +115,7 @@ TEST(XdsBootstrapTest, Basic) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
@ -189,7 +183,7 @@ TEST(XdsBootstrapTest, ValidWithoutNode) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
@ -211,7 +205,7 @@ TEST(XdsBootstrapTest, InsecureCreds) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
@ -249,7 +243,7 @@ TEST(XdsBootstrapTest, GoogleDefaultCreds) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
@ -270,7 +264,7 @@ TEST(XdsBootstrapTest, MissingChannelCreds) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(
@ -292,7 +286,7 @@ TEST(XdsBootstrapTest, NoKnownChannelCreds) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -305,7 +299,7 @@ TEST(XdsBootstrapTest, MissingXdsServers) {
auto json = Json::Parse("{}");
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -324,7 +318,7 @@ TEST(XdsBootstrapTest, TopFieldsWrongTypes) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -346,7 +340,7 @@ TEST(XdsBootstrapTest, XdsServerMissingServerUri) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(
@ -371,7 +365,7 @@ TEST(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -402,7 +396,7 @@ TEST(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(
@ -430,7 +424,7 @@ TEST(XdsBootstrapTest, NodeFieldsWrongTypes) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -456,7 +450,7 @@ TEST(XdsBootstrapTest, LocalityFieldsWrongType) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -484,7 +478,7 @@ TEST(XdsBootstrapTest, CertificateProvidersElementWrongType) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -512,7 +506,7 @@ TEST(XdsBootstrapTest, CertificateProvidersPluginNameWrongType) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -541,7 +535,7 @@ TEST(XdsBootstrapTest, CertificateProvidersUnrecognizedPluginName) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -584,7 +578,7 @@ TEST(XdsBootstrapTest, AuthorityXdsServerInvalidResourceTemplate) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -618,7 +612,7 @@ TEST(XdsBootstrapTest, AuthorityXdsServerMissingServerUri) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(
@ -703,7 +697,7 @@ TEST(XdsBootstrapTest, CertificateProvidersFakePluginParsingError) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
EXPECT_THAT(grpc_error_std_string(error),
@ -735,7 +729,7 @@ TEST(XdsBootstrapTest, CertificateProvidersFakePluginParsingSuccess) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
ASSERT_TRUE(GRPC_ERROR_IS_NONE(error)) << grpc_error_std_string(error);
@ -770,7 +764,7 @@ TEST(XdsBootstrapTest, CertificateProvidersFakePluginEmptyConfig) {
auto json = Json::Parse(json_str);
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap bootstrap(
GrpcXdsBootstrap bootstrap(
std::move(*json),
absl::make_unique<GrpcXdsCertificateProviderPluginMap>(), &error);
ASSERT_TRUE(GRPC_ERROR_IS_NONE(error)) << grpc_error_std_string(error);
@ -804,11 +798,11 @@ TEST(XdsBootstrapTest, XdsServerToJsonAndParse) {
ASSERT_TRUE(json.ok()) << json.status();
grpc_error_handle error = GRPC_ERROR_NONE;
XdsBootstrap::XdsServer xds_server =
XdsBootstrap::XdsServer::Parse(*json, &error);
GrpcXdsBootstrap::XdsServerParse(*json, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
Json::Object output = xds_server.ToJson();
Json::Object output = GrpcXdsBootstrap::XdsServerToJson(xds_server);
XdsBootstrap::XdsServer output_xds_server =
XdsBootstrap::XdsServer::Parse(output, &error);
GrpcXdsBootstrap::XdsServerParse(output, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
}

@ -1855,6 +1855,8 @@ src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_bootstrap.h \
src/core/ext/xds/xds_bootstrap_grpc.cc \
src/core/ext/xds/xds_bootstrap_grpc.h \
src/core/ext/xds/xds_certificate_provider.cc \
src/core/ext/xds/xds_certificate_provider.h \
src/core/ext/xds/xds_channel_args.h \

@ -1643,6 +1643,8 @@ src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_bootstrap.h \
src/core/ext/xds/xds_bootstrap_grpc.cc \
src/core/ext/xds/xds_bootstrap_grpc.h \
src/core/ext/xds/xds_certificate_provider.cc \
src/core/ext/xds/xds_certificate_provider.h \
src/core/ext/xds/xds_channel_args.h \

Loading…
Cancel
Save