Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions internal/xds/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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".
Expand Down
16 changes: 16 additions & 0 deletions xds/internal/xdsclient/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
214 changes: 214 additions & 0 deletions xds/internal/xdsclient/bootstrap/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}
}