@ -38,410 +38,271 @@
# include "src/core/lib/config/core_configuration.h"
# include "src/core/lib/gprpp/ref_counted_ptr.h"
# include "src/core/lib/json/json.h"
# include "src/core/lib/json/json_util .h"
# include "src/core/lib/json/json_object_loader .h"
# include "src/core/lib/security/certificate_provider/certificate_provider_factory.h"
# include "src/core/lib/security/certificate_provider/certificate_provider_registry.h"
# include "src/core/lib/security/credentials/channel_creds_registry.h"
namespace grpc_core {
namespace {
//
// GrpcXdsBootstrap::GrpcNode::Locality
//
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 ) ;
const JsonLoaderInterface * GrpcXdsBootstrap : : GrpcNode : : Locality : : JsonLoader (
const JsonArgs & ) {
static const auto * loader =
JsonObjectLoader < Locality > ( )
. OptionalField ( " region " , & Locality : : region )
. OptionalField ( " zone " , & Locality : : zone )
. OptionalField ( " sub_zone " , & Locality : : sub_zone )
. Finish ( ) ;
return loader ;
}
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 ) ;
//
// GrpcXdsBootstrap::GrpcNode
//
const JsonLoaderInterface * GrpcXdsBootstrap : : GrpcNode : : JsonLoader (
const JsonArgs & ) {
static const auto * loader =
JsonObjectLoader < GrpcNode > ( )
. OptionalField ( " id " , & GrpcNode : : id_ )
. OptionalField ( " cluster " , & GrpcNode : : cluster_ )
. OptionalField ( " locality " , & GrpcNode : : locality_ )
. OptionalField ( " metadata " , & GrpcNode : : metadata_ )
. Finish ( ) ;
return loader ;
}
} // namespace
//
// GrpcXdsBootstrap::GrpcXdsServer::ChannelCreds
//
const JsonLoaderInterface *
GrpcXdsBootstrap : : GrpcXdsServer : : ChannelCreds : : JsonLoader ( const JsonArgs & ) {
static const auto * loader =
JsonObjectLoader < ChannelCreds > ( )
. Field ( " type " , & ChannelCreds : : type )
. OptionalField ( " config " , & ChannelCreds : : config )
. Finish ( ) ;
return loader ;
}
//
// GrpcXdsBootstrap
// GrpcXdsBootstrap::GrpcXdsServer
//
std : : unique_ptr < GrpcXdsBootstrap > GrpcXdsBootstrap : : Create (
absl : : string_view json_string , 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 ) , error ) ;
namespace {
constexpr absl : : string_view kServerFeatureXdsV3 = " xds_v3 " ;
constexpr absl : : string_view kServerFeatureIgnoreResourceDeletion =
" ignore_resource_deletion " ;
} // namespace
bool GrpcXdsBootstrap : : GrpcXdsServer : : ShouldUseV3 ( ) const {
return server_features_ . find ( std : : string ( kServerFeatureXdsV3 ) ) ! =
server_features_ . end ( ) ;
}
GrpcXdsBootstrap : : GrpcXdsBootstrap ( Json json , grpc_error_handle * error ) {
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 ) ;
bool GrpcXdsBootstrap : : GrpcXdsServer : : IgnoreResourceDeletion ( ) const {
return server_features_ . find ( std : : string (
kServerFeatureIgnoreResourceDeletion ) ) ! = server_features_ . end ( ) ;
}
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 ) ;
bool GrpcXdsBootstrap : : GrpcXdsServer : : Equals ( const XdsServer & other ) const {
const auto & o = static_cast < const GrpcXdsServer & > ( other ) ;
return ( server_uri_ = = o . server_uri_ & &
channel_creds_ . type = = o . channel_creds_ . type & &
channel_creds_ . config = = o . channel_creds_ . config & &
server_features_ = = o . server_features_ ) ;
}
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 ) ;
const JsonLoaderInterface * GrpcXdsBootstrap : : GrpcXdsServer : : JsonLoader (
const JsonArgs & ) {
static const auto * loader =
JsonObjectLoader < GrpcXdsServer > ( )
. Field ( " server_uri " , & GrpcXdsServer : : server_uri_ )
. Finish ( ) ;
return loader ;
}
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 ( ) ) ;
void GrpcXdsBootstrap : : GrpcXdsServer : : JsonPostLoad ( const Json & json ,
const JsonArgs & args ,
ErrorList * errors ) {
// Parse "channel_creds".
auto channel_creds_list = LoadJsonObjectField < std : : vector < ChannelCreds > > (
json . object_value ( ) , args , " channel_creds " , errors ) ;
if ( channel_creds_list . has_value ( ) ) {
ScopedField field ( errors , " .channel_creds " ) ;
for ( size_t i = 0 ; i < channel_creds_list - > size ( ) ; + + i ) {
ScopedField field ( errors , absl : : StrCat ( " [ " , i , " ] " ) ) ;
auto & creds = ( * channel_creds_list ) [ i ] ;
// Select the first channel creds type that we support.
if ( channel_creds_ . type . empty ( ) & &
CoreConfiguration : : Get ( ) . channel_creds_registry ( ) . IsSupported (
creds . type ) ) {
if ( ! CoreConfiguration : : Get ( ) . channel_creds_registry ( ) . IsValidConfig (
creds . type , creds . config ) ) {
errors - > AddError ( absl : : StrCat (
" invalid config for channel creds type \" " , creds . type , " \" " ) ) ;
continue ;
}
channel_creds_ . type = std : : move ( creds . type ) ;
channel_creds_ . config = std : : move ( creds . config ) ;
}
}
}
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 ( channel_creds_ . type . empty ( ) ) {
errors - > AddError ( " no known creds type found " ) ;
}
}
if ( error_list . empty ( ) ) {
authorities_ [ name ] = std : : move ( authority ) ;
// Parse "server_features".
{
ScopedField field ( errors , " .server_features " ) ;
auto it = json . object_value ( ) . find ( " server_features " ) ;
if ( it ! = json . object_value ( ) . end ( ) ) {
if ( it - > second . type ( ) ! = Json : : Type : : ARRAY ) {
errors - > AddError ( " is not an array " ) ;
} else {
const Json : : Array & array = it - > second . array_value ( ) ;
for ( const Json & feature_json : array ) {
if ( feature_json . type ( ) = = Json : : Type : : STRING & &
( feature_json . string_value ( ) = = kServerFeatureXdsV3 | |
feature_json . string_value ( ) = =
kServerFeatureIgnoreResourceDeletion ) ) {
server_features_ . insert ( feature_json . string_value ( ) ) ;
}
}
}
}
}
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 ( ) ) ;
}
Json GrpcXdsBootstrap : : GrpcXdsServer : : ToJson ( ) const {
Json : : Object channel_creds_json { { " type " , channel_creds_ . type } } ;
if ( ! channel_creds_ . config . empty ( ) ) {
channel_creds_json [ " config " ] = channel_creds_ . config ;
}
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 ) ;
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 GRPC_ERROR_CREATE_FROM_VECTOR ( " errors parsing \" node \" object " ,
& error_list ) ;
return json ;
}
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 ( ) ) ;
}
//
// GrpcXdsBootstrap::GrpcAuthority
//
const JsonLoaderInterface * GrpcXdsBootstrap : : GrpcAuthority : : JsonLoader (
const JsonArgs & ) {
static const auto * loader =
JsonObjectLoader < GrpcAuthority > ( )
. OptionalField (
" client_listener_resource_name_template " ,
& GrpcAuthority : : client_listener_resource_name_template_ )
. OptionalField ( " xds_servers " , & GrpcAuthority : : servers_ )
. Finish ( ) ;
return loader ;
}
//
// GrpcXdsBootstrap
//
absl : : StatusOr < std : : unique_ptr < GrpcXdsBootstrap > > GrpcXdsBootstrap : : Create (
absl : : string_view json_string ) {
auto json = Json : : Parse ( json_string ) ;
if ( ! json . ok ( ) ) {
return absl : : InvalidArgumentError ( absl : : StrCat (
" Failed to parse bootstrap JSON string: " , json . status ( ) . ToString ( ) ) ) ;
}
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 ( ) ) ;
// Validate JSON.
class XdsJsonArgs : public JsonArgs {
public :
bool IsEnabled ( absl : : string_view key ) const override {
if ( key = = " federation " ) return XdsFederationEnabled ( ) ;
return true ;
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR ( " errors parsing \" locality \" object " ,
& error_list ) ;
} ;
auto bootstrap = LoadFromJson < GrpcXdsBootstrap > ( * json , XdsJsonArgs ( ) ) ;
if ( ! bootstrap . ok ( ) ) return bootstrap . status ( ) ;
return absl : : make_unique < GrpcXdsBootstrap > ( std : : move ( * bootstrap ) ) ;
}
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 ) ;
const JsonLoaderInterface * GrpcXdsBootstrap : : JsonLoader ( const JsonArgs & ) {
static const auto * loader =
JsonObjectLoader < GrpcXdsBootstrap > ( )
. Field ( " xds_servers " , & GrpcXdsBootstrap : : servers_ )
. OptionalField ( " node " , & GrpcXdsBootstrap : : node_ )
. OptionalField ( " certificate_providers " ,
& GrpcXdsBootstrap : : certificate_providers_ )
. OptionalField (
" server_listener_resource_name_template " ,
& GrpcXdsBootstrap : : server_listener_resource_name_template_ )
. OptionalField ( " authorities " , & GrpcXdsBootstrap : : authorities_ ,
" federation " )
. OptionalField ( " client_default_listener_resource_name_template " ,
& GrpcXdsBootstrap : :
client_default_listener_resource_name_template_ ,
" federation " )
. Finish ( ) ;
return loader ;
}
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 ( ) ) ) ;
// Find config JSON.
absl : : optional < Json > config_json ;
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 {
config_json = it - > second ;
}
} else {
// "config" is an optional field, so default to an empty JSON object.
config_json = Json : : Object ( ) ;
}
// Try to instantiate the provider.
CertificateProviderFactory * factory =
CoreConfiguration : : Get ( )
. certificate_provider_registry ( )
. LookupCertificateProviderFactory ( plugin_name ) ;
if ( factory = = nullptr ) {
error_list . push_back ( GRPC_ERROR_CREATE_FROM_CPP_STRING (
absl : : StrCat ( " Unrecognized plugin name: " , plugin_name ) ) ) ;
} else if ( config_json . has_value ( ) ) {
grpc_error_handle parse_error = GRPC_ERROR_NONE ;
RefCountedPtr < CertificateProviderFactory : : Config > config =
factory - > CreateCertificateProviderConfig ( * config_json , & parse_error ) ;
if ( ! GRPC_ERROR_IS_NONE ( parse_error ) ) {
error_list . push_back ( parse_error ) ;
} else {
certificate_providers_ . insert (
{ instance_name , { std : : move ( plugin_name ) , std : : move ( config ) } } ) ;
void GrpcXdsBootstrap : : JsonPostLoad ( const Json & /*json*/ ,
const JsonArgs & /*args*/ ,
ErrorList * errors ) {
// Verify that each authority has the right prefix in the
// client_listener_resource_name_template field.
{
ScopedField field ( errors , " .authorities " ) ;
for ( const auto & p : authorities_ ) {
const std : : string & name = p . first ;
const GrpcAuthority & authority =
static_cast < const GrpcAuthority & > ( p . second ) ;
ScopedField field (
errors , absl : : StrCat ( " [ \" " , name ,
" \" ].client_listener_resource_name_template " ) ) ;
std : : string expected_prefix = absl : : StrCat ( " xdstp:// " , name , " / " ) ;
if ( ! authority . client_listener_resource_name_template ( ) . empty ( ) & &
! absl : : StartsWith ( authority . client_listener_resource_name_template ( ) ,
expected_prefix ) ) {
errors - > AddError (
absl : : StrCat ( " field must begin with \" " , expected_prefix , " \" " ) ) ;
}
}
}
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 ( ) ) ) ;
if ( node_ . has_value ( ) ) {
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 ( ) ,
Json { 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 " ) ;
absl : : StrFormat ( " servers=[ \n %s \n ], \n " , servers_ [ 0 ] . ToJson ( ) . Dump ( ) ) ) ;
if ( ! client_default_listener_resource_name_template_ . empty ( ) ) {
parts . push_back ( absl : : StrFormat (
" client_default_listener_resource_name_template= \" %s \" , \n " ,
@ -457,14 +318,14 @@ std::string GrpcXdsBootstrap::ToString() const {
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 ) ) ;
entry . second . client_listener_resource_name_template ( ) ) ) ;
if ( entry . second . server ( ) ! = nullptr ) {
parts . push_back ( absl : : StrFormat (
" servers=[ \n %s \n ], \n " ,
static_cast < const GrpcXdsServer * > ( entry . second . server ( ) )
- > ToJson ( )
. Dump ( ) ) ) ;
}
parts . push_back ( " }, \n " ) ;
}
parts . push_back ( " } \n " ) ;
@ -482,56 +343,28 @@ std::string GrpcXdsBootstrap::ToString() const {
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 XdsBootstrap : : Authority * GrpcXdsBootstrap : : LookupAuthority (
const std : : string & name ) const {
auto it = authorities_ . find ( name ) ;
if ( it ! = authorities_ . end ( ) ) {
return & it - > second ;
}
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 ;
return nullptr ;
}
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 ) ;
const XdsBootstrap : : XdsServer * GrpcXdsBootstrap : : FindXdsServer (
const XdsBootstrap : : XdsServer & server ) const {
if ( static_cast < const GrpcXdsServer & > ( server ) = = servers_ [ 0 ] ) {
return & servers_ [ 0 ] ;
}
for ( auto & p : authorities_ ) {
const auto * authority_server =
static_cast < const GrpcXdsServer * > ( p . second . server ( ) ) ;
if ( authority_server ! = nullptr & & * authority_server = = server ) {
return authority_server ;
}
json [ " server_features " ] = std : : move ( server_features_json ) ;
}
return json ;
return nullptr ;
}
} // namespace grpc_core