Merge pull request #25214 from markdroth/xds_bootstrap_env_var

Add ability to read xDS bootstrap config from an env var.
pull/25224/head
Mark D. Roth 4 years ago committed by GitHub
commit 5b5e3f84a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 73
      src/core/ext/xds/xds_bootstrap.cc
  2. 19
      src/core/ext/xds/xds_bootstrap.h
  3. 4
      src/core/ext/xds/xds_client.cc
  4. 39
      test/cpp/end2end/xds_end2end_test.cc

@ -157,38 +157,51 @@ std::unique_ptr<XdsBootstrap> ParseJsonAndCreate(
} // namespace
std::unique_ptr<XdsBootstrap> XdsBootstrap::ReadFromFile(
XdsClient* client, TraceFlag* tracer, const char* fallback_config,
grpc_error** error) {
std::unique_ptr<XdsBootstrap> XdsBootstrap::Create(XdsClient* client,
TraceFlag* tracer,
const char* fallback_config,
grpc_error** error) {
// First, try GRPC_XDS_BOOTSTRAP env var.
grpc_core::UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
if (path == nullptr) {
if (fallback_config != nullptr) {
return ParseJsonAndCreate(client, tracer, fallback_config,
"fallback config", error);
if (path != nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
gpr_log(GPR_INFO,
"[xds_client %p] Got bootstrap file location from "
"GRPC_XDS_BOOTSTRAP environment variable: %s",
client, path.get());
}
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Environment variable GRPC_XDS_BOOTSTRAP not defined");
return nullptr;
}
if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
gpr_log(GPR_INFO,
"[xds_client %p] Got bootstrap file location from "
"GRPC_XDS_BOOTSTRAP environment variable: %s",
client, path.get());
}
grpc_slice contents;
*error = grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
if (*error != GRPC_ERROR_NONE) return nullptr;
absl::string_view contents_str_view = StringViewFromSlice(contents);
if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
gpr_log(GPR_DEBUG, "[xds_client %p] Bootstrap file contents: %s", client,
std::string(contents_str_view).c_str());
}
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);
return result;
grpc_slice contents;
*error =
grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
if (*error != GRPC_ERROR_NONE) return nullptr;
absl::string_view contents_str_view = StringViewFromSlice(contents);
if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
gpr_log(GPR_DEBUG, "[xds_client %p] Bootstrap file contents: %s", client,
std::string(contents_str_view).c_str());
}
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);
return result;
}
// Next, try GRPC_XDS_BOOTSTRAP_CONFIG env var.
grpc_core::UniquePtr<char> env_config(
gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG"));
if (env_config != nullptr) {
return ParseJsonAndCreate(client, tracer, env_config.get(),
"GRPC_XDS_BOOTSTRAP_CONFIG env var", error);
}
// Finally, try fallback config.
if (fallback_config != nullptr) {
return ParseJsonAndCreate(client, tracer, fallback_config,
"fallback config", error);
}
// No bootstrap config found.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Environment variables GRPC_XDS_BOOTSTRAP or GRPC_XDS_BOOTSTRAP_CONFIG "
"not defined");
return nullptr;
}
XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {

@ -67,14 +67,19 @@ 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).
// Creates bootstrap object, obtaining the bootstrap JSON as appropriate
// for the environment:
// - If the GRPC_XDS_BOOTSTRAP env var is set, reads the file it specifies
// to obtain the bootstrap JSON.
// - Otherwise, if the GRPC_XDS_BOOTSTRAP_CONFIG env var is set, reads the
// content of that env var to obtain the bootstrap JSON.
// - Otherwise, the JSON will be read from fallback_config (if non-null).
// If *error is not GRPC_ERROR_NONE after returning, then there was an
// error reading the file.
static std::unique_ptr<XdsBootstrap> ReadFromFile(XdsClient* client,
TraceFlag* tracer,
const char* fallback_config,
grpc_error** error);
// error (e.g., no config found or error reading the file).
static std::unique_ptr<XdsBootstrap> Create(XdsClient* client,
TraceFlag* tracer,
const char* fallback_config,
grpc_error** error);
// Do not instantiate directly -- use ReadFromFile() above instead.
XdsBootstrap(Json json, grpc_error** error);

@ -1734,8 +1734,8 @@ XdsClient::XdsClient(grpc_error** error)
: nullptr),
request_timeout_(GetRequestTimeout()),
interested_parties_(grpc_pollset_set_create()),
bootstrap_(XdsBootstrap::ReadFromFile(
this, &grpc_xds_client_trace, g_fallback_bootstrap_config, error)),
bootstrap_(XdsBootstrap::Create(this, &grpc_xds_client_trace,
g_fallback_bootstrap_config, error)),
certificate_provider_store_(MakeOrphanable<CertificateProviderStore>(
bootstrap_ == nullptr
? CertificateProviderStore::PluginDefinitionMap()

@ -1506,17 +1506,25 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
protected:
XdsEnd2endTest(size_t num_backends, size_t num_balancers,
int client_load_reporting_interval_seconds = 100,
bool use_xds_enabled_server = false)
bool use_xds_enabled_server = false,
bool bootstrap_contents_from_env_var = false)
: num_backends_(num_backends),
num_balancers_(num_balancers),
client_load_reporting_interval_seconds_(
client_load_reporting_interval_seconds),
use_xds_enabled_server_(use_xds_enabled_server) {}
use_xds_enabled_server_(use_xds_enabled_server),
bootstrap_contents_from_env_var_(bootstrap_contents_from_env_var) {}
void SetUp() override {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_V3_SUPPORT", "true");
gpr_setenv("GRPC_XDS_BOOTSTRAP",
GetParam().use_v2() ? g_bootstrap_file_v2 : g_bootstrap_file_v3);
if (bootstrap_contents_from_env_var_) {
gpr_setenv("GRPC_XDS_BOOTSTRAP_CONFIG",
GetParam().use_v2() ? kBootstrapFileV2 : kBootstrapFileV3);
} else {
gpr_setenv("GRPC_XDS_BOOTSTRAP", GetParam().use_v2()
? g_bootstrap_file_v2
: g_bootstrap_file_v3);
}
g_port_saver->Reset();
bool localhost_resolves_to_ipv4 = false;
bool localhost_resolves_to_ipv6 = false;
@ -1597,6 +1605,8 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
// Clear global xDS channel args, since they will go out of scope
// when this test object is destroyed.
grpc_core::internal::SetXdsChannelArgsForTest(nullptr);
gpr_unsetenv("GRPC_XDS_BOOTSTRAP");
gpr_unsetenv("GRPC_XDS_BOOTSTRAP_CONFIG");
}
void StartAllBackends() {
@ -2272,6 +2282,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
RouteConfiguration default_route_config_;
Cluster default_cluster_;
bool use_xds_enabled_server_;
bool bootstrap_contents_from_env_var_;
};
class BasicTest : public XdsEnd2endTest {
@ -7833,6 +7844,22 @@ TEST_P(ClientLoadReportingWithDropTest, Vanilla) {
kDropRateForThrottle * (1 + kErrorTolerance))));
}
class BootstrapContentsFromEnvVarTest : public XdsEnd2endTest {
public:
BootstrapContentsFromEnvVarTest() : XdsEnd2endTest(4, 1, 100, false, true) {}
};
TEST_P(BootstrapContentsFromEnvVarTest, Vanilla) {
SetNextResolution({});
SetNextResolutionForLbChannelAllBalancers();
AdsServiceImpl::EdsResourceArgs args({
{"locality0", GetBackendPorts()},
});
balancers_[0]->ads_service()->SetEdsResource(
BuildEdsResource(args, DefaultEdsServiceName()));
WaitForAllBackends();
}
std::string TestTypeName(const ::testing::TestParamInfo<TestType>& info) {
return info.param.AsString();
}
@ -7967,6 +7994,10 @@ INSTANTIATE_TEST_SUITE_P(XdsTest, ClientLoadReportingWithDropTest,
TestType(true, true)),
&TestTypeName);
INSTANTIATE_TEST_SUITE_P(XdsTest, BootstrapContentsFromEnvVarTest,
::testing::Values(TestType(true, false)),
&TestTypeName);
} // namespace
} // namespace testing
} // namespace grpc

Loading…
Cancel
Save