@@ -23,7 +23,6 @@ import (
2323 "errors"
2424 "fmt"
2525 "net"
26- "sync"
2726
2827 "google.golang.org/grpc"
2928 "google.golang.org/grpc/codes"
@@ -76,24 +75,19 @@ type grpcServer interface {
7675// grpc.ServiceRegistrar interface and can be passed to service registration
7776// functions in IDL generated code.
7877type GRPCServer struct {
79- gs grpcServer
80- quit * grpcsync.Event
81- logger * internalgrpclog.PrefixLogger
82- xdsCredsInUse bool
83- opts * serverOptions
84-
85- // clientMu is used only in initXDSClient(), which is called at the
86- // beginning of Serve(), where we have to decide if we have to create a
87- // client or use an existing one.
88- clientMu sync.Mutex
78+ gs grpcServer
79+ quit * grpcsync.Event
80+ logger * internalgrpclog.PrefixLogger
81+ xdsCredsInUse bool
82+ opts * serverOptions
8983 xdsC xdsclient.XDSClient
9084 xdsClientClose func ()
9185}
9286
9387// NewGRPCServer creates an xDS-enabled gRPC server using the passed in opts.
9488// The underlying gRPC server has no service registered and has not started to
9589// accept requests yet.
96- func NewGRPCServer (opts ... grpc.ServerOption ) * GRPCServer {
90+ func NewGRPCServer (opts ... grpc.ServerOption ) ( * GRPCServer , error ) {
9791 newOpts := []grpc.ServerOption {
9892 grpc .ChainUnaryInterceptor (xdsUnaryInterceptor ),
9993 grpc .ChainStreamInterceptor (xdsStreamInterceptor ),
@@ -103,8 +97,6 @@ func NewGRPCServer(opts ...grpc.ServerOption) *GRPCServer {
10397 gs : newGRPCServer (newOpts ... ),
10498 quit : grpcsync .NewEvent (),
10599 }
106- s .logger = internalgrpclog .NewPrefixLogger (logger , fmt .Sprintf (serverPrefix , s ))
107- s .logger .Infof ("Created xds.GRPCServer" )
108100 s .handleServerOptions (opts )
109101
110102 // We type assert our underlying gRPC server to the real grpc.Server here
@@ -119,8 +111,48 @@ func NewGRPCServer(opts ...grpc.ServerOption) *GRPCServer {
119111 }
120112 }
121113
114+ // Initializing the xDS client upfront (instead of at serving time)
115+ // simplifies the code by eliminating the need for a mutex to protect the
116+ // xdsC and xdsClientClose fields.
117+ newXDSClient := newXDSClient
118+ if s .opts .bootstrapContentsForTesting != nil {
119+ // Bootstrap file contents may be specified as a server option for tests.
120+ newXDSClient = func () (xdsclient.XDSClient , func (), error ) {
121+ return xdsclient .NewWithBootstrapContentsForTesting (s .opts .bootstrapContentsForTesting )
122+ }
123+ }
124+ xdsClient , xdsClientClose , err := newXDSClient ()
125+ if err != nil {
126+ return nil , fmt .Errorf ("xDS client creation failed: %v" , err )
127+ }
128+
129+ // Validate the bootstrap configuration for server specific fields.
130+
131+ // Listener resource name template is mandatory on the server side.
132+ cfg := xdsClient .BootstrapConfig ()
133+ if cfg .ServerListenerResourceNameTemplate == "" {
134+ xdsClientClose ()
135+ return nil , errors .New ("missing server_listener_resource_name_template in the bootstrap configuration" )
136+ }
137+
138+ // If xds credentials were specified by the user, but bootstrap configs do
139+ // not contain any certificate provider configuration, it is better to fail
140+ // right now rather than failing when attempting to create certificate
141+ // providers after receiving an LDS response with security configuration.
142+ if s .xdsCredsInUse {
143+ if len (cfg .CertProviderConfigs ) == 0 {
144+ xdsClientClose ()
145+ return nil , fmt .Errorf ("xds credentials are passed to the user, but certificate_providers config is missing in the bootstrap configuration" )
146+ }
147+ }
148+ s .xdsC = xdsClient
149+ s .xdsClientClose = xdsClientClose
150+
151+ s .logger = internalgrpclog .NewPrefixLogger (logger , fmt .Sprintf (serverPrefix , s ))
152+ s .logger .Infof ("Created xds.GRPCServer" )
122153 s .logger .Infof ("xDS credentials in use: %v" , s .xdsCredsInUse )
123- return s
154+
155+ return s , nil
124156}
125157
126158// handleServerOptions iterates through the list of server options passed in by
@@ -169,35 +201,6 @@ func (s *GRPCServer) GetServiceInfo() map[string]grpc.ServiceInfo {
169201 return s .gs .GetServiceInfo ()
170202}
171203
172- // initXDSClient creates a new xdsClient if there is no existing one available.
173- func (s * GRPCServer ) initXDSClient () error {
174- s .clientMu .Lock ()
175- defer s .clientMu .Unlock ()
176- if s .quit .HasFired () {
177- return grpc .ErrServerStopped
178- }
179-
180- if s .xdsC != nil {
181- return nil
182- }
183-
184- newXDSClient := newXDSClient
185- if s .opts .bootstrapContentsForTesting != nil {
186- // Bootstrap file contents may be specified as a server option for tests.
187- newXDSClient = func () (xdsclient.XDSClient , func (), error ) {
188- return xdsclient .NewWithBootstrapContentsForTesting (s .opts .bootstrapContentsForTesting )
189- }
190- }
191-
192- client , close , err := newXDSClient ()
193- if err != nil {
194- return fmt .Errorf ("xds: failed to create xds-client: %v" , err )
195- }
196- s .xdsC = client
197- s .xdsClientClose = close
198- return nil
199- }
200-
201204// Serve gets the underlying gRPC server to accept incoming connections on the
202205// listener lis, which is expected to be listening on a TCP port.
203206//
@@ -211,35 +214,16 @@ func (s *GRPCServer) Serve(lis net.Listener) error {
211214 return fmt .Errorf ("xds: GRPCServer expects listener to return a net.TCPAddr. Got %T" , lis .Addr ())
212215 }
213216
214- // If this is the first time Serve() is being called, we need to initialize
215- // our xdsClient. If not, we can use the existing one.
216- if err := s .initXDSClient (); err != nil {
217- return err
218- }
219- cfg := s .xdsC .BootstrapConfig ()
220- if cfg == nil {
221- return errors .New ("bootstrap configuration is empty" )
222- }
223-
224- // If xds credentials were specified by the user, but bootstrap configs do
225- // not contain any certificate provider configuration, it is better to fail
226- // right now rather than failing when attempting to create certificate
227- // providers after receiving an LDS response with security configuration.
228- if s .xdsCredsInUse {
229- if len (cfg .CertProviderConfigs ) == 0 {
230- return errors .New ("xds: certificate_providers config missing in bootstrap file" )
231- }
217+ if s .quit .HasFired () {
218+ return grpc .ErrServerStopped
232219 }
233220
234221 // The server listener resource name template from the bootstrap
235222 // configuration contains a template for the name of the Listener resource
236223 // to subscribe to for a gRPC server. If the token `%s` is present in the
237224 // string, it will be replaced with the server's listening "IP:port" (e.g.,
238- // "0.0.0.0:8080", "[::]:8080"). The absence of a template will be treated
239- // as an error since we do not have any default value for this.
240- if cfg .ServerListenerResourceNameTemplate == "" {
241- return errors .New ("missing server_listener_resource_name_template in the bootstrap configuration" )
242- }
225+ // "0.0.0.0:8080", "[::]:8080").
226+ cfg := s .xdsC .BootstrapConfig ()
243227 name := bootstrap .PopulateResourceTemplate (cfg .ServerListenerResourceNameTemplate , lis .Addr ().String ())
244228
245229 modeUpdateCh := buffer .NewUnbounded ()
@@ -335,8 +319,6 @@ func (s *GRPCServer) handleServingModeChanges(updateCh *buffer.Unbounded) {
335319// corresponding pending RPCs on the client side will get notified by connection
336320// errors.
337321func (s * GRPCServer ) Stop () {
338- s .clientMu .Lock ()
339- defer s .clientMu .Unlock ()
340322 s .quit .Fire ()
341323 s .gs .Stop ()
342324 if s .xdsC != nil {
@@ -348,8 +330,6 @@ func (s *GRPCServer) Stop() {
348330// from accepting new connections and RPCs and blocks until all the pending RPCs
349331// are finished.
350332func (s * GRPCServer ) GracefulStop () {
351- s .clientMu .Lock ()
352- defer s .clientMu .Unlock ()
353333 s .quit .Fire ()
354334 s .gs .GracefulStop ()
355335 if s .xdsC != nil {
0 commit comments