Merge pull request #24409 from yashykt/xdsbootstrapcertproviders

xDS Bootstrap changes for certificate providers
reviewable/pr24408/r3^2
Yash Tibrewal 4 years ago committed by GitHub
commit 83e42769b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      BUILD
  2. 6
      src/core/ext/xds/certificate_provider_factory.h
  3. 16
      src/core/ext/xds/certificate_provider_store.h
  4. 6
      src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
  5. 8
      src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
  6. 79
      src/core/ext/xds/xds_bootstrap.cc
  7. 10
      src/core/ext/xds/xds_bootstrap.h
  8. 8
      test/core/client_channel/certificate_provider_registry_test.cc
  9. 329
      test/core/client_channel/xds_bootstrap_test.cc

38
BUILD

@ -1305,6 +1305,23 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc_xds_credentials",
srcs = [
"src/core/ext/xds/certificate_provider_registry.cc",
"src/core/lib/security/credentials/xds/xds_credentials.cc",
],
hdrs = [
"src/core/ext/xds/certificate_provider_factory.h",
"src/core/ext/xds/certificate_provider_registry.h",
"src/core/ext/xds/certificate_provider_store.h",
"src/core/lib/security/credentials/xds/xds_credentials.h",
],
deps = [
"grpc_secure",
],
)
grpc_cc_library(
name = "grpc_xds_client",
srcs = [
@ -1332,7 +1349,7 @@ grpc_cc_library(
"grpc_base",
"grpc_client_channel",
"grpc_google_mesh_ca_certificate_provider_factory",
"grpc_secure",
"grpc_xds_credentials",
],
)
@ -1347,7 +1364,7 @@ grpc_cc_library(
language = "c++",
deps = [
"grpc_base",
"grpc_secure",
"grpc_xds_credentials",
],
)
@ -1736,7 +1753,6 @@ grpc_cc_library(
grpc_cc_library(
name = "grpc_secure",
srcs = [
"src/core/ext/xds/certificate_provider_registry.cc",
"src/core/lib/http/httpcli_security_connector.cc",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/credentials/alts/alts_credentials.cc",
@ -1780,9 +1796,6 @@ grpc_cc_library(
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
"src/core/ext/xds/certificate_provider_factory.h",
"src/core/ext/xds/certificate_provider_registry.h",
"src/core/ext/xds/certificate_provider_store.h",
"src/core/ext/xds/xds_channel_args.h",
"src/core/lib/security/certificate_provider.h",
"src/core/lib/security/context/security_context.h",
@ -1830,19 +1843,6 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc_xds_credentials",
srcs = [
"src/core/lib/security/credentials/xds/xds_credentials.cc",
],
hdrs = [
"src/core/lib/security/credentials/xds/xds_credentials.h",
],
deps = [
"grpc_secure",
],
)
grpc_cc_library(
name = "grpc_mock_cel",
hdrs = [

@ -32,7 +32,7 @@ namespace grpc_core {
class CertificateProviderFactory {
public:
// Interface for configs for CertificateProviders.
class Config {
class Config : public RefCounted<Config> {
public:
virtual ~Config() = default;
@ -46,12 +46,12 @@ class CertificateProviderFactory {
// Name of the plugin.
virtual const char* name() const = 0;
virtual std::unique_ptr<Config> CreateCertificateProviderConfig(
virtual RefCountedPtr<Config> CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) = 0;
// Create a CertificateProvider instance from config.
virtual RefCountedPtr<grpc_tls_certificate_provider>
CreateCertificateProvider(std::unique_ptr<Config> config) = 0;
CreateCertificateProvider(RefCountedPtr<Config> config) = 0;
};
} // namespace grpc_core

@ -25,6 +25,7 @@
#include "absl/strings/string_view.h"
#include "src/core/ext/xds/certificate_provider_factory.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/security/certificate_provider.h"
@ -34,6 +35,16 @@ namespace grpc_core {
// Map for xDS based grpc_tls_certificate_provider instances.
class CertificateProviderStore {
public:
struct PluginDefinition {
std::string plugin_name;
RefCountedPtr<CertificateProviderFactory::Config> config;
};
typedef std::map<std::string, PluginDefinition> PluginDefinitionMap;
CertificateProviderStore(PluginDefinitionMap plugin_config_map)
: plugin_config_map_(std::move(plugin_config_map)) {}
// If a provider corresponding to the config is found, a raw pointer to the
// grpc_tls_certificate_provider in the map is returned. If no provider is
// found for a key, a new provider is created. The CertificateProviderStore
@ -43,8 +54,11 @@ class CertificateProviderStore {
absl::string_view key);
private:
// Map of plugin configurations
PluginDefinitionMap plugin_config_map_;
// Underlying map for the providers.
std::map<std::string, RefCountedPtr<grpc_tls_certificate_provider>> map_;
std::map<absl::string_view, RefCountedPtr<grpc_tls_certificate_provider>>
certificate_providers_map_;
};
} // namespace grpc_core

@ -304,11 +304,11 @@ GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer(
return error_list_server;
}
std::unique_ptr<GoogleMeshCaCertificateProviderFactory::Config>
RefCountedPtr<GoogleMeshCaCertificateProviderFactory::Config>
GoogleMeshCaCertificateProviderFactory::Config::Parse(const Json& config_json,
grpc_error** error) {
auto config =
absl::make_unique<GoogleMeshCaCertificateProviderFactory::Config>();
MakeRefCounted<GoogleMeshCaCertificateProviderFactory::Config>();
if (config_json.type() != Json::Type::OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"error:config type should be OBJECT.");
@ -367,7 +367,7 @@ const char* GoogleMeshCaCertificateProviderFactory::name() const {
return kMeshCaPlugin;
}
std::unique_ptr<CertificateProviderFactory::Config>
RefCountedPtr<CertificateProviderFactory::Config>
GoogleMeshCaCertificateProviderFactory::CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) {
return GoogleMeshCaCertificateProviderFactory::Config::Parse(config_json,

@ -60,8 +60,8 @@ class GoogleMeshCaCertificateProviderFactory
const std::string& location() const { return location_; }
static std::unique_ptr<Config> Parse(const Json& config_json,
grpc_error** error);
static RefCountedPtr<Config> Parse(const Json& config_json,
grpc_error** error);
private:
// Helpers for parsing the config
@ -86,12 +86,12 @@ class GoogleMeshCaCertificateProviderFactory
const char* name() const override;
std::unique_ptr<CertificateProviderFactory::Config>
RefCountedPtr<CertificateProviderFactory::Config>
CreateCertificateProviderConfig(const Json& config_json,
grpc_error** error) override;
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
std::unique_ptr<CertificateProviderFactory::Config> config) override {
RefCountedPtr<CertificateProviderFactory::Config> config) override {
// TODO(yashykt) : To be implemented
return nullptr;
}

@ -28,6 +28,7 @@
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/xds/certificate_provider_registry.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/load_file.h"
@ -152,6 +153,16 @@ XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
}
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* parse_error = ParseCertificateProviders(&it->second);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing xds bootstrap file",
&error_list);
}
@ -370,4 +381,72 @@ grpc_error* XdsBootstrap::ParseLocality(Json* json) {
&error_list);
}
grpc_error* XdsBootstrap::ParseCertificateProviders(Json* json) {
std::vector<grpc_error*> 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_COPIED_STRING(
absl::StrCat("element \"", certificate_provider.first,
"\" is not an object")
.c_str()));
} else {
grpc_error* parse_error = ParseCertificateProvider(
certificate_provider.first, &certificate_provider.second);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR(
"errors parsing \"certificate_providers\" object", &error_list);
}
grpc_error* XdsBootstrap::ParseCertificateProvider(
const std::string& instance_name, Json* certificate_provider_json) {
std::vector<grpc_error*> 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()));
CertificateProviderFactory* factory =
CertificateProviderRegistry::LookupCertificateProviderFactory(
plugin_name);
if (factory != nullptr) {
RefCountedPtr<CertificateProviderFactory::Config> config;
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 {
grpc_error* parse_error = GRPC_ERROR_NONE;
config = factory->CreateCertificateProviderConfig(it->second,
&parse_error);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
} else {
// "config" is an optional field, so create an empty JSON object.
grpc_error* parse_error = GRPC_ERROR_NONE;
config = factory->CreateCertificateProviderConfig(Json::Object(),
&parse_error);
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
}
certificate_providers_.insert(
{instance_name, {std::move(plugin_name), std::move(config)}});
}
}
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
// string is not static in this case.
if (error_list.empty()) return GRPC_ERROR_NONE;
grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("errors parsing element \"", instance_name, "\"").c_str());
for (size_t i = 0; i < error_list.size(); ++i) {
error = grpc_error_add_child(error, error_list[i]);
}
return error;
}
} // namespace grpc_core

@ -28,6 +28,7 @@
#include <grpc/slice.h>
#include "src/core/ext/xds/certificate_provider_store.h"
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/error.h"
@ -75,6 +76,11 @@ class XdsBootstrap {
const XdsServer& server() const { return servers_[0]; }
const Node* node() const { return node_.get(); }
const CertificateProviderStore::PluginDefinitionMap& certificate_providers()
const {
return certificate_providers_;
}
private:
grpc_error* ParseXdsServerList(Json* json);
grpc_error* ParseXdsServer(Json* json, size_t idx);
@ -83,9 +89,13 @@ class XdsBootstrap {
grpc_error* ParseServerFeaturesArray(Json* json, XdsServer* server);
grpc_error* ParseNode(Json* json);
grpc_error* ParseLocality(Json* json);
grpc_error* ParseCertificateProviders(Json* json);
grpc_error* ParseCertificateProvider(const std::string& instance_name,
Json* certificate_provider_json);
absl::InlinedVector<XdsServer, 1> servers_;
std::unique_ptr<Node> node_;
CertificateProviderStore::PluginDefinitionMap certificate_providers_;
};
} // namespace grpc_core

@ -32,13 +32,13 @@ class FakeCertificateProviderFactory1 : public CertificateProviderFactory {
public:
const char* name() const override { return "fake1"; }
std::unique_ptr<Config> CreateCertificateProviderConfig(
RefCountedPtr<Config> CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) override {
return nullptr;
}
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
std::unique_ptr<Config> config) override {
RefCountedPtr<Config> config) override {
return nullptr;
}
};
@ -47,13 +47,13 @@ class FakeCertificateProviderFactory2 : public CertificateProviderFactory {
public:
const char* name() const override { return "fake2"; }
std::unique_ptr<Config> CreateCertificateProviderConfig(
RefCountedPtr<Config> CreateCertificateProviderConfig(
const Json& config_json, grpc_error** error) override {
return nullptr;
}
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
std::unique_ptr<Config> config) override {
RefCountedPtr<Config> config) override {
return nullptr;
}
};

@ -16,26 +16,29 @@
#include <regex>
#include "absl/strings/numbers.h"
#include <gmock/gmock.h>
#include <gtest/gtest.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.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
void VerifyRegexMatch(grpc_error* error, const std::regex& e) {
std::smatch match;
std::string s(grpc_error_string(error));
EXPECT_TRUE(std::regex_search(s, match, e));
GRPC_ERROR_UNREF(error);
}
class XdsBootstrapTest : public ::testing::Test {
public:
XdsBootstrapTest() { grpc_init(); }
~XdsBootstrapTest() { grpc_shutdown_blocking(); }
};
TEST(XdsBootstrapTest, Basic) {
TEST_F(XdsBootstrapTest, Basic) {
const char* json_str =
"{"
" \"xds_servers\": ["
@ -108,7 +111,7 @@ TEST(XdsBootstrapTest, Basic) {
::testing::Property(&Json::string_value, "1")))));
}
TEST(XdsBootstrapTest, ValidWithoutChannelCredsAndNode) {
TEST_F(XdsBootstrapTest, ValidWithoutChannelCredsAndNode) {
const char* json_str =
"{"
" \"xds_servers\": ["
@ -127,36 +130,36 @@ TEST(XdsBootstrapTest, ValidWithoutChannelCredsAndNode) {
EXPECT_EQ(bootstrap.node(), nullptr);
}
TEST(XdsBootstrapTest, MissingXdsServers) {
TEST_F(XdsBootstrapTest, MissingXdsServers) {
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse("{}", &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(std::string("\"xds_servers\" field not present"));
VerifyRegexMatch(error, e);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex("\"xds_servers\" field not present"));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, TopFieldsWrongTypes) {
TEST_F(XdsBootstrapTest, TopFieldsWrongTypes) {
const char* json_str =
"{"
" \"xds_servers\":1,"
" \"node\":1"
" \"node\":1,"
" \"certificate_providers\":1"
"}";
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("\"xds_servers\" field is not an array(.*)"
"\"node\" field is not an object"));
VerifyRegexMatch(error, e);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex(
"\"xds_servers\" field is not an array.*"
"\"node\" field is not an object.*"
"\"certificate_providers\" field is not an object"));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, XdsServerMissingServerUri) {
TEST_F(XdsBootstrapTest, XdsServerMissingServerUri) {
const char* json_str =
"{"
" \"xds_servers\":[{}]"
@ -165,16 +168,14 @@ TEST(XdsBootstrapTest, XdsServerMissingServerUri) {
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"xds_servers\" array(.*)"
"errors parsing index 0(.*)"
"\"server_uri\" field not present"));
VerifyRegexMatch(error, e);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
"errors parsing index 0.*"
"\"server_uri\" field not present"));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
TEST_F(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
const char* json_str =
"{"
" \"xds_servers\":["
@ -188,17 +189,16 @@ TEST(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"xds_servers\" array(.*)"
"errors parsing index 0(.*)"
"\"server_uri\" field is not a string(.*)"
"\"channel_creds\" field is not an array"));
VerifyRegexMatch(error, e);
EXPECT_THAT(
grpc_error_string(error),
::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
"errors parsing index 0.*"
"\"server_uri\" field is not a string.*"
"\"channel_creds\" field is not an array"));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
TEST_F(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
const char* json_str =
"{"
" \"xds_servers\":["
@ -217,19 +217,18 @@ TEST(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"xds_servers\" array(.*)"
"errors parsing index 0(.*)"
"errors parsing \"channel_creds\" array(.*)"
"errors parsing index 0(.*)"
"\"type\" field is not a string(.*)"
"\"config\" field is not an object"));
VerifyRegexMatch(error, e);
EXPECT_THAT(
grpc_error_string(error),
::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
"errors parsing index 0.*"
"errors parsing \"channel_creds\" array.*"
"errors parsing index 0.*"
"\"type\" field is not a string.*"
"\"config\" field is not an object"));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, NodeFieldsWrongTypes) {
TEST_F(XdsBootstrapTest, NodeFieldsWrongTypes) {
const char* json_str =
"{"
" \"node\":{"
@ -243,18 +242,16 @@ TEST(XdsBootstrapTest, NodeFieldsWrongTypes) {
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"node\" object(.*)"
"\"id\" field is not a string(.*)"
"\"cluster\" field is not a string(.*)"
"\"locality\" field is not an object(.*)"
"\"metadata\" field is not an object"));
VerifyRegexMatch(error, e);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex("errors parsing \"node\" object.*"
"\"id\" field is not a string.*"
"\"cluster\" field is not a string.*"
"\"locality\" field is not an object.*"
"\"metadata\" field is not an object"));
GRPC_ERROR_UNREF(error);
}
TEST(XdsBootstrapTest, LocalityFieldsWrongType) {
TEST_F(XdsBootstrapTest, LocalityFieldsWrongType) {
const char* json_str =
"{"
" \"node\":{"
@ -269,33 +266,207 @@ TEST(XdsBootstrapTest, LocalityFieldsWrongType) {
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("errors parsing \"node\" object(.*)"
"errors parsing \"locality\" object(.*)"
"\"region\" field is not a string(.*)"
"\"zone\" field is not a string(.*)"
"\"subzone\" field is not a string"));
VerifyRegexMatch(error, e);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex("errors parsing \"node\" object.*"
"errors parsing \"locality\" object.*"
"\"region\" field is not a string.*"
"\"zone\" field is not a string.*"
"\"subzone\" field is not a string"));
GRPC_ERROR_UNREF(error);
}
TEST_F(XdsBootstrapTest, CertificateProvidersElementWrongType) {
const char* json_str =
"{"
" \"xds_servers\": ["
" {"
" \"server_uri\": \"fake:///lb\""
" }"
" ],"
" \"certificate_providers\": {"
" \"plugin\":1"
" }"
"}";
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex(
"errors parsing \"certificate_providers\" object.*"
"element \"plugin\" is not an object"));
GRPC_ERROR_UNREF(error);
}
TEST_F(XdsBootstrapTest, CertificateProvidersPluginNameWrongType) {
const char* json_str =
"{"
" \"xds_servers\": ["
" {"
" \"server_uri\": \"fake:///lb\""
" }"
" ],"
" \"certificate_providers\": {"
" \"plugin\": {"
" \"plugin_name\":1"
" }"
" }"
"}";
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex(
"errors parsing \"certificate_providers\" object.*"
"errors parsing element \"plugin\".*"
"\"plugin_name\" field is not a string"));
GRPC_ERROR_UNREF(error);
}
class FakeCertificateProviderFactory : public CertificateProviderFactory {
public:
class Config : public CertificateProviderFactory::Config {
public:
explicit Config(int value) : value_(value) {}
int value() const { return value_; }
const char* name() const override { return "fake"; }
private:
int value_;
};
const char* name() const override { return "fake"; }
RefCountedPtr<CertificateProviderFactory::Config>
CreateCertificateProviderConfig(const Json& config_json,
grpc_error** error) override {
std::vector<grpc_error*> error_list;
EXPECT_EQ(config_json.type(), Json::Type::OBJECT);
auto it = config_json.object_value().find("value");
if (it == config_json.object_value().end()) {
return MakeRefCounted<FakeCertificateProviderFactory::Config>(0);
} else if (it->second.type() != Json::Type::NUMBER) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:config field:value not of type number");
} else {
int value = 0;
EXPECT_TRUE(absl::SimpleAtoi(it->second.string_value(), &value));
return MakeRefCounted<FakeCertificateProviderFactory::Config>(value);
}
return nullptr;
}
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
RefCountedPtr<CertificateProviderFactory::Config> config) override {
return nullptr;
}
};
TEST_F(XdsBootstrapTest, CertificateProvidersFakePluginParsingError) {
CertificateProviderRegistry::RegisterCertificateProviderFactory(
absl::make_unique<FakeCertificateProviderFactory>());
const char* json_str =
"{"
" \"xds_servers\": ["
" {"
" \"server_uri\": \"fake:///lb\""
" }"
" ],"
" \"certificate_providers\": {"
" \"fake_plugin\": {"
" \"plugin_name\": \"fake\","
" \"config\": {"
" \"value\": \"10\""
" }"
" }"
" }"
"}";
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
EXPECT_THAT(grpc_error_string(error),
::testing::ContainsRegex(
"errors parsing \"certificate_providers\" object.*"
"errors parsing element \"fake_plugin\".*"
"field:config field:value not of type number"));
GRPC_ERROR_UNREF(error);
}
TEST_F(XdsBootstrapTest, CertificateProvidersFakePluginParsingSuccess) {
CertificateProviderRegistry::RegisterCertificateProviderFactory(
absl::make_unique<FakeCertificateProviderFactory>());
const char* json_str =
"{"
" \"xds_servers\": ["
" {"
" \"server_uri\": \"fake:///lb\""
" }"
" ],"
" \"certificate_providers\": {"
" \"fake_plugin\": {"
" \"plugin_name\": \"fake\","
" \"config\": {"
" \"value\": 10"
" }"
" }"
" }"
"}";
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const CertificateProviderStore::PluginDefinition& fake_plugin =
bootstrap.certificate_providers().at("fake_plugin");
ASSERT_EQ(fake_plugin.plugin_name, "fake");
ASSERT_STREQ(fake_plugin.config->name(), "fake");
ASSERT_EQ(static_cast<RefCountedPtr<FakeCertificateProviderFactory::Config>>(
fake_plugin.config)
->value(),
10);
}
TEST_F(XdsBootstrapTest, CertificateProvidersFakePluginEmptyConfig) {
CertificateProviderRegistry::RegisterCertificateProviderFactory(
absl::make_unique<FakeCertificateProviderFactory>());
const char* json_str =
"{"
" \"xds_servers\": ["
" {"
" \"server_uri\": \"fake:///lb\""
" }"
" ],"
" \"certificate_providers\": {"
" \"fake_plugin\": {"
" \"plugin_name\": \"fake\""
" }"
" }"
"}";
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(json_str, &error);
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
ASSERT_TRUE(error == GRPC_ERROR_NONE);
const CertificateProviderStore::PluginDefinition& fake_plugin =
bootstrap.certificate_providers().at("fake_plugin");
ASSERT_EQ(fake_plugin.plugin_name, "fake");
ASSERT_STREQ(fake_plugin.config->name(), "fake");
ASSERT_EQ(static_cast<RefCountedPtr<FakeCertificateProviderFactory::Config>>(
fake_plugin.config)
->value(),
0);
}
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
// Regexes don't work in old libstdc++ versions, so just skip testing in those
// cases
#if defined(__GLIBCXX__) && (__GLIBCXX__ <= 20150623)
gpr_log(GPR_ERROR,
"Skipping xds_bootstrap_test since std::regex is not supported on "
"this system.");
return 0;
#endif
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

Loading…
Cancel
Save