diff --git a/src/core/ext/xds/xds_bootstrap.cc b/src/core/ext/xds/xds_bootstrap.cc index e48d9827dec..95f4c3de1e3 100644 --- a/src/core/ext/xds/xds_bootstrap.cc +++ b/src/core/ext/xds/xds_bootstrap.cc @@ -132,13 +132,40 @@ std::string BootstrapString(const XdsBootstrap& bootstrap) { return absl::StrJoin(parts, ""); } +std::unique_ptr ParseJsonAndCreate( + XdsClient* client, TraceFlag* tracer, absl::string_view json_string, + absl::string_view bootstrap_source, grpc_error** error) { + Json json = Json::Parse(json_string, error); + if (*error != GRPC_ERROR_NONE) { + grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING( + absl::StrCat("Failed to parse bootstrap from ", bootstrap_source) + .c_str(), + error, 1); + GRPC_ERROR_UNREF(*error); + *error = error_out; + return nullptr; + } + std::unique_ptr result = + absl::make_unique(std::move(json), error); + if (*error == GRPC_ERROR_NONE && GRPC_TRACE_FLAG_ENABLED(*tracer)) { + gpr_log(GPR_INFO, + "[xds_client %p] Bootstrap config for creating xds client:\n%s", + client, BootstrapString(*result).c_str()); + } + return result; +} + } // namespace -std::unique_ptr XdsBootstrap::ReadFromFile(XdsClient* client, - TraceFlag* tracer, - grpc_error** error) { +std::unique_ptr XdsBootstrap::ReadFromFile( + XdsClient* client, TraceFlag* tracer, const char* fallback_config, + grpc_error** error) { grpc_core::UniquePtr path(gpr_getenv("GRPC_XDS_BOOTSTRAP")); if (path == nullptr) { + if (fallback_config != nullptr) { + return ParseJsonAndCreate(client, tracer, fallback_config, + "fallback config", error); + } *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Environment variable GRPC_XDS_BOOTSTRAP not defined"); return nullptr; @@ -157,23 +184,10 @@ std::unique_ptr XdsBootstrap::ReadFromFile(XdsClient* client, gpr_log(GPR_DEBUG, "[xds_client %p] Bootstrap file contents: %s", client, std::string(contents_str_view).c_str()); } - Json json = Json::Parse(contents_str_view, error); + std::string bootstrap_source = absl::StrCat("file ", path.get()); + auto result = ParseJsonAndCreate(client, tracer, contents_str_view, + bootstrap_source, error); grpc_slice_unref_internal(contents); - if (*error != GRPC_ERROR_NONE) { - grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING( - absl::StrCat("Failed to parse bootstrap file ", path.get()).c_str(), - error, 1); - GRPC_ERROR_UNREF(*error); - *error = error_out; - return nullptr; - } - std::unique_ptr result = - absl::make_unique(std::move(json), error); - if (*error == GRPC_ERROR_NONE && GRPC_TRACE_FLAG_ENABLED(*tracer)) { - gpr_log(GPR_INFO, - "[xds_client %p] Bootstrap config for creating xds client:\n%s", - client, BootstrapString(*result).c_str()); - } return result; } diff --git a/src/core/ext/xds/xds_bootstrap.h b/src/core/ext/xds/xds_bootstrap.h index 969d5d54992..5d1f9095858 100644 --- a/src/core/ext/xds/xds_bootstrap.h +++ b/src/core/ext/xds/xds_bootstrap.h @@ -67,10 +67,13 @@ class XdsBootstrap { bool ShouldUseV3() const; }; + // Normally locates the bootstrap file via an env var. If no env var + // is set, fallback_config will be used instead (if non-null). // If *error is not GRPC_ERROR_NONE after returning, then there was an // error reading the file. static std::unique_ptr ReadFromFile(XdsClient* client, TraceFlag* tracer, + const char* fallback_config, grpc_error** error); // Do not instantiate directly -- use ReadFromFile() above instead. diff --git a/src/core/ext/xds/xds_client.cc b/src/core/ext/xds/xds_client.cc index b31bbbdc1f1..e95cf7aa663 100644 --- a/src/core/ext/xds/xds_client.cc +++ b/src/core/ext/xds/xds_client.cc @@ -72,6 +72,7 @@ namespace { Mutex* g_mu = nullptr; const grpc_channel_args* g_channel_args = nullptr; XdsClient* g_xds_client = nullptr; +char* g_fallback_bootstrap_config = nullptr; } // namespace @@ -1740,8 +1741,8 @@ XdsClient::XdsClient(grpc_error** error) : nullptr), request_timeout_(GetRequestTimeout()), interested_parties_(grpc_pollset_set_create()), - bootstrap_( - XdsBootstrap::ReadFromFile(this, &grpc_xds_client_trace, error)), + bootstrap_(XdsBootstrap::ReadFromFile( + this, &grpc_xds_client_trace, g_fallback_bootstrap_config, error)), certificate_provider_store_(MakeOrphanable( bootstrap_ == nullptr ? CertificateProviderStore::PluginDefinitionMap() @@ -2207,6 +2208,8 @@ void XdsClientGlobalInit() { g_mu = new Mutex; } void XdsClientGlobalShutdown() { delete g_mu; g_mu = nullptr; + gpr_free(g_fallback_bootstrap_config); + g_fallback_bootstrap_config = nullptr; } RefCountedPtr XdsClient::GetOrCreate(grpc_error** error) { @@ -2232,6 +2235,12 @@ void UnsetGlobalXdsClientForTest() { g_xds_client = nullptr; } +void SetXdsFallbackBootstrapConfig(char* config) { + MutexLock lock(g_mu); + gpr_free(g_fallback_bootstrap_config); + g_fallback_bootstrap_config = config; +} + } // namespace internal } // namespace grpc_core diff --git a/src/core/ext/xds/xds_client.h b/src/core/ext/xds/xds_client.h index f1c6467556c..791b3990376 100644 --- a/src/core/ext/xds/xds_client.h +++ b/src/core/ext/xds/xds_client.h @@ -329,6 +329,9 @@ class XdsClient : public DualRefCounted { namespace internal { void SetXdsChannelArgsForTest(grpc_channel_args* args); void UnsetGlobalXdsClientForTest(); +// Sets bootstrap config to be used when no env var is set. +// Takes ownership of config. +void SetXdsFallbackBootstrapConfig(char* config); } // namespace internal } // namespace grpc_core