gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/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 "gitee.com/ks-custle/core-gm/grpc"
    33  	"gitee.com/ks-custle/core-gm/grpc/credentials/google"
    34  	"gitee.com/ks-custle/core-gm/grpc/grpclog"
    35  	"gitee.com/ks-custle/core-gm/grpc/internal/envconfig"
    36  	"gitee.com/ks-custle/core-gm/grpc/internal/googlecloud"
    37  	internalgrpclog "gitee.com/ks-custle/core-gm/grpc/internal/grpclog"
    38  	"gitee.com/ks-custle/core-gm/grpc/internal/grpcrand"
    39  	"gitee.com/ks-custle/core-gm/grpc/resolver"
    40  	_ "gitee.com/ks-custle/core-gm/grpc/xds" // To register xds resolvers and balancers.
    41  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient"
    42  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/bootstrap"
    43  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource/version"
    44  	"google.golang.org/protobuf/types/known/structpb"
    45  
    46  	v3corepb "gitee.com/ks-custle/core-gm/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 is deprecated, use URL.Scheme instead.
    87  		//t.Scheme = dnsName
    88  		t.URL.Scheme = dnsName
    89  		return resolver.Get(dnsName).Build(t, cc, opts)
    90  	}
    91  
    92  	// Note that the following calls to getZone() and getIPv6Capable() does I/O,
    93  	// and has 10 seconds timeout each.
    94  	//
    95  	// This should be fine in most of the cases. In certain error cases, this
    96  	// could block Dial() for up to 10 seconds (each blocking call has its own
    97  	// goroutine).
    98  	zoneCh, ipv6CapableCh := make(chan string), make(chan bool)
    99  	go func() { zoneCh <- getZone(httpReqTimeout) }()
   100  	go func() { ipv6CapableCh <- getIPv6Capable(httpReqTimeout) }()
   101  
   102  	balancerName := envconfig.C2PResolverTestOnlyTrafficDirectorURI
   103  	if balancerName == "" {
   104  		balancerName = tdURL
   105  	}
   106  	config := &bootstrap.Config{
   107  		XDSServer: &bootstrap.ServerConfig{
   108  			ServerURI:    balancerName,
   109  			Creds:        grpc.WithCredentialsBundle(google.NewDefaultCredentials()),
   110  			TransportAPI: version.TransportV3,
   111  			NodeProto:    newNode(<-zoneCh, <-ipv6CapableCh),
   112  		},
   113  		ClientDefaultListenerResourceNameTemplate: "%s",
   114  	}
   115  
   116  	// Create singleton xds client with this config. The xds client will be
   117  	// used by the xds resolver later.
   118  	xdsC, err := newClientWithConfig(config)
   119  	if err != nil {
   120  		return nil, fmt.Errorf("failed to start xDS client: %v", err)
   121  	}
   122  
   123  	// Create and return an xDS resolver.
   124  	// t.Scheme is deprecated, use URL.Scheme instead.
   125  	//t.Scheme = xdsName
   126  	t.URL.Scheme = xdsName
   127  	xdsR, err := resolver.Get(xdsName).Build(t, cc, opts)
   128  	if err != nil {
   129  		xdsC.Close()
   130  		return nil, err
   131  	}
   132  	return &c2pResolver{
   133  		Resolver: xdsR,
   134  		client:   xdsC,
   135  	}, nil
   136  }
   137  
   138  func (c2pResolverBuilder) Scheme() string {
   139  	return c2pScheme
   140  }
   141  
   142  type c2pResolver struct {
   143  	resolver.Resolver
   144  	client xdsclient.XDSClient
   145  }
   146  
   147  func (r *c2pResolver) Close() {
   148  	r.Resolver.Close()
   149  	r.client.Close()
   150  }
   151  
   152  var ipv6EnabledMetadata = &structpb.Struct{
   153  	Fields: map[string]*structpb.Value{
   154  		ipv6CapableMetadataName: structpb.NewBoolValue(true),
   155  	},
   156  }
   157  
   158  var id = fmt.Sprintf("C2P-%d", grpcrand.Int())
   159  
   160  // newNode makes a copy of defaultNode, and populate it's Metadata and
   161  // Locality fields.
   162  func newNode(zone string, ipv6Capable bool) *v3corepb.Node {
   163  	ret := &v3corepb.Node{
   164  		// Not all required fields are set in defaultNote. Metadata will be set
   165  		// if ipv6 is enabled. Locality will be set to the value from metadata.
   166  		Id:                   id,
   167  		UserAgentName:        gRPCUserAgentName,
   168  		UserAgentVersionType: &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version},
   169  		ClientFeatures:       []string{clientFeatureNoOverprovisioning},
   170  	}
   171  	ret.Locality = &v3corepb.Locality{Zone: zone}
   172  	if ipv6Capable {
   173  		ret.Metadata = ipv6EnabledMetadata
   174  	}
   175  	return ret
   176  }
   177  
   178  // runDirectPath returns whether this resolver should use direct path.
   179  //
   180  // direct path is enabled if this client is running on GCE, and the normal xDS
   181  // is not used (bootstrap env vars are not set).
   182  func runDirectPath() bool {
   183  	return envconfig.XDSBootstrapFileName == "" && envconfig.XDSBootstrapFileContent == "" && onGCE()
   184  }