xds/federation: support new bootstrap fields and protect them by an env var (#4936)

This commit is contained in:
Menghan Li 2021-11-08 14:18:52 -08:00 committed by GitHub
parent c53203c581
commit 82c2825168
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 234 additions and 0 deletions

View File

@ -44,6 +44,7 @@ const (
aggregateAndDNSSupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER"
retrySupportEnv = "GRPC_XDS_EXPERIMENTAL_ENABLE_RETRY"
rbacSupportEnv = "GRPC_XDS_EXPERIMENTAL_RBAC"
federationEnv = "GRPC_EXPERIMENTAL_XDS_FEDERATION"
c2pResolverSupportEnv = "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER"
c2pResolverTestOnlyTrafficDirectorURIEnv = "GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI"
@ -88,6 +89,9 @@ var (
// "GRPC_XDS_EXPERIMENTAL_RBAC" to "false".
RBACSupport = !strings.EqualFold(os.Getenv(rbacSupportEnv), "false")
// FederationSupport indicates whether federation support is enabled.
FederationSupport = strings.EqualFold(os.Getenv(federationEnv), "true")
// C2PResolverSupport indicates whether support for C2P resolver is enabled.
// This can be enabled by setting the environment variable
// "GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER" to "true".

View File

@ -338,6 +338,22 @@ func NewConfigFromContents(data []byte) (*Config, error) {
if err := json.Unmarshal(v, &config.ServerListenerResourceNameTemplate); err != nil {
return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
}
case "client_default_listener_resource_name_template":
if !env.FederationSupport {
logger.Warningf("xds: bootstrap field %v is not support when Federation is disabled", k)
continue
}
if err := json.Unmarshal(v, &config.ClientDefaultListenerResourceNameTemplate); err != nil {
return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
}
case "authorities":
if !env.FederationSupport {
logger.Warningf("xds: bootstrap field %v is not support when Federation is disabled", k)
continue
}
if err := json.Unmarshal(v, &config.Authorities); err != nil {
return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
}
default:
logger.Warningf("Bootstrap content has unknown field: %s", k)
}

View File

@ -775,3 +775,217 @@ func TestNewConfigWithServerListenerResourceNameTemplate(t *testing.T) {
})
}
}
func TestNewConfigWithFederation(t *testing.T) {
cancel := setupBootstrapOverride(map[string]string{
"badClientListenerResourceNameTemplate": `
{
"node": { "id": "ENVOY_NODE_ID" },
"xds_servers" : [{
"server_uri": "trafficdirector.googleapis.com:443"
}],
"client_default_listener_resource_name_template": 123456789
}`,
"badClientListenerResourceNameTemplatePerAuthority": `
{
"node": { "id": "ENVOY_NODE_ID" },
"xds_servers" : [{
"server_uri": "trafficdirector.googleapis.com:443",
"channel_creds": [ { "type": "google_default" } ]
}],
"authorities": {
"xds.td.com": {
"client_listener_resource_name_template": "some/template/%s",
"xds_servers": [{
"server_uri": "td.com",
"channel_creds": [ { "type": "google_default" } ],
"server_features" : ["foo", "bar", "xds_v3"]
}]
}
}
}`,
"good": `
{
"node": {
"id": "ENVOY_NODE_ID",
"metadata": {
"TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
}
},
"xds_servers" : [{
"server_uri": "trafficdirector.googleapis.com:443",
"channel_creds": [ { "type": "google_default" } ]
}],
"server_listener_resource_name_template": "xdstp://xds.example.com/envoy.config.listener.v3.Listener/grpc/server?listening_address=%s",
"client_default_listener_resource_name_template": "xdstp://xds.example.com/envoy.config.listener.v3.Listener/%s",
"authorities": {
"xds.td.com": {
"client_listener_resource_name_template": "xdstp://xds.td.com/envoy.config.listener.v3.Listener/%s",
"xds_servers": [{
"server_uri": "td.com",
"channel_creds": [ { "type": "google_default" } ],
"server_features" : ["foo", "bar", "xds_v3"]
}]
}
}
}`,
// If client_default_listener_resource_name_template is not set, it
// defaults to "%s".
"goodWithDefaultDefaultClientListenerTemplate": `
{
"node": {
"id": "ENVOY_NODE_ID",
"metadata": {
"TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
}
},
"xds_servers" : [{
"server_uri": "trafficdirector.googleapis.com:443",
"channel_creds": [ { "type": "google_default" } ]
}]
}`,
// If client_listener_resource_name_template in authority is not set, it
// defaults to
// "xdstp://<authority_name>/envoy.config.listener.v3.Listener/%s".
"goodWithDefaultClientListenerTemplatePerAuthority": `
{
"node": {
"id": "ENVOY_NODE_ID",
"metadata": {
"TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
}
},
"xds_servers" : [{
"server_uri": "trafficdirector.googleapis.com:443",
"channel_creds": [ { "type": "google_default" } ]
}],
"client_default_listener_resource_name_template": "xdstp://xds.example.com/envoy.config.listener.v3.Listener/%s",
"authorities": {
"xds.td.com": { }
}
}`,
// It's OK for an authority to not have servers. The top-level server
// will be used.
"goodWithNoServerPerAuthority": `
{
"node": {
"id": "ENVOY_NODE_ID",
"metadata": {
"TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
}
},
"xds_servers" : [{
"server_uri": "trafficdirector.googleapis.com:443",
"channel_creds": [ { "type": "google_default" } ]
}],
"client_default_listener_resource_name_template": "xdstp://xds.example.com/envoy.config.listener.v3.Listener/%s",
"authorities": {
"xds.td.com": {
"client_listener_resource_name_template": "xdstp://xds.td.com/envoy.config.listener.v3.Listener/%s"
}
}
}`,
})
defer cancel()
tests := []struct {
name string
wantConfig *Config
wantErr bool
}{
{
name: "badClientListenerResourceNameTemplate",
wantErr: true,
},
{
name: "badClientListenerResourceNameTemplatePerAuthority",
wantErr: true,
},
{
name: "good",
wantConfig: &Config{
XDSServer: &ServerConfig{
ServerURI: "trafficdirector.googleapis.com:443",
Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()),
credsType: "google_default",
TransportAPI: version.TransportV2,
NodeProto: v2NodeProto,
},
ServerListenerResourceNameTemplate: "xdstp://xds.example.com/envoy.config.listener.v3.Listener/grpc/server?listening_address=%s",
ClientDefaultListenerResourceNameTemplate: "xdstp://xds.example.com/envoy.config.listener.v3.Listener/%s",
Authorities: map[string]*Authority{
"xds.td.com": {
ClientListenerResourceNameTemplate: "xdstp://xds.td.com/envoy.config.listener.v3.Listener/%s",
XDSServer: &ServerConfig{
ServerURI: "td.com",
Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()),
credsType: "google_default",
TransportAPI: version.TransportV3,
NodeProto: v3NodeProto,
},
},
},
},
},
{
name: "goodWithDefaultDefaultClientListenerTemplate",
wantConfig: &Config{
XDSServer: &ServerConfig{
ServerURI: "trafficdirector.googleapis.com:443",
Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()),
credsType: "google_default",
TransportAPI: version.TransportV2,
NodeProto: v2NodeProto,
},
ClientDefaultListenerResourceNameTemplate: "%s",
},
},
{
name: "goodWithDefaultClientListenerTemplatePerAuthority",
wantConfig: &Config{
XDSServer: &ServerConfig{
ServerURI: "trafficdirector.googleapis.com:443",
Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()),
credsType: "google_default",
TransportAPI: version.TransportV2,
NodeProto: v2NodeProto,
},
ClientDefaultListenerResourceNameTemplate: "xdstp://xds.example.com/envoy.config.listener.v3.Listener/%s",
Authorities: map[string]*Authority{
"xds.td.com": {
ClientListenerResourceNameTemplate: "xdstp://xds.td.com/envoy.config.listener.v3.Listener/%s",
},
},
},
},
{
name: "goodWithNoServerPerAuthority",
wantConfig: &Config{
XDSServer: &ServerConfig{
ServerURI: "trafficdirector.googleapis.com:443",
Creds: grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()),
credsType: "google_default",
TransportAPI: version.TransportV2,
NodeProto: v2NodeProto,
},
ClientDefaultListenerResourceNameTemplate: "xdstp://xds.example.com/envoy.config.listener.v3.Listener/%s",
Authorities: map[string]*Authority{
"xds.td.com": {
ClientListenerResourceNameTemplate: "xdstp://xds.td.com/envoy.config.listener.v3.Listener/%s",
},
},
},
},
}
oldFederationSupport := env.FederationSupport
env.FederationSupport = true
defer func() { env.FederationSupport = oldFederationSupport }()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testNewConfigWithFileNameEnv(t, test.name, test.wantErr, test.wantConfig)
testNewConfigWithFileContentEnv(t, test.name, test.wantErr, test.wantConfig)
})
}
}