Skip to content

Commit

Permalink
Add data source snowflake_current_account (Snowflake-Labs#567)
Browse files Browse the repository at this point in the history
  • Loading branch information
robbruce authored and anton-chekanov committed Jan 25, 2022
1 parent 9a3e210 commit cd6d302
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 0 deletions.
38 changes: 38 additions & 0 deletions docs/data-sources/current_account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "snowflake_current_account Data Source - terraform-provider-snowflake"
subcategory: ""
description: |-
---

# snowflake_current_account (Data Source)



## Example Usage

```terraform
data "snowflake_current_account" "this" {}
resource "aws_ssm_parameter" "snowflake_account_url" {
name = "/snowflake/account_url"
type = "String"
value = data.snowflake_current_account.this.url
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- **id** (String) The ID of this resource.

### Read-Only

- **account** (String) The Snowflake Account ID; as returned by CURRENT_ACCOUNT().
- **region** (String) The Snowflake Region; as returned by CURRENT_REGION()
- **url** (String) The Snowflake URL.


Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
data "snowflake_current_account" "this" {}

resource "aws_ssm_parameter" "snowflake_account_url" {
name = "/snowflake/account_url"
type = "String"
value = data.snowflake_current_account.this.url
}
64 changes: 64 additions & 0 deletions pkg/datasources/current_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package datasources

import (
"database/sql"
"fmt"
"log"

"github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

var currentAccountSchema = map[string]*schema.Schema{
"account": {
Type: schema.TypeString,
Computed: true,
Description: "The Snowflake Account ID; as returned by CURRENT_ACCOUNT().",
},

"region": {
Type: schema.TypeString,
Computed: true,
Description: "The Snowflake Region; as returned by CURRENT_REGION()",
},

"url": {
Type: schema.TypeString,
Computed: true,
Description: "The Snowflake URL.",
},
}

// CurrentAccount the Snowflake current account resource
func CurrentAccount() *schema.Resource {
return &schema.Resource{
Read: ReadCurrentAccount,
Schema: currentAccountSchema,
}
}

// ReadCurrentAccount read the current snowflake account information
func ReadCurrentAccount(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
acc, err := snowflake.ReadCurrentAccount(db)

if err != nil {
log.Printf("[DEBUG] current_account failed to decode")
d.SetId("")
return nil
}

d.SetId(fmt.Sprintf("%s.%s", acc.Account, acc.Region))
d.Set("account", acc.Account)
d.Set("region", acc.Region)
url, err := acc.AccountURL()

if err != nil {
log.Printf("[DEBUG] generating snowflake url failed")
d.SetId("")
return nil
}

d.Set("url", url)
return nil
}
30 changes: 30 additions & 0 deletions pkg/datasources/current_account_acceptance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package datasources_test

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccCurrentAccount(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
Providers: providers(),
Steps: []resource.TestStep{
{
Config: currentAccount(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.snowflake_current_account.p", "account"),
resource.TestCheckResourceAttrSet("data.snowflake_current_account.p", "region"),
resource.TestCheckResourceAttrSet("data.snowflake_current_account.p", "url"),
),
},
},
})
}

func currentAccount() string {
s := `
data snowflake_current_account p {}
`
return s
}
1 change: 1 addition & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func getResources() map[string]*schema.Resource {

func getDataSources() map[string]*schema.Resource {
dataSources := map[string]*schema.Resource{
"snowflake_current_account": datasources.CurrentAccount(),
"snowflake_system_generate_scim_access_token": datasources.SystemGenerateSCIMAccessToken(),
"snowflake_system_get_aws_sns_iam_policy": datasources.SystemGetAWSSNSIAMPolicy(),
"snowflake_system_get_privatelink_config": datasources.SystemGetPrivateLinkConfig(),
Expand Down
68 changes: 68 additions & 0 deletions pkg/snowflake/current_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package snowflake

import (
"database/sql"
"fmt"
"strings"

"github.com/jmoiron/sqlx"
)

// taken from https://docs.snowflake.com/en/user-guide/admin-account-identifier.html#snowflake-region-ids
var regionMapping = map[string]string{
"aws_us_west_2": "", // left black as this is the default
"aws_us_east_2": "us-east-2.aws",
"aws_us_east_1": "us-east-1",
"aws_us_east_1_gov": "us-east-1-gov.aws",
"aws_ca_central_1": "ca-central-1.aws",
"aws_eu_west_1": "eu-west-1",
"aws_eu_west_2": "eu-west-2.aws",
"aws_eu_central_1": "eu-central-1",
"aws_ap_northeast_1": "ap-northeast-1.aws",
"aws_ap_south_1": "ap-south-1.aws",
"aws_ap_southeast_1": "ap-southeast-1",
"aws_ap_southeast_2": "ap-southeast-2",
"gcp_us_central1": "us-central1.gcp",
"gcp_europe_west2": "europe-west2.gcp",
"gcp_europe_west4": "europe-west4.gcp",
"azure_westus2": "west-us-2.azure",
"azure_eastus2": "east-us-2.azure",
"azure_usgovvirginia": "us-gov-virginia.azure",
"azure_canadacentral": "canada-central.azure",
"azure_westeurope": "west-europe.azure",
"azure_southeastasia": "southeast-asia.azure",
"azure_switzerlandnorth": "switzerland-north.azure",
"azure_australiaeast": "australia-east.azure",
}

func SelectCurrentAccount() string {
return `SELECT CURRENT_ACCOUNT() AS "account", CURRENT_REGION() AS "region";`
}

type account struct {
Account string `db:"account"`
Region string `db:"region"`
}

func ScanCurrentAccount(row *sqlx.Row) (*account, error) {
acc := &account{}
err := row.StructScan(acc)
return acc, err
}

func ReadCurrentAccount(db *sql.DB) (*account, error) {
row := QueryRow(db, SelectCurrentAccount())
return ScanCurrentAccount(row)
}

func (acc *account) AccountURL() (string, error) {
if region_id, ok := regionMapping[strings.ToLower(acc.Region)]; ok {
account_id := acc.Account
if len(region_id) > 0 {
account_id = fmt.Sprintf("%s.%s", account_id, region_id)
}
return fmt.Sprintf("https://%s.snowflakecomputing.com", account_id), nil
}

return "", fmt.Errorf("Failed to map Snowflake account region %s to a region_id", acc.Region)
}
71 changes: 71 additions & 0 deletions pkg/snowflake/current_account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package snowflake_test

import (
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
"testing"
)

func TestCurrentAccountSelect(t *testing.T) {
r := require.New(t)
r.Equal(`SELECT CURRENT_ACCOUNT() AS "account", CURRENT_REGION() AS "region";`, snowflake.SelectCurrentAccount())
}

func TestCurrentAccountRead(t *testing.T) {
type testCaseEntry struct {
account string
region string
url string
}

testCases := map[string]testCaseEntry{
"aws oregon": {
"ab1234",
"AWS_US_WEST_2",
"https://ab1234.snowflakecomputing.com",
},
"aws n virginia": {
"cd5678",
"AWS_US_EAST_1",
"https://cd5678.us-east-1.snowflakecomputing.com",
},
"aws canada central": {
"ef9012",
"AWS_CA_CENTRAL_1",
"https://ef9012.ca-central-1.aws.snowflakecomputing.com",
},
"gcp canada central": {
"gh3456",
"gcp_us_central1",
"https://gh3456.us-central1.gcp.snowflakecomputing.com",
},
"azure washington": {
"ij7890",
"azure_westus2",
"https://ij7890.west-us-2.azure.snowflakecomputing.com",
},
}

for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
r := require.New(t)
mockDB, mock, err := sqlmock.New()
r.NoError(err)
defer mockDB.Close()
sqlxDB := sqlx.NewDb(mockDB, "sqlmock")

rows := sqlmock.NewRows([]string{"account", "region"}).AddRow(testCase.account, testCase.region)
mock.ExpectQuery(`SELECT CURRENT_ACCOUNT\(\) AS "account", CURRENT_REGION\(\) AS "region";`).WillReturnRows(rows)

acc, err := snowflake.ReadCurrentAccount(sqlxDB.DB)
r.NoError(err)
r.Equal(testCase.account, acc.Account)
r.Equal(testCase.region, acc.Region)
url, err := acc.AccountURL()
r.NoError(err)
r.Equal(testCase.url, url)
})
}
}

0 comments on commit cd6d302

Please sign in to comment.