mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-22 00:16:23 +01:00
179 lines
5.5 KiB
Go
179 lines
5.5 KiB
Go
|
/*
|
||
|
*
|
||
|
* Copyright 2021 gRPC authors.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
// Package googledirectpath implements a resolver that configures xds to make
|
||
|
// cloud to prod directpath connection.
|
||
|
//
|
||
|
// It's a combo of DNS and xDS resolvers. It delegates to DNS if
|
||
|
// - not on GCE, or
|
||
|
// - xDS bootstrap env var is set (so this client needs to do normal xDS, not
|
||
|
// direct path, and clients with this scheme is not part of the xDS mesh).
|
||
|
package googledirectpath
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"time"
|
||
|
|
||
|
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||
|
"google.golang.org/grpc"
|
||
|
"google.golang.org/grpc/credentials/google"
|
||
|
"google.golang.org/grpc/grpclog"
|
||
|
"google.golang.org/grpc/internal/googlecloud"
|
||
|
internalgrpclog "google.golang.org/grpc/internal/grpclog"
|
||
|
"google.golang.org/grpc/internal/grpcrand"
|
||
|
"google.golang.org/grpc/internal/xds/env"
|
||
|
"google.golang.org/grpc/resolver"
|
||
|
_ "google.golang.org/grpc/xds" // To register xds resolvers and balancers.
|
||
|
"google.golang.org/grpc/xds/internal/version"
|
||
|
"google.golang.org/grpc/xds/internal/xdsclient"
|
||
|
"google.golang.org/grpc/xds/internal/xdsclient/bootstrap"
|
||
|
"google.golang.org/protobuf/types/known/structpb"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
c2pScheme = "google-c2p"
|
||
|
|
||
|
tdURL = "directpath-pa.googleapis.com"
|
||
|
httpReqTimeout = 10 * time.Second
|
||
|
zoneURL = "http://metadata.google.internal/computeMetadata/v1/instance/zone"
|
||
|
ipv6URL = "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ipv6s"
|
||
|
|
||
|
gRPCUserAgentName = "gRPC Go"
|
||
|
clientFeatureNoOverprovisioning = "envoy.lb.does_not_support_overprovisioning"
|
||
|
ipv6CapableMetadataName = "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE"
|
||
|
|
||
|
logPrefix = "[google-c2p-resolver]"
|
||
|
|
||
|
dnsName, xdsName = "dns", "xds"
|
||
|
)
|
||
|
|
||
|
// For overriding in unittests.
|
||
|
var (
|
||
|
onGCE = googlecloud.OnGCE
|
||
|
|
||
|
newClientWithConfig = func(config *bootstrap.Config) (xdsclient.XDSClient, error) {
|
||
|
return xdsclient.NewWithConfig(config)
|
||
|
}
|
||
|
|
||
|
logger = internalgrpclog.NewPrefixLogger(grpclog.Component("directpath"), logPrefix)
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
if env.C2PResolverSupport {
|
||
|
resolver.Register(c2pResolverBuilder{})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type c2pResolverBuilder struct{}
|
||
|
|
||
|
func (c2pResolverBuilder) Build(t resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
|
||
|
if !runDirectPath() {
|
||
|
// If not xDS, fallback to DNS.
|
||
|
t.Scheme = dnsName
|
||
|
return resolver.Get(dnsName).Build(t, cc, opts)
|
||
|
}
|
||
|
|
||
|
// Note that the following calls to getZone() and getIPv6Capable() does I/O,
|
||
|
// and has 10 seconds timeout each.
|
||
|
//
|
||
|
// This should be fine in most of the cases. In certain error cases, this
|
||
|
// could block Dial() for up to 10 seconds (each blocking call has its own
|
||
|
// goroutine).
|
||
|
zoneCh, ipv6CapableCh := make(chan string), make(chan bool)
|
||
|
go func() { zoneCh <- getZone(httpReqTimeout) }()
|
||
|
go func() { ipv6CapableCh <- getIPv6Capable(httpReqTimeout) }()
|
||
|
|
||
|
balancerName := env.C2PResolverTestOnlyTrafficDirectorURI
|
||
|
if balancerName == "" {
|
||
|
balancerName = tdURL
|
||
|
}
|
||
|
config := &bootstrap.Config{
|
||
|
BalancerName: balancerName,
|
||
|
Creds: grpc.WithCredentialsBundle(google.NewDefaultCredentials()),
|
||
|
TransportAPI: version.TransportV3,
|
||
|
NodeProto: newNode(<-zoneCh, <-ipv6CapableCh),
|
||
|
}
|
||
|
|
||
|
// Create singleton xds client with this config. The xds client will be
|
||
|
// used by the xds resolver later.
|
||
|
xdsC, err := newClientWithConfig(config)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("failed to start xDS client: %v", err)
|
||
|
}
|
||
|
|
||
|
// Create and return an xDS resolver.
|
||
|
t.Scheme = xdsName
|
||
|
xdsR, err := resolver.Get(xdsName).Build(t, cc, opts)
|
||
|
if err != nil {
|
||
|
xdsC.Close()
|
||
|
return nil, err
|
||
|
}
|
||
|
return &c2pResolver{
|
||
|
Resolver: xdsR,
|
||
|
client: xdsC,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (c2pResolverBuilder) Scheme() string {
|
||
|
return c2pScheme
|
||
|
}
|
||
|
|
||
|
type c2pResolver struct {
|
||
|
resolver.Resolver
|
||
|
client xdsclient.XDSClient
|
||
|
}
|
||
|
|
||
|
func (r *c2pResolver) Close() {
|
||
|
r.Resolver.Close()
|
||
|
r.client.Close()
|
||
|
}
|
||
|
|
||
|
var ipv6EnabledMetadata = &structpb.Struct{
|
||
|
Fields: map[string]*structpb.Value{
|
||
|
ipv6CapableMetadataName: structpb.NewBoolValue(true),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
var id = fmt.Sprintf("C2P-%d", grpcrand.Int())
|
||
|
|
||
|
// newNode makes a copy of defaultNode, and populate it's Metadata and
|
||
|
// Locality fields.
|
||
|
func newNode(zone string, ipv6Capable bool) *v3corepb.Node {
|
||
|
ret := &v3corepb.Node{
|
||
|
// Not all required fields are set in defaultNote. Metadata will be set
|
||
|
// if ipv6 is enabled. Locality will be set to the value from metadata.
|
||
|
Id: id,
|
||
|
UserAgentName: gRPCUserAgentName,
|
||
|
UserAgentVersionType: &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version},
|
||
|
ClientFeatures: []string{clientFeatureNoOverprovisioning},
|
||
|
}
|
||
|
ret.Locality = &v3corepb.Locality{Zone: zone}
|
||
|
if ipv6Capable {
|
||
|
ret.Metadata = ipv6EnabledMetadata
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// runDirectPath returns whether this resolver should use direct path.
|
||
|
//
|
||
|
// direct path is enabled if this client is running on GCE, and the normal xDS
|
||
|
// is not used (bootstrap env vars are not set).
|
||
|
func runDirectPath() bool {
|
||
|
return env.BootstrapFileName == "" && env.BootstrapFileContent == "" && onGCE()
|
||
|
}
|