github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/googledirectpath/googlec2p.go (about) 1 /* 2 * 3 * Copyright 2021 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 googledirectpath implements a resolver that configures xds to make 20 // cloud to prod directpath connection. 21 // 22 // It's a combo of DNS and xDS resolvers. It delegates to DNS if 23 // - not on GCE, or 24 // - xDS bootstrap env var is set (so this client needs to do normal xDS, not 25 // direct path, and clients with this scheme is not part of the xDS mesh). 26 package googledirectpath 27 28 import ( 29 "fmt" 30 "time" 31 32 grpc "github.com/hxx258456/ccgo/grpc" 33 "github.com/hxx258456/ccgo/grpc/credentials/google" 34 "github.com/hxx258456/ccgo/grpc/grpclog" 35 "github.com/hxx258456/ccgo/grpc/internal/envconfig" 36 "github.com/hxx258456/ccgo/grpc/internal/googlecloud" 37 internalgrpclog "github.com/hxx258456/ccgo/grpc/internal/grpclog" 38 "github.com/hxx258456/ccgo/grpc/internal/grpcrand" 39 "github.com/hxx258456/ccgo/grpc/resolver" 40 _ "github.com/hxx258456/ccgo/grpc/xds" // To register xds resolvers and balancers. 41 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient" 42 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/bootstrap" 43 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource/version" 44 "google.golang.org/protobuf/types/known/structpb" 45 46 v3corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/core/v3" 47 ) 48 49 const ( 50 c2pScheme = "google-c2p-experimental" 51 52 tdURL = "dns:///directpath-pa.googleapis.com" 53 httpReqTimeout = 10 * time.Second 54 zoneURL = "http://metadata.google.internal/computeMetadata/v1/instance/zone" 55 ipv6URL = "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ipv6s" 56 57 gRPCUserAgentName = "gRPC Go" 58 clientFeatureNoOverprovisioning = "envoy.lb.does_not_support_overprovisioning" 59 ipv6CapableMetadataName = "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE" 60 61 logPrefix = "[google-c2p-resolver]" 62 63 dnsName, xdsName = "dns", "xds" 64 ) 65 66 // For overriding in unittests. 67 var ( 68 onGCE = googlecloud.OnGCE 69 70 newClientWithConfig = func(config *bootstrap.Config) (xdsclient.XDSClient, error) { 71 return xdsclient.NewWithConfig(config) 72 } 73 74 logger = internalgrpclog.NewPrefixLogger(grpclog.Component("directpath"), logPrefix) 75 ) 76 77 func init() { 78 resolver.Register(c2pResolverBuilder{}) 79 } 80 81 type c2pResolverBuilder struct{} 82 83 func (c2pResolverBuilder) Build(t resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { 84 if !runDirectPath() { 85 // If not xDS, fallback to DNS. 86 t.Scheme = dnsName 87 return resolver.Get(dnsName).Build(t, cc, opts) 88 } 89 90 // Note that the following calls to getZone() and getIPv6Capable() does I/O, 91 // and has 10 seconds timeout each. 92 // 93 // This should be fine in most of the cases. In certain error cases, this 94 // could block Dial() for up to 10 seconds (each blocking call has its own 95 // goroutine). 96 zoneCh, ipv6CapableCh := make(chan string), make(chan bool) 97 go func() { zoneCh <- getZone(httpReqTimeout) }() 98 go func() { ipv6CapableCh <- getIPv6Capable(httpReqTimeout) }() 99 100 balancerName := envconfig.C2PResolverTestOnlyTrafficDirectorURI 101 if balancerName == "" { 102 balancerName = tdURL 103 } 104 config := &bootstrap.Config{ 105 XDSServer: &bootstrap.ServerConfig{ 106 ServerURI: balancerName, 107 Creds: grpc.WithCredentialsBundle(google.NewDefaultCredentials()), 108 TransportAPI: version.TransportV3, 109 NodeProto: newNode(<-zoneCh, <-ipv6CapableCh), 110 }, 111 ClientDefaultListenerResourceNameTemplate: "%s", 112 } 113 114 // Create singleton xds client with this config. The xds client will be 115 // used by the xds resolver later. 116 xdsC, err := newClientWithConfig(config) 117 if err != nil { 118 return nil, fmt.Errorf("failed to start xDS client: %v", err) 119 } 120 121 // Create and return an xDS resolver. 122 t.Scheme = xdsName 123 xdsR, err := resolver.Get(xdsName).Build(t, cc, opts) 124 if err != nil { 125 xdsC.Close() 126 return nil, err 127 } 128 return &c2pResolver{ 129 Resolver: xdsR, 130 client: xdsC, 131 }, nil 132 } 133 134 func (c2pResolverBuilder) Scheme() string { 135 return c2pScheme 136 } 137 138 type c2pResolver struct { 139 resolver.Resolver 140 client xdsclient.XDSClient 141 } 142 143 func (r *c2pResolver) Close() { 144 r.Resolver.Close() 145 r.client.Close() 146 } 147 148 var ipv6EnabledMetadata = &structpb.Struct{ 149 Fields: map[string]*structpb.Value{ 150 ipv6CapableMetadataName: structpb.NewBoolValue(true), 151 }, 152 } 153 154 var id = fmt.Sprintf("C2P-%d", grpcrand.Int()) 155 156 // newNode makes a copy of defaultNode, and populate it's Metadata and 157 // Locality fields. 158 func newNode(zone string, ipv6Capable bool) *v3corepb.Node { 159 ret := &v3corepb.Node{ 160 // Not all required fields are set in defaultNote. Metadata will be set 161 // if ipv6 is enabled. Locality will be set to the value from metadata. 162 Id: id, 163 UserAgentName: gRPCUserAgentName, 164 UserAgentVersionType: &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, 165 ClientFeatures: []string{clientFeatureNoOverprovisioning}, 166 } 167 ret.Locality = &v3corepb.Locality{Zone: zone} 168 if ipv6Capable { 169 ret.Metadata = ipv6EnabledMetadata 170 } 171 return ret 172 } 173 174 // runDirectPath returns whether this resolver should use direct path. 175 // 176 // direct path is enabled if this client is running on GCE, and the normal xDS 177 // is not used (bootstrap env vars are not set). 178 func runDirectPath() bool { 179 return envconfig.XDSBootstrapFileName == "" && envconfig.XDSBootstrapFileContent == "" && onGCE() 180 }