Skip to content

Commit baf33b2

Browse files
authored
feat(internaloption): add EnableDirectPath internaloption (googleapis#732)
We want to make bigtable attempt DirectPath by default, instead of checking the environment variable GOOGLE_CLOUD_ENABLE_DIRECT_PATH. Notice that even after this PR, the real datapath is still CFE since ACL is currently denied for all projects.
1 parent 4870c18 commit baf33b2

File tree

5 files changed

+38
-54
lines changed

5 files changed

+38
-54
lines changed

internal/settings.go

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type DialSettings struct {
4141
CustomClaims map[string]interface{}
4242
SkipValidation bool
4343
ImpersonationConfig *impersonate.Config
44+
EnableDirectPath bool
4445

4546
// Google API system parameters. For more information please read:
4647
// https://cloud.google.com/apis/docs/system-parameters

option/internaloption/internaloption.go

+15
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,18 @@ type skipDialSettingsValidation struct{}
5050
func (s skipDialSettingsValidation) Apply(settings *internal.DialSettings) {
5151
settings.SkipValidation = true
5252
}
53+
54+
// EnableDirectPath returns a ClientOption that overrides the default
55+
// attempt to use DirectPath.
56+
//
57+
// It should only be used internally by generated clients.
58+
// This is an EXPERIMENTAL API and may be changed or removed in the future.
59+
func EnableDirectPath(dp bool) option.ClientOption {
60+
return enableDirectPath(dp)
61+
}
62+
63+
type enableDirectPath bool
64+
65+
func (e enableDirectPath) Apply(o *internal.DialSettings) {
66+
o.EnableDirectPath = bool(e)
67+
}

transport/grpc/dial.go

+8-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"crypto/tls"
1313
"errors"
1414
"log"
15-
"os"
1615
"strings"
1716

1817
"go.opencensus.io/plugin/ocgrpc"
@@ -138,9 +137,7 @@ func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.C
138137
// * The endpoint is a host:port (or dns:///host:port).
139138
// * Credentials are obtained via GCE metadata server, using the default
140139
// service account.
141-
// * Opted in via GOOGLE_CLOUD_ENABLE_DIRECT_PATH environment variable.
142-
// For example, GOOGLE_CLOUD_ENABLE_DIRECT_PATH=spanner,pubsub
143-
if isDirectPathEnabled(endpoint) && isTokenSourceDirectPathCompatible(creds.TokenSource) {
140+
if o.EnableDirectPath && checkDirectPathEndPoint(endpoint) && isTokenSourceDirectPathCompatible(creds.TokenSource) {
144141
if !strings.HasPrefix(endpoint, "dns:///") {
145142
endpoint = "dns:///" + endpoint
146143
}
@@ -189,7 +186,7 @@ func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.C
189186
// point when isDirectPathEnabled will default to true, we guard it by
190187
// the Directpath env var for now once we can introspect user defined
191188
// dialer (https://github.com/grpc/grpc-go/issues/2795).
192-
if timeoutDialerOption != nil && isDirectPathEnabled(endpoint) {
189+
if timeoutDialerOption != nil && o.EnableDirectPath && checkDirectPathEndPoint(endpoint) {
193190
grpcOpts = append(grpcOpts, timeoutDialerOption)
194191
}
195192

@@ -250,8 +247,8 @@ func isTokenSourceDirectPathCompatible(ts oauth2.TokenSource) bool {
250247
return true
251248
}
252249

253-
func isDirectPathEnabled(endpoint string) bool {
254-
// Only host:port is supported, not other schemes (e.g., "tcp://" or "unix://").
250+
func checkDirectPathEndPoint(endpoint string) bool {
251+
// Only [dns:///]host[:port] is supported, not other schemes (e.g., "tcp://" or "unix://").
255252
// Also don't try direct path if the user has chosen an alternate name resolver
256253
// (i.e., via ":///" prefix).
257254
//
@@ -261,15 +258,11 @@ func isDirectPathEnabled(endpoint string) bool {
261258
return false
262259
}
263260

264-
// Only try direct path if the user has opted in via the environment variable.
265-
directPathAPIs := strings.Split(os.Getenv("GOOGLE_CLOUD_ENABLE_DIRECT_PATH"), ",")
266-
for _, api := range directPathAPIs {
267-
// Ignore empty string since an empty env variable splits into [""]
268-
if api != "" && strings.Contains(endpoint, api) {
269-
return true
270-
}
261+
if endpoint == "" {
262+
return false
271263
}
272-
return false
264+
265+
return true
273266
}
274267

275268
func processAndValidateOpts(opts []option.ClientOption) (*internal.DialSettings, error) {

transport/grpc/dial_socketopt_test.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ import (
1111
"errors"
1212
"fmt"
1313
"net"
14-
"os"
1514
"syscall"
1615
"testing"
1716
"time"
1817

1918
"golang.org/x/oauth2"
2019
"golang.org/x/sys/unix"
2120
"google.golang.org/api/option"
21+
"google.golang.org/api/option/internaloption"
2222
"google.golang.org/grpc"
2323
)
2424

@@ -90,9 +90,6 @@ func getTCPUserTimeout(conn net.Conn) (int, error) {
9090

9191
// Check that tcp timeout dialer overwrites user defined dialer.
9292
func TestDialWithDirectPathEnabled(t *testing.T) {
93-
os.Setenv("GOOGLE_CLOUD_ENABLE_DIRECT_PATH", "example,other")
94-
defer os.Clearenv()
95-
9693
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
9794

9895
userDialer := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
@@ -104,7 +101,8 @@ func TestDialWithDirectPathEnabled(t *testing.T) {
104101
conn, err := Dial(ctx,
105102
option.WithTokenSource(oauth2.StaticTokenSource(nil)), // No creds.
106103
option.WithGRPCDialOption(userDialer),
107-
option.WithEndpoint("example.google.com:443"))
104+
option.WithEndpoint("example.google.com:443"),
105+
internaloption.EnableDirectPath(true))
108106
if err != nil {
109107
t.Errorf("DialGRPC: error %v, want nil", err)
110108
}

transport/grpc/dial_test.go

+11-34
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"context"
99
"errors"
1010
"net"
11-
"os"
1211
"testing"
1312
"time"
1413

@@ -55,62 +54,40 @@ func TestGRPCHook(t *testing.T) {
5554
}
5655
}
5756

58-
func TestIsDirectPathEnabled(t *testing.T) {
57+
func TestCheckDirectPathEndPoint(t *testing.T) {
5958
for _, testcase := range []struct {
6059
name string
6160
endpoint string
62-
envVar string
6361
want bool
6462
}{
6563
{
66-
name: "matches",
67-
endpoint: "some-api",
68-
envVar: "some-api",
69-
want: true,
70-
},
71-
{
72-
name: "does not match",
73-
endpoint: "some-api",
74-
envVar: "some-other-api",
64+
name: "empty endpoint are disallowed",
65+
endpoint: "",
7566
want: false,
7667
},
7768
{
78-
name: "matches in list",
79-
endpoint: "some-api-2",
80-
envVar: "some-api-1,some-api-2,some-api-3",
69+
name: "dns schemes are allowed",
70+
endpoint: "dns:///foo",
8171
want: true,
8272
},
8373
{
84-
name: "empty env var",
85-
endpoint: "",
86-
envVar: "",
87-
want: false,
88-
},
89-
{
90-
name: "trailing comma",
91-
endpoint: "",
92-
envVar: "foo,bar,",
93-
want: false,
74+
name: "host without no prefix are allowed",
75+
endpoint: "foo",
76+
want: true,
9477
},
9578
{
96-
name: "dns schemes are allowed",
97-
endpoint: "dns:///foo",
98-
envVar: "dns:///foo",
79+
name: "host with port are allowed",
80+
endpoint: "foo:1234",
9981
want: true,
10082
},
10183
{
10284
name: "non-dns schemes are disallowed",
10385
endpoint: "https://foo",
104-
envVar: "https://foo",
10586
want: false,
10687
},
10788
} {
10889
t.Run(testcase.name, func(t *testing.T) {
109-
if err := os.Setenv("GOOGLE_CLOUD_ENABLE_DIRECT_PATH", testcase.envVar); err != nil {
110-
t.Fatal(err)
111-
}
112-
113-
if got := isDirectPathEnabled(testcase.endpoint); got != testcase.want {
90+
if got := checkDirectPathEndPoint(testcase.endpoint); got != testcase.want {
11491
t.Fatalf("got %v, want %v", got, testcase.want)
11592
}
11693
})

0 commit comments

Comments
 (0)