google.golang.org/grpc@v1.72.2/xds/internal/xdsclient/transport/grpctransport/grpctransport.go (about) 1 /* 2 * 3 * Copyright 2024 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 // Package grpctransport provides an implementation of the transport interface 19 // using gRPC. 20 package grpctransport 21 22 import ( 23 "context" 24 "fmt" 25 "time" 26 27 "google.golang.org/grpc" 28 "google.golang.org/grpc/keepalive" 29 "google.golang.org/grpc/xds/internal/xdsclient/internal" 30 "google.golang.org/grpc/xds/internal/xdsclient/transport" 31 32 v3adsgrpc "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 33 v3adspb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 34 v3lrsgrpc "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" 35 v3lrspb "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" 36 ) 37 38 func init() { 39 internal.GRPCNewClient = grpc.NewClient 40 internal.NewADSStream = func(ctx context.Context, cc *grpc.ClientConn) (v3adsgrpc.AggregatedDiscoveryService_StreamAggregatedResourcesClient, error) { 41 return v3adsgrpc.NewAggregatedDiscoveryServiceClient(cc).StreamAggregatedResources(ctx) 42 } 43 } 44 45 // Builder provides a way to build a gRPC-based transport to an xDS server. 46 type Builder struct{} 47 48 // Build creates a new gRPC-based transport to an xDS server using the provided 49 // options. This involves creating a grpc.ClientConn to the server identified by 50 // the server URI in the provided options. 51 func (b *Builder) Build(opts transport.BuildOptions) (transport.Transport, error) { 52 if opts.ServerConfig == nil { 53 return nil, fmt.Errorf("ServerConfig field in opts cannot be nil") 54 } 55 56 // NOTE: The bootstrap package ensures that the server_uri and credentials 57 // inside the server config are always populated. If we end up using a 58 // different type in BuildOptions to specify the server configuration, we 59 // must ensure that those fields are not empty before proceeding. 60 61 // Dial the xDS management server with dial options specified by the server 62 // configuration and a static keepalive configuration that is common across 63 // gRPC language implementations. 64 kpCfg := grpc.WithKeepaliveParams(keepalive.ClientParameters{ 65 Time: 5 * time.Minute, 66 Timeout: 20 * time.Second, 67 }) 68 dopts := append(opts.ServerConfig.DialOptions(), kpCfg) 69 dialer := internal.GRPCNewClient.(func(string, ...grpc.DialOption) (*grpc.ClientConn, error)) 70 cc, err := dialer(opts.ServerConfig.ServerURI(), dopts...) 71 if err != nil { 72 // An error from a non-blocking dial indicates something serious. 73 return nil, fmt.Errorf("failed to create a grpc transport to the management server %q: %v", opts.ServerConfig.ServerURI(), err) 74 } 75 cc.Connect() 76 77 return &grpcTransport{cc: cc}, nil 78 } 79 80 type grpcTransport struct { 81 cc *grpc.ClientConn 82 } 83 84 func (g *grpcTransport) CreateStreamingCall(ctx context.Context, method string) (transport.StreamingCall, error) { 85 switch method { 86 case v3adsgrpc.AggregatedDiscoveryService_StreamAggregatedResources_FullMethodName: 87 return g.newADSStreamingCall(ctx) 88 case v3lrsgrpc.LoadReportingService_StreamLoadStats_FullMethodName: 89 return g.newLRSStreamingCall(ctx) 90 default: 91 return nil, fmt.Errorf("unsupported method: %v", method) 92 } 93 } 94 95 func (g *grpcTransport) newADSStreamingCall(ctx context.Context) (transport.StreamingCall, error) { 96 newStream := internal.NewADSStream.(func(context.Context, *grpc.ClientConn) (v3adsgrpc.AggregatedDiscoveryService_StreamAggregatedResourcesClient, error)) 97 stream, err := newStream(ctx, g.cc) 98 if err != nil { 99 return nil, fmt.Errorf("failed to create an ADS stream: %v", err) 100 } 101 return &adsStream{stream: stream}, nil 102 } 103 104 func (g *grpcTransport) newLRSStreamingCall(ctx context.Context) (transport.StreamingCall, error) { 105 stream, err := v3lrsgrpc.NewLoadReportingServiceClient(g.cc).StreamLoadStats(ctx) 106 if err != nil { 107 return nil, fmt.Errorf("failed to create an LRS stream: %v", err) 108 } 109 return &lrsStream{stream: stream}, nil 110 } 111 112 func (g *grpcTransport) Close() error { 113 return g.cc.Close() 114 } 115 116 type adsStream struct { 117 stream v3adsgrpc.AggregatedDiscoveryService_StreamAggregatedResourcesClient 118 } 119 120 func (a *adsStream) Send(msg any) error { 121 return a.stream.Send(msg.(*v3adspb.DiscoveryRequest)) 122 } 123 124 func (a *adsStream) Recv() (any, error) { 125 return a.stream.Recv() 126 } 127 128 type lrsStream struct { 129 stream v3lrsgrpc.LoadReportingService_StreamLoadStatsClient 130 } 131 132 func (l *lrsStream) Send(msg any) error { 133 return l.stream.Send(msg.(*v3lrspb.LoadStatsRequest)) 134 } 135 136 func (l *lrsStream) Recv() (any, error) { 137 return l.stream.Recv() 138 }