Skip to content

Commit 75d9091

Browse files
authored
xds: allow wildcard listener port on server (#9341)
This implements grpc/proposal#559 RELEASE NOTES: - xds/server: Support listener resource with a wildcard port that enables deployments where server ports are assigned dynamically.
1 parent ef79129 commit 75d9091

2 files changed

Lines changed: 73 additions & 1 deletion

File tree

internal/xds/server/listener_wrapper.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,10 @@ func (lw *ldsWatcher) ResourceChanged(update *xdsresource.ListenerUpdate, onDone
457457
// What this means is that the XDSClient has ACKed a resource which can push
458458
// the server into a "not serving" mode. This is not ideal, but this is
459459
// what we have decided to do.
460-
if ilc == nil || (ilc.Address != l.addr || ilc.Port != l.port) {
460+
//
461+
// A port value of 0 in the xDS Listener matches any listening port, but the
462+
// listener address itself must still match exactly.
463+
if ilc == nil || ilc.Address != l.addr || (ilc.Port != "0" && ilc.Port != l.port) {
461464
// TODO(purnesh42h): Are there any other cases where this can be
462465
// treated as an ambient error?
463466
l.mu.Lock()

xds/server_serving_mode_ext_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,3 +535,72 @@ func (s) TestServer_MismatchedAddressListenerReceivedOnServer(t *testing.T) {
535535
defer cc.Close()
536536
waitForSuccessfulRPC(ctx, t, cc)
537537
}
538+
539+
// Tests the case where the server receives a listener resource with a wildcard
540+
// port. The server should match the listener address and transition to Serving
541+
// mode regardless of the port on which it is listening.
542+
func (s) TestServer_ListenerMatchWithWildcardPort(t *testing.T) {
543+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
544+
defer cancel()
545+
managementServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true})
546+
547+
// Create bootstrap configuration pointing to the above management server.
548+
nodeID := uuid.New().String()
549+
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address)
550+
551+
// Create a listener on a local port to act as the xDS enabled gRPC server.
552+
lis, err := testutils.LocalTCPListener()
553+
if err != nil {
554+
t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
555+
}
556+
host, port, err := hostPortFromListener(lis)
557+
if err != nil {
558+
t.Fatalf("Failed to retrieve host and port of server: %v", err)
559+
}
560+
561+
// Configure a server-side listener with a wildcard port on the management
562+
// server. Construct the listener with the actual port first so its resource
563+
// name matches the server's default watch name, then replace only the port
564+
// value in the socket address with zero.
565+
listener := e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone, "routeName")
566+
listener.Address.GetSocketAddress().PortSpecifier = &v3corepb.SocketAddress_PortValue{
567+
PortValue: 0,
568+
}
569+
resources := e2e.UpdateOptions{
570+
NodeID: nodeID,
571+
Listeners: []*v3listenerpb.Listener{listener},
572+
SkipValidation: true,
573+
}
574+
if err := managementServer.Update(ctx, resources); err != nil {
575+
t.Fatal(err)
576+
}
577+
578+
// Start an xDS-enabled gRPC server with the above bootstrap configuration.
579+
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
580+
if err != nil {
581+
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
582+
}
583+
pool := xdsclient.NewPool(config)
584+
modeChangeHandler := newServingModeChangeHandler(t)
585+
modeChangeOpt := xds.ServingModeCallback(modeChangeHandler.modeChangeCallback)
586+
createStubServer(t, lis, modeChangeOpt, xds.ClientPoolForTesting(pool))
587+
588+
// Ensure the server transitions to SERVING mode despite the wildcard port.
589+
select {
590+
case <-ctx.Done():
591+
t.Fatal("Timeout waiting for the xDS-enabled gRPC server to go SERVING")
592+
case gotMode := <-modeChangeHandler.modeCh:
593+
if gotMode != connectivity.ServingModeServing {
594+
t.Fatalf("Mode changed to %v, want %v", gotMode, connectivity.ServingModeServing)
595+
}
596+
}
597+
598+
// Create a gRPC client to the server and verify that we can make a
599+
// successful RPC.
600+
cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
601+
if err != nil {
602+
t.Fatalf("Failed to dial local test server: %v", err)
603+
}
604+
defer cc.Close()
605+
waitForSuccessfulRPC(ctx, t, cc)
606+
}

0 commit comments

Comments
 (0)