Skip to content

Commit

Permalink
[feature] storage integration (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
sjauld committed Mar 10, 2020
1 parent 4dd975e commit 17c22dc
Show file tree
Hide file tree
Showing 19 changed files with 749 additions and 87 deletions.
46 changes: 33 additions & 13 deletions README.md
Expand Up @@ -208,19 +208,20 @@ These resources do not enforce exclusive attachment of a grant, it is the user's

#### properties

| NAME | TYPE | DESCRIPTION | OPTIONAL | REQUIRED | COMPUTED | DEFAULT |
|--------------------|--------|-------------------------------------------------------------------------------------------------------------------|----------|-----------|----------|---------|
| aws_external_id | string | | true | false | true | <nil> |
| comment | string | Specifies a comment for the stage. | true | false | false | <nil> |
| copy_options | string | Specifies the copy options for the stage. | true | false | false | <nil> |
| credentials | string | Specifies the credentials for the stage. | true | false | false | <nil> |
| database | string | The database in which to create the stage. | false | true | false | <nil> |
| encryption | string | Specifies the encryption settings for the stage. | true | false | false | <nil> |
| file_format | string | Specifies the file format for the stage. | true | false | false | <nil> |
| name | string | Specifies the identifier for the stage; must be unique for the database and schema in which the stage is created. | false | true | false | <nil> |
| schema | string | The schema in which to create the stage. | false | true | false | <nil> |
| snowflake_iam_user | string | | true | false | true | <nil> |
| url | string | Specifies the URL for the stage. | true | false | false | <nil> |
| NAME | TYPE | DESCRIPTION | OPTIONAL | REQUIRED | COMPUTED | DEFAULT |
|---------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-----------|----------|---------|
| aws_external_id | string | | true | false | true | <nil> |
| comment | string | Specifies a comment for the stage. | true | false | false | <nil> |
| copy_options | string | Specifies the copy options for the stage. | true | false | false | <nil> |
| credentials | string | Specifies the credentials for the stage. | true | false | false | <nil> |
| database | string | The database in which to create the stage. | false | true | false | <nil> |
| encryption | string | Specifies the encryption settings for the stage. | true | false | false | <nil> |
| file_format | string | Specifies the file format for the stage. | true | false | false | <nil> |
| name | string | Specifies the identifier for the stage; must be unique for the database and schema in which the stage is created. | false | true | false | <nil> |
| schema | string | The schema in which to create the stage. | false | true | false | <nil> |
| snowflake_iam_user | string | | true | false | true | <nil> |
| storage_integration | string | Specifies the name of the storage integration used to delegate authentication responsibility for external cloud storage to a Snowflake identity and access management (IAM) entity. | true | false | false | <nil> |
| url | string | Specifies the URL for the stage. | true | false | false | <nil> |

### snowflake_stage_grant

Expand All @@ -241,6 +242,25 @@ These resources do not enforce exclusive attachment of a grant, it is the user's
| shares | set | Grants privilege to these shares. | true | false | false | <nil> |
| stage_name | string | The name of the stage on which to grant privileges. | false | true | false | <nil> |

### snowflake_storage_integration

#### properties

| NAME | TYPE | DESCRIPTION | OPTIONAL | REQUIRED | COMPUTED | DEFAULT |
|---------------------------|--------|---------------------------------------------------------------------------------------------------------------|----------|-----------|----------|------------------|
| azure_tenant_id | string | | true | false | false | "" |
| comment | string | | true | false | false | "" |
| created_on | string | Date and time when the storage integration was created. | false | false | true | <nil> |
| enabled | bool | | true | false | false | true |
| name | string | | false | true | false | <nil> |
| storage_allowed_locations | list | Explicitly limits external stages that use the integration to reference one or more storage locations. | false | true | false | <nil> |
| storage_aws_external_id | string | The external ID that Snowflake will use when assuming the AWS role. | false | false | true | <nil> |
| storage_aws_iam_user_arn | string | The Snowflake user that will attempt to assume the AWS role. | false | false | true | <nil> |
| storage_aws_role_arn | string | | true | false | false | "" |
| storage_blocked_locations | list | Explicitly prohibits external stages that use the integration from referencing one or more storage locations. | true | false | false | <nil> |
| storage_provider | string | | false | true | false | <nil> |
| type | string | | true | false | false | "EXTERNAL_STAGE" |

### snowflake_table_grant

**Note**: The snowflake_table_grant resource creates exclusive attachments of grants.
Expand Down
37 changes: 19 additions & 18 deletions pkg/provider/provider.go
Expand Up @@ -60,24 +60,25 @@ func Provider() *schema.Provider {
},
},
ResourcesMap: map[string]*schema.Resource{
"snowflake_database": resources.Database(),
"snowflake_database_grant": resources.DatabaseGrant(),
"snowflake_managed_account": resources.ManagedAccount(),
"snowflake_pipe": resources.Pipe(),
"snowflake_resource_monitor": resources.ResourceMonitor(),
"snowflake_role": resources.Role(),
"snowflake_role_grants": resources.RoleGrants(),
"snowflake_schema": resources.Schema(),
"snowflake_schema_grant": resources.SchemaGrant(),
"snowflake_share": resources.Share(),
"snowflake_stage": resources.Stage(),
"snowflake_stage_grant": resources.StageGrant(),
"snowflake_user": resources.User(),
"snowflake_view": resources.View(),
"snowflake_view_grant": resources.ViewGrant(),
"snowflake_table_grant": resources.TableGrant(),
"snowflake_warehouse": resources.Warehouse(),
"snowflake_warehouse_grant": resources.WarehouseGrant(),
"snowflake_database": resources.Database(),
"snowflake_database_grant": resources.DatabaseGrant(),
"snowflake_managed_account": resources.ManagedAccount(),
"snowflake_pipe": resources.Pipe(),
"snowflake_resource_monitor": resources.ResourceMonitor(),
"snowflake_role": resources.Role(),
"snowflake_role_grants": resources.RoleGrants(),
"snowflake_schema": resources.Schema(),
"snowflake_schema_grant": resources.SchemaGrant(),
"snowflake_share": resources.Share(),
"snowflake_stage": resources.Stage(),
"snowflake_stage_grant": resources.StageGrant(),
"snowflake_storage_integration": resources.StorageIntegration(),
"snowflake_user": resources.User(),
"snowflake_view": resources.View(),
"snowflake_view_grant": resources.ViewGrant(),
"snowflake_table_grant": resources.TableGrant(),
"snowflake_warehouse": resources.Warehouse(),
"snowflake_warehouse_grant": resources.WarehouseGrant(),
},
DataSourcesMap: map[string]*schema.Resource{},
ConfigureFunc: ConfigureProvider,
Expand Down
18 changes: 9 additions & 9 deletions pkg/resources/database.go
Expand Up @@ -29,17 +29,17 @@ var databaseSchema = map[string]*schema.Schema{
Computed: true,
},
"from_share": &schema.Schema{
Type: schema.TypeMap,
Description: "Specify a provider and a share in this map to create a database from a share.",
Optional: true,
ForceNew: true,
Type: schema.TypeMap,
Description: "Specify a provider and a share in this map to create a database from a share.",
Optional: true,
ForceNew: true,
ConflictsWith: []string{"from_database"},
},
"from_database": &schema.Schema{
Type: schema.TypeString,
Description: "Specify a database to create a clone from.",
Optional: true,
ForceNew: true,
Type: schema.TypeString,
Description: "Specify a database to create a clone from.",
Optional: true,
ForceNew: true,
ConflictsWith: []string{"from_share"},
},
}
Expand All @@ -66,7 +66,7 @@ func CreateDatabase(data *schema.ResourceData, meta interface{}) error {
if _, ok := data.GetOk("from_share"); ok {
return createDatabaseFromShare(data, meta)
}

if _, ok := data.GetOk("from_database"); ok {
return createDatabaseFromDatabase(data, meta)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/resources/database_test.go
Expand Up @@ -94,7 +94,7 @@ func TestDatabaseCreateFromDatabase(t *testing.T) {
a := assert.New(t)

in := map[string]interface{}{
"name": "good_name",
"name": "good_name",
"from_database": "abc123",
}
d := schema.TestResourceDataRaw(t, resources.Database().Schema, in)
Expand Down
4 changes: 2 additions & 2 deletions pkg/resources/grant_helpers.go
Expand Up @@ -59,7 +59,7 @@ type grant struct {
type grantID struct {
ResourceName string
SchemaName string
ObjectName string
ObjectName string
Privilege string
}

Expand Down Expand Up @@ -153,7 +153,7 @@ func grantIDFromString(stringID string) (*grantID, error) {
grantResult := &grantID{
ResourceName: lines[0][0],
SchemaName: lines[0][1],
ObjectName: lines[0][2],
ObjectName: lines[0][2],
Privilege: lines[0][3],
}
return grantResult, nil
Expand Down
4 changes: 2 additions & 2 deletions pkg/resources/grant_helpers_internal_test.go
Expand Up @@ -62,7 +62,7 @@ func TestGrantStruct(t *testing.T) {
grant := &grantID{
ResourceName: "database_name",
SchemaName: "schema",
ObjectName: "view_name",
ObjectName: "view_name",
Privilege: "priv",
}
gID, err := grant.String()
Expand All @@ -79,7 +79,7 @@ func TestGrantStruct(t *testing.T) {
grant = &grantID{
ResourceName: "database|name",
SchemaName: "schema|name",
ObjectName: "view|name",
ObjectName: "view|name",
Privilege: "priv",
}
gID, err = grant.String()
Expand Down
8 changes: 8 additions & 0 deletions pkg/resources/helpers_test.go
Expand Up @@ -56,6 +56,14 @@ func roleGrants(t *testing.T, id string, params map[string]interface{}) *schema.
return d
}

func storageIntegration(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData {
a := assert.New(t)
d := schema.TestResourceDataRaw(t, resources.StorageIntegration().Schema, params)
a.NotNil(d)
d.SetId(id)
return d
}

func user(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData {
a := assert.New(t)
d := schema.TestResourceDataRaw(t, resources.User().Schema, params)
Expand Down
28 changes: 28 additions & 0 deletions pkg/resources/list_expansion_internal_test.go
@@ -0,0 +1,28 @@
package resources

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestExpandStringList(t *testing.T) {
r := require.New(t)

in := []interface{}{"this", "is", "just", "a", "test"}
out := expandStringList(in)

r.Equal("this", out[0])
r.Equal("is", out[1])
r.Equal("just", out[2])
r.Equal("a", out[3])
r.Equal("test", out[4])
}

func TestExpandBlankStringList(t *testing.T) {
r := require.New(t)
in := []interface{}{}
out := expandStringList(in)

r.Equal(len(out), 0)
}
26 changes: 26 additions & 0 deletions pkg/resources/stage.go
Expand Up @@ -45,6 +45,11 @@ var stageSchema = map[string]*schema.Schema{
Optional: true,
Description: "Specifies the credentials for the stage.",
},
"storage_integration": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Specifies the name of the storage integration used to delegate authentication responsibility for external cloud storage to a Snowflake identity and access management (IAM) entity.",
},
"file_format": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -157,6 +162,10 @@ func CreateStage(data *schema.ResourceData, meta interface{}) error {
builder.WithCredentials(v.(string))
}

if v, ok := data.GetOk("storage_integration"); ok {
builder.WithStorageIntegration(v.(string))
}

if v, ok := data.GetOk("file_format"); ok {
builder.WithFileFormat(v.(string))
}
Expand Down Expand Up @@ -249,6 +258,11 @@ func ReadStage(data *schema.ResourceData, meta interface{}) error {
return err
}

err = data.Set("storage_integration", stageShow.storageIntegration)
if err != nil {
return err
}

err = data.Set("comment", stageShow.comment)
if err != nil {
return err
Expand Down Expand Up @@ -305,6 +319,18 @@ func UpdateStage(data *schema.ResourceData, meta interface{}) error {

data.SetPartial("credentials")
}

if data.HasChange("storage_integration") {
_, si := data.GetChange("storage_integration")
q := builder.ChangeStorageIntegration(si.(string))
err := DBExec(db, q)
if err != nil {
return errors.Wrapf(err, "error updating stage storage integration on %v", data.Id())
}

data.SetPartial("storage_integration")
}

if data.HasChange("encryption") {
_, encryption := data.GetChange("encryption")
q := builder.ChangeEncryption(encryption.(string))
Expand Down

0 comments on commit 17c22dc

Please sign in to comment.