diff --git a/internal/settings.go b/internal/settings.go index 26259b82abb..db508bdc01f 100644 --- a/internal/settings.go +++ b/internal/settings.go @@ -41,6 +41,7 @@ type DialSettings struct { CustomClaims map[string]interface{} SkipValidation bool ImpersonationConfig *impersonate.Config + EnableDirectPath bool // Google API system parameters. For more information please read: // https://cloud.google.com/apis/docs/system-parameters diff --git a/option/internaloption/internaloption.go b/option/internaloption/internaloption.go index b4d78a830ae..e6639a3b7a1 100644 --- a/option/internaloption/internaloption.go +++ b/option/internaloption/internaloption.go @@ -50,3 +50,18 @@ type skipDialSettingsValidation struct{} func (s skipDialSettingsValidation) Apply(settings *internal.DialSettings) { settings.SkipValidation = true } + +// EnableDirectPath returns a ClientOption that overrides the default +// attempt to use DirectPath. +// +// It should only be used by Yoshi libraries. +// This is an EXPERIMENTAL API and may be changed or removed in the future. +func EnableDirectPath(dp bool) option.ClientOption { + return enableDirectPath(dp) +} + +type enableDirectPath bool + +func (e enableDirectPath) Apply(o *internal.DialSettings) { + o.EnableDirectPath = bool(e) +} diff --git a/transport/grpc/dial.go b/transport/grpc/dial.go index 55c04a5af06..813ee94e409 100644 --- a/transport/grpc/dial.go +++ b/transport/grpc/dial.go @@ -12,7 +12,6 @@ import ( "crypto/tls" "errors" "log" - "os" "strings" "go.opencensus.io/plugin/ocgrpc" @@ -135,12 +134,11 @@ func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.C } // Attempt Direct Path only if: + // * Yoshi library set AttemptDirectPath option // * The endpoint is a host:port (or dns:///host:port). // * Credentials are obtained via GCE metadata server, using the default // service account. - // * Opted in via GOOGLE_CLOUD_ENABLE_DIRECT_PATH environment variable. - // For example, GOOGLE_CLOUD_ENABLE_DIRECT_PATH=spanner,pubsub - if isDirectPathEnabled(endpoint) && isTokenSourceDirectPathCompatible(creds.TokenSource) { + if o.EnableDirectPath && checkDirectPathEndPoint(endpoint) && isTokenSourceDirectPathCompatible(creds.TokenSource) { if !strings.HasPrefix(endpoint, "dns:///") { endpoint = "dns:///" + endpoint } @@ -189,7 +187,7 @@ func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.C // point when isDirectPathEnabled will default to true, we guard it by // the Directpath env var for now once we can introspect user defined // dialer (https://github.com/grpc/grpc-go/issues/2795). - if timeoutDialerOption != nil && isDirectPathEnabled(endpoint) { + if timeoutDialerOption != nil && o.EnableDirectPath && checkDirectPathEndPoint(endpoint) { grpcOpts = append(grpcOpts, timeoutDialerOption) } @@ -250,7 +248,7 @@ func isTokenSourceDirectPathCompatible(ts oauth2.TokenSource) bool { return true } -func isDirectPathEnabled(endpoint string) bool { +func checkDirectPathEndPoint(endpoint string) bool { // Only host:port is supported, not other schemes (e.g., "tcp://" or "unix://"). // Also don't try direct path if the user has chosen an alternate name resolver // (i.e., via ":///" prefix). @@ -261,15 +259,7 @@ func isDirectPathEnabled(endpoint string) bool { return false } - // Only try direct path if the user has opted in via the environment variable. - directPathAPIs := strings.Split(os.Getenv("GOOGLE_CLOUD_ENABLE_DIRECT_PATH"), ",") - for _, api := range directPathAPIs { - // Ignore empty string since an empty env variable splits into [""] - if api != "" && strings.Contains(endpoint, api) { - return true - } - } - return false + return true } func processAndValidateOpts(opts []option.ClientOption) (*internal.DialSettings, error) {