From b6f792a5c7858760b7b46cefa0fbfa9a08a75609 Mon Sep 17 00:00:00 2001 From: Derek Rada Date: Wed, 6 Apr 2022 12:31:38 -0700 Subject: [PATCH] Add port/protocol for driver --- docs/index.md | 8 ++++++-- examples/provider/provider.tf | 6 ++++-- pkg/provider/provider.go | 30 +++++++++++++++++++++++++----- pkg/provider/provider_test.go | 18 ++++++++++-------- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/docs/index.md b/docs/index.md index 39d32d9b36..2e1c3a7184 100644 --- a/docs/index.md +++ b/docs/index.md @@ -31,8 +31,10 @@ provider "snowflake" { oauth_redirect_url = "..." // optional - role = "..." - host = "..." + role = "..." + host = "..." + protocol = "https" + port = 443 } ``` @@ -59,9 +61,11 @@ provider "snowflake" { - **oauth_redirect_url** (String, Sensitive) Required when `oauth_refresh_token` is used. Can be sourced from `SNOWFLAKE_OAUTH_REDIRECT_URL` environment variable. - **oauth_refresh_token** (String, Sensitive) Token for use with OAuth. Setup and generation of the token is left to other tools. Should be used in conjunction with `oauth_client_id`, `oauth_client_secret`, `oauth_endpoint`, `oauth_redirect_url`. Cannot be used with `browser_auth`, `private_key_path`, `oauth_access_token` or `password`. Can be sourced from `SNOWFLAKE_OAUTH_REFRESH_TOKEN` environment variable. - **password** (String, Sensitive) Password for username+password auth. Cannot be used with `browser_auth` or `private_key_path`. Can be source from `SNOWFLAKE_PASSWORD` environment variable. +- **port** (Number) Support custom port values to snowflake go driver for use with privatelink. Can be sourced from `SNOWFLAKE_PORT` environment variable. - **private_key** (String, Sensitive) Private Key for username+private-key auth. Cannot be used with `browser_auth` or `password`. Can be source from `SNOWFLAKE_PRIVATE_KEY` environment variable. - **private_key_passphrase** (String, Sensitive) Supports the encryption ciphers aes-128-cbc, aes-128-gcm, aes-192-cbc, aes-192-gcm, aes-256-cbc, aes-256-gcm, and des-ede3-cbc - **private_key_path** (String, Sensitive) Path to a private key for using keypair authentication. Cannot be used with `browser_auth`, `oauth_access_token` or `password`. Can be source from `SNOWFLAKE_PRIVATE_KEY_PATH` environment variable. +- **protocol** (String) Support custom protocols to snowflake go driver. Can be sourced from `SNOWFLAKE_PROTOCOL` environment variable. - **region** (String) [Snowflake region](https://docs.snowflake.com/en/user-guide/intro-regions.html) to use. Can be source from the `SNOWFLAKE_REGION` environment variable. - **role** (String) Snowflake role to use for operations. If left unset, default role for user will be used. Can come from the `SNOWFLAKE_ROLE` environment variable. diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index e0d8e152dc..6d3d2a4f6b 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -17,6 +17,8 @@ provider "snowflake" { oauth_redirect_url = "..." // optional - role = "..." - host = "..." + role = "..." + host = "..." + protocol = "https" + port = 443 } diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index f50d868b65..fbdb2cb9a4 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -151,6 +151,18 @@ func Provider() *schema.Provider { Optional: true, DefaultFunc: schema.EnvDefaultFunc("SNOWFLAKE_HOST", nil), }, + "port": { + Type: schema.TypeInt, + Description: "Support custom port values to snowflake go driver for use with privatelink. Can be sourced from `SNOWFLAKE_PORT` environment variable.", + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("SNOWFLAKE_PORT", 443), + }, + "protocol": { + Type: schema.TypeString, + Description: "Support custom protocols to snowflake go driver. Can be sourced from `SNOWFLAKE_PROTOCOL` environment variable.", + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("SNOWFLAKE_PROTOCOL", "https"), + }, }, ResourcesMap: getResources(), DataSourcesMap: getDataSources(), @@ -281,6 +293,8 @@ func ConfigureProvider(s *schema.ResourceData) (interface{}, error) { oauthEndpoint := s.Get("oauth_endpoint").(string) oauthRedirectURL := s.Get("oauth_redirect_url").(string) host := s.Get("host").(string) + protocol := s.Get("protocol").(string) + port := s.Get("port").(int) if oauthRefreshToken != "" { accessToken, err := GetOauthAccessToken(oauthEndpoint, oauthClientID, oauthClientSecret, GetOauthData(oauthRefreshToken, oauthRedirectURL)) @@ -302,6 +316,8 @@ func ConfigureProvider(s *schema.ResourceData) (interface{}, error) { region, role, host, + protocol, + port, ) if err != nil { return nil, errors.Wrap(err, "could not build dsn for snowflake connection") @@ -326,7 +342,9 @@ func DSN( oauthAccessToken, region, role, - host string) (string, error) { + host, + protocol string, + port int) (string, error) { // us-west-2 is their default region, but if you actually specify that it won't trigger their default code // https://github.com/snowflakedb/gosnowflake/blob/52137ce8c32eaf93b0bd22fc5c7297beff339812/dsn.go#L61 @@ -335,10 +353,12 @@ func DSN( } config := gosnowflake.Config{ - Account: account, - User: user, - Region: region, - Role: role, + Account: account, + User: user, + Region: region, + Role: role, + Port: port, + Protocol: protocol, } // If host is set trust it and do not use the region value diff --git a/pkg/provider/provider_test.go b/pkg/provider/provider_test.go index 80e3bf3c5e..681f9619c0 100644 --- a/pkg/provider/provider_test.go +++ b/pkg/provider/provider_test.go @@ -34,7 +34,9 @@ func TestDSN(t *testing.T) { browserAuth bool region, role, - host string + host, + protocol string + port int } tests := []struct { name string @@ -42,18 +44,18 @@ func TestDSN(t *testing.T) { want string wantErr bool }{ - {"simple", args{"acct", "user", "pass", false, "region", "role", ""}, + {"simple", args{"acct", "user", "pass", false, "region", "role", "", "https", 443}, "user:pass@acct.region.snowflakecomputing.com:443?ocspFailOpen=true®ion=region&role=role&validateDefaultParameters=true", false}, - {"us-west-2 special case", args{"acct2", "user2", "pass2", false, "us-west-2", "role2", ""}, + {"us-west-2 special case", args{"acct2", "user2", "pass2", false, "us-west-2", "role2", "", "https", 443}, "user2:pass2@acct2.snowflakecomputing.com:443?ocspFailOpen=true&role=role2&validateDefaultParameters=true", false}, - {"customhostwregion", args{"acct3", "user3", "pass3", false, "", "role3", "zha123.us-east-1.privatelink.snowflakecomputing.com"}, + {"customhostwregion", args{"acct3", "user3", "pass3", false, "", "role3", "zha123.us-east-1.privatelink.snowflakecomputing.com", "https", 443}, "user3:pass3@zha123.us-east-1.privatelink.snowflakecomputing.com:443?account=acct3&ocspFailOpen=true&role=role3&validateDefaultParameters=true", false}, - {"customhostignoreregion", args{"acct4", "user4", "pass4", false, "fakeregion", "role4", "zha1234.us-east-1.privatelink.snowflakecomputing.com"}, - "user4:pass4@zha1234.us-east-1.privatelink.snowflakecomputing.com:443?account=acct4&ocspFailOpen=true&role=role4&validateDefaultParameters=true", false}, + {"customhostignoreregion", args{"acct4", "user4", "pass4", false, "fakeregion", "role4", "zha1234.us-east-1.privatelink.snowflakecomputing.com", "http", 8443}, + "user4:pass4@zha1234.us-east-1.privatelink.snowflakecomputing.com:8443?account=acct4&ocspFailOpen=true&protocol=http&role=role4&validateDefaultParameters=true", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := provider.DSN(tt.args.account, tt.args.user, tt.args.password, tt.args.browserAuth, "", "", "", "", tt.args.region, tt.args.role, tt.args.host) + got, err := provider.DSN(tt.args.account, tt.args.user, tt.args.password, tt.args.browserAuth, "", "", "", "", tt.args.region, tt.args.role, tt.args.host, tt.args.protocol, tt.args.port) if (err != nil) != tt.wantErr { t.Errorf("DSN() error = %v, wantErr %v", err, tt.wantErr) return @@ -89,7 +91,7 @@ func TestOAuthDSN(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := provider.DSN(tt.args.account, tt.args.user, "", false, "", "", "", tt.args.oauthAccessToken, tt.args.region, tt.args.role, "") + got, err := provider.DSN(tt.args.account, tt.args.user, "", false, "", "", "", tt.args.oauthAccessToken, tt.args.region, tt.args.role, "", "https", 443) if (err != nil) != tt.wantErr { t.Errorf("DSN() error = %v, dsn = %v, wantErr %v", err, got, tt.wantErr)