Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xdsclient: use dataplane authority for virtualhost lookup #6997

Merged
merged 14 commits into from Feb 28, 2024
69 changes: 69 additions & 0 deletions test/xds/xds_client_federation_test.go
Expand Up @@ -140,6 +140,75 @@ func (s) TestClientSideFederation(t *testing.T) {
}
}

// TestClientSideFederationWithTDOM tests that federation is supported with new
// xdstp style names with TD Open Mesh (TDOM) Authority. TD Open Mesh Authority
// currently only support new style for LDS. So, this test only tests the new
// style for LDS resources and the old style for other resources.
func (s) TestClientSideFederationWithTDOM(t *testing.T) {
// Start a management server as TDOM authority.
const tdomAuth = "traffic-director-global.xds.googleapis.com"
tdomAuthServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{})
if err != nil {
t.Fatalf("Failed to spin up the xDS management server: %v", err)
}
t.Cleanup(tdomAuthServer.Stop)

// Create a bootstrap file in a temporary directory.
nodeID := uuid.New().String()
bootstrapContents, err := bootstrap.Contents(bootstrap.Options{
NodeID: nodeID,
ServerURI: tdomAuthServer.Address,
ClientDefaultListenerResourceNameTemplate: fmt.Sprintf("xdstp://%s/envoy.config.listener.v3.Listener/%%s", tdomAuth),
Authorities: map[string]string{tdomAuth: tdomAuthServer.Address},
})
if err != nil {
t.Fatalf("Failed to create bootstrap file: %v", err)
}

resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
resolver, err := resolverBuilder(bootstrapContents)
if err != nil {
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
}
server := stubserver.StartTestService(t, nil)
defer server.Stop()

const serviceName = "my-service-client-side-xds"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This string looks like it would have worked before your changes. Does this test fail without your changes to xds_resolver.go?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Now the serviceName has 2 special chars - , and /.

// LDS is new style name.
ldsName := fmt.Sprintf("xdstp://%s/envoy.config.listener.v3.Listener/%s", tdomAuth, serviceName)
// All other resources are with old style name.
rdsName := "route-" + serviceName
cdsName := "cluster-" + serviceName
edsName := "endpoints-" + serviceName
arvindbr8 marked this conversation as resolved.
Show resolved Hide resolved

resourceUpdate := e2e.UpdateOptions{
NodeID: nodeID,
Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
Routes: []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(rdsName, serviceName, cdsName)},
Clusters: []*v3clusterpb.Cluster{e2e.DefaultCluster(cdsName, edsName, e2e.SecurityLevelNone)},
Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(edsName, "localhost", []uint32{testutils.ParsePort(t, server.Address)})},
SkipValidation: true,
}

ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
defer cancel()
if err := tdomAuthServer.Update(ctx, resourceUpdate); err != nil {
t.Fatal(err)
}

// Create a ClientConn and make a successful RPC.
cc, err := grpc.Dial(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
if err != nil {
t.Fatalf("failed to dial local test server: %v", err)
}
defer cc.Close()

client := testgrpc.NewTestServiceClient(cc)
if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
t.Fatalf("rpc EmptyCall() failed: %v", err)
}
}

// TestFederation_UnknownAuthorityInDialTarget tests the case where a ClientConn
// is created with a dial target containing an authority which is not specified
// in the bootstrap configuration. The test verifies that RPCs on the ClientConn
Expand Down
12 changes: 10 additions & 2 deletions xds/internal/resolver/xds_resolver.go
Expand Up @@ -22,6 +22,7 @@
import (
"context"
"fmt"
"net/url"
"strings"
"sync/atomic"

Expand Down Expand Up @@ -119,6 +120,7 @@
endpoint = target.URL.Opaque
}
endpoint = strings.TrimPrefix(endpoint, "/")
r.dataplaneAuthority = url.PathEscape(endpoint)
r.ldsResourceName = bootstrap.PopulateResourceTemplate(template, endpoint)
r.listenerWatcher = newListenerWatcher(r.ldsResourceName, r)
return r, nil
Expand Down Expand Up @@ -190,6 +192,12 @@
serializer *grpcsync.CallbackSerializer
serializerCancel context.CancelFunc

// dataplaneAuthority is the authority used for the data plane connections,
// which is also used to select the VirtualHost within the xDS
// RouteConfiguration. This is %-encoded to match with VirtualHost Domain
// in xDS RouteConfiguration.
dataplaneAuthority string

ldsResourceName string
listenerWatcher *listenerWatcher
listenerUpdateRecvd bool
Expand Down Expand Up @@ -413,9 +421,9 @@
}

func (r *xdsResolver) applyRouteConfigUpdate(update xdsresource.RouteConfigUpdate) {
matchVh := xdsresource.FindBestMatchingVirtualHost(r.ldsResourceName, update.VirtualHosts)
matchVh := xdsresource.FindBestMatchingVirtualHost(r.dataplaneAuthority, update.VirtualHosts)
if matchVh == nil {
r.onError(fmt.Errorf("no matching virtual host found for %q", r.ldsResourceName))
r.onError(fmt.Errorf("no matching virtual host found for %q", r.dataplaneAuthority))

Check warning on line 426 in xds/internal/resolver/xds_resolver.go

View check run for this annotation

Codecov / codecov/patch

xds/internal/resolver/xds_resolver.go#L426

Added line #L426 was not covered by tests
return
}
r.currentRouteConfig = update
Expand Down