gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/server.go (about)

     1  /*
     2   *
     3   * Copyright 2020 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package xds
    20  
    21  import (
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"net"
    26  	"sync"
    27  
    28  	grpc "gitee.com/ks-custle/core-gm/grpc"
    29  	"gitee.com/ks-custle/core-gm/grpc/codes"
    30  	"gitee.com/ks-custle/core-gm/grpc/connectivity"
    31  	"gitee.com/ks-custle/core-gm/grpc/credentials"
    32  	"gitee.com/ks-custle/core-gm/grpc/grpclog"
    33  	"gitee.com/ks-custle/core-gm/grpc/internal"
    34  	"gitee.com/ks-custle/core-gm/grpc/internal/buffer"
    35  	"gitee.com/ks-custle/core-gm/grpc/internal/envconfig"
    36  	internalgrpclog "gitee.com/ks-custle/core-gm/grpc/internal/grpclog"
    37  	"gitee.com/ks-custle/core-gm/grpc/internal/grpcsync"
    38  	iresolver "gitee.com/ks-custle/core-gm/grpc/internal/resolver"
    39  	"gitee.com/ks-custle/core-gm/grpc/internal/transport"
    40  	"gitee.com/ks-custle/core-gm/grpc/metadata"
    41  	"gitee.com/ks-custle/core-gm/grpc/status"
    42  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/server"
    43  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient"
    44  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/bootstrap"
    45  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource"
    46  )
    47  
    48  const serverPrefix = "[xds-server %p] "
    49  
    50  var (
    51  	// These new functions will be overridden in unit tests.
    52  	newXDSClient = func() (xdsclient.XDSClient, error) {
    53  		return xdsclient.New()
    54  	}
    55  	newGRPCServer = func(opts ...grpc.ServerOption) grpcServer {
    56  		return grpc.NewServer(opts...)
    57  	}
    58  
    59  	grpcGetServerCreds    = internal.GetServerCredentials.(func(*grpc.Server) credentials.TransportCredentials)
    60  	drainServerTransports = internal.DrainServerTransports.(func(*grpc.Server, string))
    61  	logger                = grpclog.Component("xds")
    62  )
    63  
    64  func prefixLogger(p *GRPCServer) *internalgrpclog.PrefixLogger {
    65  	return internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf(serverPrefix, p))
    66  }
    67  
    68  // grpcServer contains methods from grpc.Server which are used by the
    69  // GRPCServer type here. This is useful for overriding in unit tests.
    70  type grpcServer interface {
    71  	RegisterService(*grpc.ServiceDesc, interface{})
    72  	Serve(net.Listener) error
    73  	Stop()
    74  	GracefulStop()
    75  	GetServiceInfo() map[string]grpc.ServiceInfo
    76  }
    77  
    78  // GRPCServer wraps a gRPC server and provides server-side xDS functionality, by
    79  // communication with a management server using xDS APIs. It implements the
    80  // grpc.ServiceRegistrar interface and can be passed to service registration
    81  // functions in IDL generated code.
    82  type GRPCServer struct {
    83  	gs            grpcServer
    84  	quit          *grpcsync.Event
    85  	logger        *internalgrpclog.PrefixLogger
    86  	xdsCredsInUse bool
    87  	opts          *serverOptions
    88  
    89  	// clientMu is used only in initXDSClient(), which is called at the
    90  	// beginning of Serve(), where we have to decide if we have to create a
    91  	// client or use an existing one.
    92  	clientMu sync.Mutex
    93  	xdsC     xdsclient.XDSClient
    94  }
    95  
    96  // NewGRPCServer creates an xDS-enabled gRPC server using the passed in opts.
    97  // The underlying gRPC server has no service registered and has not started to
    98  // accept requests yet.
    99  func NewGRPCServer(opts ...grpc.ServerOption) *GRPCServer {
   100  	newOpts := []grpc.ServerOption{
   101  		grpc.ChainUnaryInterceptor(xdsUnaryInterceptor),
   102  		grpc.ChainStreamInterceptor(xdsStreamInterceptor),
   103  	}
   104  	newOpts = append(newOpts, opts...)
   105  	s := &GRPCServer{
   106  		gs:   newGRPCServer(newOpts...),
   107  		quit: grpcsync.NewEvent(),
   108  		opts: handleServerOptions(opts),
   109  	}
   110  	s.logger = prefixLogger(s)
   111  	s.logger.Infof("Created xds.GRPCServer")
   112  
   113  	// We type assert our underlying gRPC server to the real grpc.Server here
   114  	// before trying to retrieve the configured credentials. This approach
   115  	// avoids performing the same type assertion in the grpc package which
   116  	// provides the implementation for internal.GetServerCredentials, and allows
   117  	// us to use a fake gRPC server in tests.
   118  	if gs, ok := s.gs.(*grpc.Server); ok {
   119  		creds := grpcGetServerCreds(gs)
   120  		if xc, ok := creds.(interface{ UsesXDS() bool }); ok && xc.UsesXDS() {
   121  			s.xdsCredsInUse = true
   122  		}
   123  	}
   124  
   125  	s.logger.Infof("xDS credentials in use: %v", s.xdsCredsInUse)
   126  	return s
   127  }
   128  
   129  // handleServerOptions iterates through the list of server options passed in by
   130  // the user, and handles the xDS server specific options.
   131  func handleServerOptions(opts []grpc.ServerOption) *serverOptions {
   132  	so := &serverOptions{}
   133  	for _, opt := range opts {
   134  		if o, ok := opt.(*serverOption); ok {
   135  			o.apply(so)
   136  		}
   137  	}
   138  	return so
   139  }
   140  
   141  // RegisterService registers a service and its implementation to the underlying
   142  // gRPC server. It is called from the IDL generated code. This must be called
   143  // before invoking Serve.
   144  func (s *GRPCServer) RegisterService(sd *grpc.ServiceDesc, ss interface{}) {
   145  	s.gs.RegisterService(sd, ss)
   146  }
   147  
   148  // GetServiceInfo returns a map from service names to ServiceInfo.
   149  // Service names include the package names, in the form of <package>.<service>.
   150  func (s *GRPCServer) GetServiceInfo() map[string]grpc.ServiceInfo {
   151  	return s.gs.GetServiceInfo()
   152  }
   153  
   154  // initXDSClient creates a new xdsClient if there is no existing one available.
   155  func (s *GRPCServer) initXDSClient() error {
   156  	s.clientMu.Lock()
   157  	defer s.clientMu.Unlock()
   158  
   159  	if s.xdsC != nil {
   160  		return nil
   161  	}
   162  
   163  	newXDSClient := newXDSClient
   164  	if s.opts.bootstrapContents != nil {
   165  		newXDSClient = func() (xdsclient.XDSClient, error) {
   166  			return xdsclient.NewClientWithBootstrapContents(s.opts.bootstrapContents)
   167  		}
   168  	}
   169  	client, err := newXDSClient()
   170  	if err != nil {
   171  		return fmt.Errorf("xds: failed to create xds-client: %v", err)
   172  	}
   173  	s.xdsC = client
   174  	s.logger.Infof("Created an xdsClient")
   175  	return nil
   176  }
   177  
   178  // Serve gets the underlying gRPC server to accept incoming connections on the
   179  // listener lis, which is expected to be listening on a TCP port.
   180  //
   181  // A connection to the management server, to receive xDS configuration, is
   182  // initiated here.
   183  //
   184  // Serve will return a non-nil error unless Stop or GracefulStop is called.
   185  func (s *GRPCServer) Serve(lis net.Listener) error {
   186  	s.logger.Infof("Serve() passed a net.Listener on %s", lis.Addr().String())
   187  	if _, ok := lis.Addr().(*net.TCPAddr); !ok {
   188  		return fmt.Errorf("xds: GRPCServer expects listener to return a net.TCPAddr. Got %T", lis.Addr())
   189  	}
   190  
   191  	// If this is the first time Serve() is being called, we need to initialize
   192  	// our xdsClient. If not, we can use the existing one.
   193  	if err := s.initXDSClient(); err != nil {
   194  		return err
   195  	}
   196  	cfg := s.xdsC.BootstrapConfig()
   197  	if cfg == nil {
   198  		return errors.New("bootstrap configuration is empty")
   199  	}
   200  
   201  	// If xds credentials were specified by the user, but bootstrap configs do
   202  	// not contain any certificate provider configuration, it is better to fail
   203  	// right now rather than failing when attempting to create certificate
   204  	// providers after receiving an LDS response with security configuration.
   205  	if s.xdsCredsInUse {
   206  		if len(cfg.CertProviderConfigs) == 0 {
   207  			return errors.New("xds: certificate_providers config missing in bootstrap file")
   208  		}
   209  	}
   210  
   211  	// The server listener resource name template from the bootstrap
   212  	// configuration contains a template for the name of the Listener resource
   213  	// to subscribe to for a gRPC server. If the token `%s` is present in the
   214  	// string, it will be replaced with the server's listening "IP:port" (e.g.,
   215  	// "0.0.0.0:8080", "[::]:8080"). The absence of a template will be treated
   216  	// as an error since we do not have any default value for this.
   217  	if cfg.ServerListenerResourceNameTemplate == "" {
   218  		return errors.New("missing server_listener_resource_name_template in the bootstrap configuration")
   219  	}
   220  	name := bootstrap.PopulateResourceTemplate(cfg.ServerListenerResourceNameTemplate, lis.Addr().String())
   221  
   222  	modeUpdateCh := buffer.NewUnbounded()
   223  	go func() {
   224  		s.handleServingModeChanges(modeUpdateCh)
   225  	}()
   226  
   227  	// Create a listenerWrapper which handles all functionality required by
   228  	// this particular instance of Serve().
   229  	lw, goodUpdateCh := server.NewListenerWrapper(server.ListenerWrapperParams{
   230  		Listener:             lis,
   231  		ListenerResourceName: name,
   232  		XDSCredsInUse:        s.xdsCredsInUse,
   233  		XDSClient:            s.xdsC,
   234  		ModeCallback: func(addr net.Addr, mode connectivity.ServingMode, err error) {
   235  			modeUpdateCh.Put(&modeChangeArgs{
   236  				addr: addr,
   237  				mode: mode,
   238  				err:  err,
   239  			})
   240  		},
   241  		DrainCallback: func(addr net.Addr) {
   242  			if gs, ok := s.gs.(*grpc.Server); ok {
   243  				drainServerTransports(gs, addr.String())
   244  			}
   245  		},
   246  	})
   247  
   248  	// Block until a good LDS response is received or the server is stopped.
   249  	select {
   250  	case <-s.quit.Done():
   251  		// Since the listener has not yet been handed over to gs.Serve(), we
   252  		// need to explicitly close the listener. Cancellation of the xDS watch
   253  		// is handled by the listenerWrapper.
   254  		lw.Close()
   255  		return nil
   256  	case <-goodUpdateCh:
   257  	}
   258  	return s.gs.Serve(lw)
   259  }
   260  
   261  // modeChangeArgs wraps argument required for invoking mode change callback.
   262  type modeChangeArgs struct {
   263  	addr net.Addr
   264  	mode connectivity.ServingMode
   265  	err  error
   266  }
   267  
   268  // handleServingModeChanges runs as a separate goroutine, spawned from Serve().
   269  // It reads a channel on to which mode change arguments are pushed, and in turn
   270  // invokes the user registered callback. It also calls an internal method on the
   271  // underlying grpc.Server to gracefully close existing connections, if the
   272  // listener moved to a "not-serving" mode.
   273  func (s *GRPCServer) handleServingModeChanges(updateCh *buffer.Unbounded) {
   274  	for {
   275  		select {
   276  		case <-s.quit.Done():
   277  			return
   278  		case u := <-updateCh.Get():
   279  			updateCh.Load()
   280  			args := u.(*modeChangeArgs)
   281  			if args.mode == connectivity.ServingModeNotServing {
   282  				// We type assert our underlying gRPC server to the real
   283  				// grpc.Server here before trying to initiate the drain
   284  				// operation. This approach avoids performing the same type
   285  				// assertion in the grpc package which provides the
   286  				// implementation for internal.GetServerCredentials, and allows
   287  				// us to use a fake gRPC server in tests.
   288  				if gs, ok := s.gs.(*grpc.Server); ok {
   289  					drainServerTransports(gs, args.addr.String())
   290  				}
   291  			}
   292  			if s.opts.modeCallback != nil {
   293  				s.opts.modeCallback(args.addr, ServingModeChangeArgs{
   294  					Mode: args.mode,
   295  					Err:  args.err,
   296  				})
   297  			}
   298  		}
   299  	}
   300  }
   301  
   302  // Stop stops the underlying gRPC server. It immediately closes all open
   303  // connections. It cancels all active RPCs on the server side and the
   304  // corresponding pending RPCs on the client side will get notified by connection
   305  // errors.
   306  func (s *GRPCServer) Stop() {
   307  	s.quit.Fire()
   308  	s.gs.Stop()
   309  	if s.xdsC != nil {
   310  		s.xdsC.Close()
   311  	}
   312  }
   313  
   314  // GracefulStop stops the underlying gRPC server gracefully. It stops the server
   315  // from accepting new connections and RPCs and blocks until all the pending RPCs
   316  // are finished.
   317  func (s *GRPCServer) GracefulStop() {
   318  	s.quit.Fire()
   319  	s.gs.GracefulStop()
   320  	if s.xdsC != nil {
   321  		s.xdsC.Close()
   322  	}
   323  }
   324  
   325  // routeAndProcess routes the incoming RPC to a configured route in the route
   326  // table and also processes the RPC by running the incoming RPC through any HTTP
   327  // Filters configured.
   328  func routeAndProcess(ctx context.Context) error {
   329  	conn := transport.GetConnection(ctx)
   330  	cw, ok := conn.(interface {
   331  		VirtualHosts() []xdsresource.VirtualHostWithInterceptors
   332  	})
   333  	if !ok {
   334  		return errors.New("missing virtual hosts in incoming context")
   335  	}
   336  	mn, ok := grpc.Method(ctx)
   337  	if !ok {
   338  		return errors.New("missing method name in incoming context")
   339  	}
   340  	md, ok := metadata.FromIncomingContext(ctx)
   341  	if !ok {
   342  		return errors.New("missing metadata in incoming context")
   343  	}
   344  	// A41 added logic to the core grpc implementation to guarantee that once
   345  	// the RPC gets to this point, there will be a single, unambiguous authority
   346  	// present in the header map.
   347  	authority := md.Get(":authority")
   348  	vh := xdsresource.FindBestMatchingVirtualHostServer(authority[0], cw.VirtualHosts())
   349  	if vh == nil {
   350  		return status.Error(codes.Unavailable, "the incoming RPC did not match a configured Virtual Host")
   351  	}
   352  
   353  	var rwi *xdsresource.RouteWithInterceptors
   354  	rpcInfo := iresolver.RPCInfo{
   355  		Context: ctx,
   356  		Method:  mn,
   357  	}
   358  	for _, r := range vh.Routes {
   359  		if r.M.Match(rpcInfo) {
   360  			// "NonForwardingAction is expected for all Routes used on server-side; a route with an inappropriate action causes
   361  			// RPCs matching that route to fail with UNAVAILABLE." - A36
   362  			if r.ActionType != xdsresource.RouteActionNonForwardingAction {
   363  				return status.Error(codes.Unavailable, "the incoming RPC matched to a route that was not of action type non forwarding")
   364  			}
   365  			rwi = &r
   366  			break
   367  		}
   368  	}
   369  	if rwi == nil {
   370  		return status.Error(codes.Unavailable, "the incoming RPC did not match a configured Route")
   371  	}
   372  	for _, interceptor := range rwi.Interceptors {
   373  		if err := interceptor.AllowRPC(ctx); err != nil {
   374  			return status.Errorf(codes.PermissionDenied, "Incoming RPC is not allowed: %v", err)
   375  		}
   376  	}
   377  	return nil
   378  }
   379  
   380  // xdsUnaryInterceptor is the unary interceptor added to the gRPC server to
   381  // perform any xDS specific functionality on unary RPCs.
   382  func xdsUnaryInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
   383  	if envconfig.XDSRBAC {
   384  		if err := routeAndProcess(ctx); err != nil {
   385  			return nil, err
   386  		}
   387  	}
   388  	return handler(ctx, req)
   389  }
   390  
   391  // xdsStreamInterceptor is the stream interceptor added to the gRPC server to
   392  // perform any xDS specific functionality on streaming RPCs.
   393  func xdsStreamInterceptor(srv interface{}, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
   394  	if envconfig.XDSRBAC {
   395  		if err := routeAndProcess(ss.Context()); err != nil {
   396  			return err
   397  		}
   398  	}
   399  	return handler(srv, ss)
   400  }