From 377eacde6e38f437718f5a0f4115d6cda8b20dca Mon Sep 17 00:00:00 2001 From: "Jonathan Hess (he/him)" <103529393+hessjcg@users.noreply.github.com> Date: Fri, 24 Jun 2022 14:18:34 -0600 Subject: [PATCH] chore: Move dialer options out of cmd/main.go and into internal/proxy.go (#1247) Move dialer options out of cmd/main.go and into internal/proxy.go. This consolidates all code relating to cloud.google.com/go/cloudsqlconn into the internal/proxy package. --- cmd/root.go | 46 ++---------------------------- cmd/root_test.go | 7 +++-- internal/proxy/proxy.go | 55 +++++++++++++++++++++++++++++++++--- internal/proxy/proxy_test.go | 9 ++++-- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 1eace8e20..212b16311 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -29,15 +29,12 @@ import ( "syscall" "time" - "cloud.google.com/go/cloudsqlconn" "contrib.go.opencensus.io/exporter/prometheus" "contrib.go.opencensus.io/exporter/stackdriver" "github.com/GoogleCloudPlatform/cloudsql-proxy/v2/cloudsql" - "github.com/GoogleCloudPlatform/cloudsql-proxy/v2/internal/gcloud" "github.com/GoogleCloudPlatform/cloudsql-proxy/v2/internal/proxy" "github.com/spf13/cobra" "go.opencensus.io/trace" - "golang.org/x/oauth2" ) var ( @@ -162,6 +159,8 @@ func parseConfig(cmd *cobra.Command, conf *proxy.Config, args []string) error { return newBadCommandError("missing instance_connection_name (e.g., project:region:instance)") } + conf.UserAgent = userAgent + userHasSet := func(f string) bool { return cmd.PersistentFlags().Lookup(f).Changed } @@ -185,34 +184,6 @@ func parseConfig(cmd *cobra.Command, conf *proxy.Config, args []string) error { if conf.CredentialsFile != "" && conf.GcloudAuth { return newBadCommandError("cannot specify --credentials-file and --gcloud-auth flags at the same time") } - conf.DialerOpts = []cloudsqlconn.Option{ - cloudsqlconn.WithUserAgent(userAgent), - } - switch { - case conf.Token != "": - cmd.Printf("Authorizing with the -token flag\n") - conf.DialerOpts = append(conf.DialerOpts, cloudsqlconn.WithTokenSource( - oauth2.StaticTokenSource(&oauth2.Token{AccessToken: conf.Token}), - )) - case conf.CredentialsFile != "": - cmd.Printf("Authorizing with the credentials file at %q\n", conf.CredentialsFile) - conf.DialerOpts = append(conf.DialerOpts, cloudsqlconn.WithCredentialsFile( - conf.CredentialsFile, - )) - case conf.GcloudAuth: - cmd.Println("Authorizing with gcloud user credentials") - ts, err := gcloud.TokenSource() - if err != nil { - return err - } - conf.DialerOpts = append(conf.DialerOpts, cloudsqlconn.WithTokenSource(ts)) - default: - cmd.Println("Authorizing with Application Default Credentials") - } - - if conf.IAMAuthN { - conf.DialerOpts = append(conf.DialerOpts, cloudsqlconn.WithIAMAuthN()) - } if userHasSet("http-port") && !userHasSet("prometheus-namespace") { return newBadCommandError("cannot specify --http-port without --prometheus-namespace") @@ -406,18 +377,7 @@ func runSignalWrapper(cmd *Command) error { startCh := make(chan *proxy.Client) go func() { defer close(startCh) - // Check if the caller has configured a dialer. - // Otherwise, initialize a new one. - d := cmd.conf.Dialer - if d == nil { - var err error - d, err = cloudsqlconn.NewDialer(ctx, cmd.conf.DialerOpts...) - if err != nil { - shutdownCh <- fmt.Errorf("error initializing dialer: %v", err) - return - } - } - p, err := proxy.NewClient(ctx, d, cmd.Command, cmd.conf) + p, err := proxy.NewClient(ctx, cmd.Command, cmd.conf) if err != nil { shutdownCh <- fmt.Errorf("unable to start: %v", err) return diff --git a/cmd/root_test.go b/cmd/root_test.go index 7c575d71f..b1f37416b 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -26,7 +26,6 @@ import ( "cloud.google.com/go/cloudsqlconn" "github.com/GoogleCloudPlatform/cloudsql-proxy/v2/internal/proxy" "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/spf13/cobra" ) @@ -36,6 +35,9 @@ func TestNewCommandArguments(t *testing.T) { trueValue := true withDefaults := func(c *proxy.Config) *proxy.Config { + if c.UserAgent == "" { + c.UserAgent = userAgent + } if c.Addr == "" { c.Addr = "127.0.0.1" } @@ -218,8 +220,7 @@ func TestNewCommandArguments(t *testing.T) { t.Fatalf("want error = nil, got = %v", err) } - opts := cmpopts.IgnoreFields(proxy.Config{}, "DialerOpts") - if got := c.conf; !cmp.Equal(tc.want, got, opts) { + if got := c.conf; !cmp.Equal(tc.want, got) { t.Fatalf("want = %#v\ngot = %#v\ndiff = %v", tc.want, got, cmp.Diff(tc.want, got)) } }) diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 3810f2e83..13c6f5f7f 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -26,7 +26,9 @@ import ( "cloud.google.com/go/cloudsqlconn" "github.com/GoogleCloudPlatform/cloudsql-proxy/v2/cloudsql" + "github.com/GoogleCloudPlatform/cloudsql-proxy/v2/internal/gcloud" "github.com/spf13/cobra" + "golang.org/x/oauth2" ) // InstanceConnConfig holds the configuration for an individual instance @@ -49,6 +51,9 @@ type InstanceConnConfig struct { // Config contains all the configuration provided by the caller. type Config struct { + // UserAgent is the user agent to use when connecting to the cloudsql instance + UserAgent string + // Token is the Bearer token used for authorization. Token string @@ -81,10 +86,37 @@ type Config struct { // Dialer specifies the dialer to use when connecting to Cloud SQL // instances. Dialer cloudsql.Dialer +} + +// DialerOptions builds appropriate list of options from the Config +// values for use by cloudsqlconn.NewClient() +func (c *Config) DialerOptions() ([]cloudsqlconn.Option, error) { + opts := []cloudsqlconn.Option{ + cloudsqlconn.WithUserAgent(c.UserAgent), + } + switch { + case c.Token != "": + opts = append(opts, cloudsqlconn.WithTokenSource( + oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.Token}), + )) + case c.CredentialsFile != "": + opts = append(opts, cloudsqlconn.WithCredentialsFile( + c.CredentialsFile, + )) + case c.GcloudAuth: + ts, err := gcloud.TokenSource() + if err != nil { + return nil, err + } + opts = append(opts, cloudsqlconn.WithTokenSource(ts)) + default: + } + + if c.IAMAuthN { + opts = append(opts, cloudsqlconn.WithIAMAuthN()) + } - // DialerOpts specifies the opts to use when creating a new dialer. This - // value is ignored when a Dialer has been set. - DialerOpts []cloudsqlconn.Option + return opts, nil } type portConfig struct { @@ -140,7 +172,22 @@ type Client struct { } // NewClient completes the initial setup required to get the proxy to a "steady" state. -func NewClient(ctx context.Context, d cloudsql.Dialer, cmd *cobra.Command, conf *Config) (*Client, error) { +func NewClient(ctx context.Context, cmd *cobra.Command, conf *Config) (*Client, error) { + // Check if the caller has configured a dialer. + // Otherwise, initialize a new one. + d := conf.Dialer + if d == nil { + var err error + dialerOpts, err := conf.DialerOptions() + if err != nil { + return nil, fmt.Errorf("error initializing dialer: %v", err) + } + d, err = cloudsqlconn.NewDialer(ctx, dialerOpts...) + if err != nil { + return nil, fmt.Errorf("error initializing dialer: %v", err) + } + } + var mnts []*socketMount for _, inst := range conf.Instances { go func(name string) { diff --git a/internal/proxy/proxy_test.go b/internal/proxy/proxy_test.go index fc8c03595..69e2b7866 100644 --- a/internal/proxy/proxy_test.go +++ b/internal/proxy/proxy_test.go @@ -211,7 +211,8 @@ func TestClientInitialization(t *testing.T) { for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { - c, err := proxy.NewClient(ctx, fakeDialer{}, &cobra.Command{}, tc.in) + tc.in.Dialer = fakeDialer{} + c, err := proxy.NewClient(ctx, &cobra.Command{}, tc.in) if err != nil { t.Fatalf("want error = nil, got = %v", err) } @@ -254,14 +255,16 @@ func TestClientInitializationWorksRepeatedly(t *testing.T) { Instances: []proxy.InstanceConnConfig{ {Name: "proj:region:pg"}, }, + Dialer: fakeDialer{}, } - c, err := proxy.NewClient(ctx, fakeDialer{}, &cobra.Command{}, in) + + c, err := proxy.NewClient(ctx, &cobra.Command{}, in) if err != nil { t.Fatalf("want error = nil, got = %v", err) } c.Close() - c, err = proxy.NewClient(ctx, fakeDialer{}, &cobra.Command{}, in) + c, err = proxy.NewClient(ctx, &cobra.Command{}, in) if err != nil { t.Fatalf("want error = nil, got = %v", err) }