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 }