Skip to content

Commit

Permalink
feat: add WithAutoIP option (#346)
Browse files Browse the repository at this point in the history
This commit adds an option to support a legacy behavior where a public
IP is selected if available, and otherwise the private IP is used.

Fixes 244.
  • Loading branch information
enocom committed Oct 17, 2022
1 parent c2c9899 commit bd20b6b
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 4 deletions.
16 changes: 15 additions & 1 deletion internal/cloudsql/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,21 @@ func (i *Instance) ConnectInfo(ctx context.Context, ipType string) (string, *tls
if err != nil {
return "", nil, err
}
addr, ok := res.md.ipAddrs[ipType]
var (
addr string
ok bool
)
switch ipType {
case AutoIP:
// Try Public first
addr, ok = res.md.ipAddrs[PublicIP]
if !ok {
// Try Private second
addr, ok = res.md.ipAddrs[PrivateIP]
}
default:
addr, ok = res.md.ipAddrs[ipType]
}
if !ok {
err := errtype.NewConfigError(
fmt.Sprintf("instance does not have IP of type %q", ipType),
Expand Down
61 changes: 61 additions & 0 deletions internal/cloudsql/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,67 @@ func TestConnectInfo(t *testing.T) {
}
}

func TestConnectInfoAutoIP(t *testing.T) {
tcs := []struct {
desc string
ips []mock.FakeCSQLInstanceOption
wantIP string
}{
{
desc: "when public IP is enabled",
ips: []mock.FakeCSQLInstanceOption{
mock.WithPublicIP("8.8.8.8"),
mock.WithPrivateIP("10.0.0.1"),
},
wantIP: "8.8.8.8",
},
{
desc: "when only private IP is enabled",
ips: []mock.FakeCSQLInstanceOption{
mock.WithPrivateIP("10.0.0.1"),
},
wantIP: "10.0.0.1",
},
}

for _, tc := range tcs {
var opts []mock.FakeCSQLInstanceOption
opts = append(opts, mock.WithNoIPAddrs())
opts = append(opts, tc.ips...)
inst := mock.NewFakeCSQLInstance("p", "r", "i", opts...)
client, cleanup, err := mock.NewSQLAdminService(
context.Background(),
mock.InstanceGetSuccess(inst, 1),
mock.CreateEphemeralSuccess(inst, 1),
)
if err != nil {
t.Fatalf("%s", err)
}
defer func() {
if cErr := cleanup(); cErr != nil {
t.Fatalf("%v", cErr)
}
}()

i, err := NewInstance("p:r:i", client, RSAKey, 30*time.Second, nil, "", RefreshCfg{})
if err != nil {
t.Fatalf("failed to create mock instance: %v", err)
}

got, _, err := i.ConnectInfo(context.Background(), AutoIP)
if err != nil {
t.Fatalf("failed to retrieve connect info: %v", err)
}

if got != tc.wantIP {
t.Fatalf(
"ConnectInfo returned unexpected IP address, want = %v, got = %v",
tc.wantIP, got,
)
}
}
}

func TestConnectInfoErrors(t *testing.T) {
ctx := context.Background()

Expand Down
2 changes: 2 additions & 0 deletions internal/cloudsql/refresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const (
PublicIP = "PUBLIC"
// PrivateIP is the value for private IP Cloud SQL instances.
PrivateIP = "PRIVATE"
// AutoIP selects public IP if available and otherwise selects private IP.
AutoIP = "AutoIP"
)

// metadata contains information about a Cloud SQL instance needed to create connections.
Expand Down
2 changes: 1 addition & 1 deletion internal/cloudsql/refresh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func TestRefreshMetadataConfigError(t *testing.T) {
mock.NewFakeCSQLInstance(
cn.project, cn.region, cn.name,
mock.WithRegion("my-region"),
mock.WithMissingIPAddrs(),
mock.WithNoIPAddrs(),
), 1),
wantErr: &errtype.ConfigError{},
desc: "When the instance has no supported IP addresses",
Expand Down
4 changes: 2 additions & 2 deletions internal/mock/cloudsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ func WithClientCertSigner(s ClientSignFunc) FakeCSQLInstanceOption {
}
}

// WithMissingIPAddrs configures a Fake Cloud SQL instance to have no IP
// WithNoIPAddrs configures a Fake Cloud SQL instance to have no IP
// addresses.
func WithMissingIPAddrs() FakeCSQLInstanceOption {
func WithNoIPAddrs() FakeCSQLInstanceOption {
return func(f *FakeCSQLInstance) {
f.ipAddrs = map[string]string{}
}
Expand Down
9 changes: 9 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ func WithPrivateIP() DialOption {
}
}

// WithAutoIP returns a DialOption that selects the public IP if available and
// otherwise falls back to private IP. This option is present for backwards
// compatibility only and is not recommended for use in production.
func WithAutoIP() DialOption {
return func(cfg *dialCfg) {
cfg.ipType = cloudsql.AutoIP
}
}

// WithDialIAMAuthN allows you to enable or disable IAM Authentication for this
// instance as descibed in the documentation for WithIAMAuthN. This value will
// overide the Dialer-level configuration set with WithIAMAuthN.
Expand Down

0 comments on commit bd20b6b

Please sign in to comment.