From 878561474ce03c2783593cdc13a16737a5782eb1 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Mon, 6 Feb 2023 14:31:29 -0800 Subject: [PATCH 01/26] fix: cleanup grant logic --- pkg/resources/grant_helpers.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/pkg/resources/grant_helpers.go b/pkg/resources/grant_helpers.go index 62bef714e5..8795162a8e 100644 --- a/pkg/resources/grant_helpers.go +++ b/pkg/resources/grant_helpers.go @@ -276,13 +276,11 @@ func readGenericGrant( // Now see which roles have our privilege. for roleName, privileges := range rolePrivileges { if privileges.hasString(priv) { - // CASE A: If multiple grants is not enabled (meaning this is authoritative) then we always care about what roles have privilige. - caseA := !multipleGrantFeatureFlag - // CASE B: If this is not authoritative, then at least continue managing whatever roles we already are managing - caseB := multipleGrantFeatureFlag && existingRoles.Contains(roleName) - // CASE C: If this is not authoritative and we are not managing the role, then we only care about the role if future objects is disabled. Otherwise we will get flooded with diffs. - caseC := multipleGrantFeatureFlag && !futureObjects - if caseA || caseB || caseC { + // CASE A: Whatever role we were already managing, continue to do so. + caseA := existingRoles.Contains(roleName) + // CASE B : If multiple grants is not enabled (meaning this is an authoritative resource) then we care about what roles have privilige unless on_future is enabled in which case we don't care (because we will get flooded with diffs) + caseB := !multipleGrantFeatureFlag && !futureObjects + if caseA || caseB { roles = append(roles, roleName) } } @@ -295,13 +293,11 @@ func readGenericGrant( // Now see which shares have our privilege. for shareName, privileges := range sharePrivileges { if privileges.hasString(priv) { - // CASE A: If multiple grants is not enabled (meaning this is authoritative) then we always care about what shares have privilige. - caseA := !multipleGrantFeatureFlag - // CASE B: If this is not authoritative, then at least continue managing whatever shares we already are managing - caseB := multipleGrantFeatureFlag && existingShares.Contains(shareName) - // CASE C: If this is not authoritative and we are not managing the share, then we only care about the share if future objects is disabled. Otherwise we will get flooded with diffs. - caseC := multipleGrantFeatureFlag && !futureObjects - if caseA || caseB || caseC { + // CASE A: Whatever share we were already managing, continue to do so. + caseA := existingShares.Contains(shareName) + // CASE B : If multiple grants is not enabled (meaning this is an authoritative resource) then we care about what shares have privilige unless on_future is enabled in which case we don't care (because we will get flooded with diffs) + caseB := !multipleGrantFeatureFlag && !futureObjects + if caseA || caseB { shares = append(shares, shareName) } } From 0a0b2e14820835b201ab8160a9efbb7afb5e57c0 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Mon, 6 Feb 2023 14:42:25 -0800 Subject: [PATCH 02/26] fix nil pointer dereference --- pkg/resources/grant_helpers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/resources/grant_helpers.go b/pkg/resources/grant_helpers.go index 8795162a8e..a0cdcafd96 100644 --- a/pkg/resources/grant_helpers.go +++ b/pkg/resources/grant_helpers.go @@ -267,7 +267,7 @@ func readGenericGrant( } } - var existingRoles *schema.Set + var existingRoles = schema.NewSet(schema.HashString, []interface{}{}) if v, ok := d.GetOk("roles"); ok && v != nil { existingRoles = v.(*schema.Set) } @@ -286,7 +286,7 @@ func readGenericGrant( } } - var existingShares *schema.Set + var existingShares = schema.NewSet(schema.HashString, []interface{}{}) if v, ok := d.GetOk("shares"); ok && v != nil { existingShares = v.(*schema.Set) } From 0f9e3611cdf54087d6dde3365c42f5b94cecf346 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Mon, 6 Feb 2023 14:45:03 -0800 Subject: [PATCH 03/26] fix nil pointer dereference --- pkg/resources/grant_helpers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/resources/grant_helpers.go b/pkg/resources/grant_helpers.go index a0cdcafd96..11e8a115ea 100644 --- a/pkg/resources/grant_helpers.go +++ b/pkg/resources/grant_helpers.go @@ -267,7 +267,7 @@ func readGenericGrant( } } - var existingRoles = schema.NewSet(schema.HashString, []interface{}{}) + existingRoles := schema.NewSet(schema.HashString, []interface{}{}) if v, ok := d.GetOk("roles"); ok && v != nil { existingRoles = v.(*schema.Set) } @@ -286,7 +286,7 @@ func readGenericGrant( } } - var existingShares = schema.NewSet(schema.HashString, []interface{}{}) + existingShares := schema.NewSet(schema.HashString, []interface{}{}) if v, ok := d.GetOk("shares"); ok && v != nil { existingShares = v.(*schema.Set) } From 2aa943f60d005bed35c8f757cecf5fff87b65065 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:09:02 -0800 Subject: [PATCH 04/26] revise grant id --- go.mod | 1 + go.sum | 2 + pkg/helpers/imports.go | 72 ++++++++ pkg/resources/account_grant.go | 61 +++---- pkg/resources/database_grant.go | 89 +++++----- pkg/resources/external_table_grant.go | 153 +++++++++++------ pkg/resources/file_format_grant.go | 133 +++++++++------ pkg/resources/function_grant.go | 164 +++++++++++------- pkg/resources/grant_helpers.go | 108 ------------ pkg/resources/grant_helpers_internal_test.go | 169 ------------------- pkg/resources/integration_grant.go | 101 +++++++---- pkg/resources/masking_policy_grant.go | 121 ++++++++----- pkg/resources/materialized_view_grant.go | 143 +++++++++++----- pkg/resources/pipe_grant.go | 139 +++++++++------ pkg/resources/procedure_grant.go | 164 +++++++++++------- pkg/resources/resource_monitor_grant.go | 101 +++++++---- pkg/resources/role_grants.go | 69 ++++++-- pkg/resources/role_ownership_grant.go | 1 - pkg/resources/row_access_policy_grant.go | 116 ++++++++----- pkg/resources/schema_grant.go | 131 +++++++++----- pkg/resources/sequence_grant.go | 135 ++++++++++----- pkg/resources/stage_grant.go | 142 ++++++++++------ pkg/resources/stream_grant.go | 126 ++++++++------ pkg/resources/table_grant.go | 158 ++++++++++------- pkg/resources/tag_grant.go | 120 ++++++++----- pkg/resources/task_grant.go | 135 ++++++++++----- pkg/resources/user_grant.go | 100 ++++++++--- pkg/resources/view_grant.go | 159 ++++++++++------- pkg/resources/warehouse_grant.go | 103 +++++++---- 29 files changed, 1941 insertions(+), 1275 deletions(-) create mode 100644 pkg/helpers/imports.go delete mode 100644 pkg/resources/grant_helpers_internal_test.go diff --git a/go.mod b/go.mod index 0f2d4bf6e4..34b0f068a0 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/luna-duclos/instrumentedsql v1.1.3 github.com/mitchellh/go-homedir v1.1.0 + github.com/rs/xid v1.4.0 github.com/snowflakedb/gosnowflake v1.6.16 github.com/stretchr/testify v1.8.1 github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a diff --git a/go.sum b/go.sum index f483040d4c..a014d12e57 100644 --- a/go.sum +++ b/go.sum @@ -338,6 +338,8 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= diff --git a/pkg/helpers/imports.go b/pkg/helpers/imports.go new file mode 100644 index 0000000000..42689161d4 --- /dev/null +++ b/pkg/helpers/imports.go @@ -0,0 +1,72 @@ +package helpers + +import ( + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/rs/xid" +) + +func RandomSnowflakeID() string { + guid := xid.New() + return fmt.Sprintf("snow-%s", guid.String()) +} + +func DecodeSnowflakeImportID(id string, v interface{}) (interface{}, error) { + attributes := make(map[string]string) + parts := strings.Split(id, "|") + for _, part := range parts { + if !strings.Contains(part, "=") { + return nil, fmt.Errorf("invalid import ID format: %s, attributes must be defined as key=value format", id) + } + key := strings.TrimSpace(strings.Split(part, "=")[0]) + value := strings.TrimSpace(strings.Split(part, "=")[1]) + attributes[key] = value + } + for k, v := range attributes { + fmt.Printf("[DEBUG] %s=%s\n", k, v) + } + + // w is the interface{} + w := reflect.ValueOf(&v).Elem() + + // Allocate a temporary variable with type of the struct. + // v.Elem() is the value contained in the interface. + tmp := reflect.New(w.Elem().Type()).Elem() + + // Copy the struct value contained in interface to + // the temporary variable. + tmp.Set(w.Elem()) + + t := tmp.Type() + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + tag := field.Tag.Get("tf") + importValue := attributes[tag] + f := tmp.FieldByName(field.Name) + switch f.Kind() { + case reflect.String: + f.SetString(importValue) + case reflect.Int: + intVal, err := strconv.Atoi(importValue) + if err != nil { + return nil, err + } + f.SetInt(int64(intVal)) + case reflect.Bool: + f.SetBool(importValue == "true") + case reflect.Slice: + p := strings.Split(importValue, ",") + for _, v := range p { + v := strings.Trim(v, "\"") + f.Set(reflect.Append(f, reflect.ValueOf(v))) + } + } + } + // Set the interface to the modified struct value. + w.Set(tmp) + fmt.Printf("[DEBUG] v=%+v\n", v) + return v, nil +} diff --git a/pkg/resources/account_grant.go b/pkg/resources/account_grant.go index c7c743e9f0..4329d86dac 100644 --- a/pkg/resources/account_grant.go +++ b/pkg/resources/account_grant.go @@ -1,6 +1,9 @@ package resources import ( + "context" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -48,6 +51,7 @@ var accountGrantSchema = map[string]*schema.Schema{ Description: "The account privilege to grant. Valid privileges are those in [globalPrivileges](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege.html)", Default: privilegeMonitorUsage, ValidateFunc: validation.StringInSlice(validAccountPrivileges.ToList(), true), + ForceNew: true, }, "roles": { Type: schema.TypeSet, @@ -81,53 +85,45 @@ func AccountGrant() *TerraformGrantResource { Schema: accountGrantSchema, Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, + StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + v, err := helpers.DecodeSnowflakeImportID(d.Id(), AccountGrantID{}) + if err != nil { + return nil, err + } + id := v.(AccountGrantID) + d.Set("privilege", id.Privilege) + d.Set("roles", id.Roles) + d.Set("with_grant_option", id.WithGrantOption) + d.SetId(helpers.RandomSnowflakeID()) + return []*schema.ResourceData{d}, nil + }, }, }, ValidPrivs: validAccountPrivileges, } } +type AccountGrantID struct { + Privilege string `tf:"privilege"` + Roles []string `tf:"roles"` + WithGrantOption bool `tf:"with_grant_option"` +} + // CreateAccountGrant implements schema.CreateFunc. func CreateAccountGrant(d *schema.ResourceData, meta interface{}) error { - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - builder := snowflake.AccountGrant() if err := createGenericGrant(d, meta, builder); err != nil { return err } - grantID := &grantID{ - ResourceName: "ACCOUNT", - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grantID.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + d.SetId(helpers.RandomSnowflakeID()) return ReadAccountGrant(d, meta) } // ReadAccountGrant implements schema.ReadFunc. func ReadAccountGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) - if err != nil { - return err - } - if err := d.Set("privilege", grantID.Privilege); err != nil { - return err - } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { - return err - } - builder := snowflake.AccountGrant() return readGenericGrant(d, meta, accountGrantSchema, builder, false, validAccountPrivileges) @@ -150,20 +146,17 @@ func UpdateAccountGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - grantID, err := grantIDFromString(d.Id()) - if err != nil { - return err - } - builder := snowflake.AccountGrant() + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) // first revoke - if err := deleteGenericGrantRolesAndShares(meta, builder, grantID.Privilege, rolesToRevoke, nil); err != nil { + if err := deleteGenericGrantRolesAndShares(meta, builder, privilege, rolesToRevoke, nil); err != nil { return err } // then add - if err := createGenericGrantRolesAndShares(meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, nil); err != nil { + if err := createGenericGrantRolesAndShares(meta, builder, privilege, withGrantOption, rolesToAdd, nil); err != nil { return err } diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index 4c6d145c73..44b3a2aec2 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -1,8 +1,9 @@ package resources import ( + "context" "fmt" - + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -71,70 +72,58 @@ func DatabaseGrant() *TerraformGrantResource { Schema: databaseGrantSchema, Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, + StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + v, err := helpers.DecodeSnowflakeImportID(d.Id(), DatabaseGrantID{}) + if err != nil { + return nil, err + } + id := v.(DatabaseGrantID) + d.Set("database_name", id.DatabaseName) + d.Set("privilege", id.Privilege) + d.Set("roles", id.Roles) + d.Set("shares", id.Shares) + d.Set("with_grant_option", id.WithGrantOption) + d.SetId(helpers.RandomSnowflakeID()) + return []*schema.ResourceData{d}, nil + }, }, }, ValidPrivs: validDatabasePrivileges, } } +type DatabaseGrantID struct { + DatabaseName string `tf:"database_name"` + Privilege string `tf:"privilege"` + Roles []string `tf:"roles"` + Shares []string `tf:"shares"` + WithGrantOption bool `tf:"with_grant_option"` +} + // CreateDatabaseGrant implements schema.CreateFunc. func CreateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - dbName := d.Get("database_name").(string) - builder := snowflake.DatabaseGrant(dbName) - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - + databaseName := d.Get("database_name").(string) + builder := snowflake.DatabaseGrant(databaseName) if err := createGenericGrant(d, meta, builder); err != nil { return fmt.Errorf("error creating database grant err = %w", err) } - grant := &grantID{ - ResourceName: dbName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return fmt.Errorf("error creating database grant err = %w", err) - } - d.SetId(dataIDInput) + d.SetId(helpers.RandomSnowflakeID()) return ReadDatabaseGrant(d, meta) } // ReadDatabaseGrant implements schema.ReadFunc. func ReadDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) - if err != nil { - return err - } - if err := d.Set("database_name", grantID.ResourceName); err != nil { - return err - } - if err := d.Set("privilege", grantID.Privilege); err != nil { - return err - } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { - return err - } - - // IMPORTED PRIVILEGES is not a real resource, so we can't actually verify - // that it is still there. Just exit for now - if grantID.Privilege == "IMPORTED PRIVILEGES" { - return nil - } - - builder := snowflake.DatabaseGrant(grantID.ResourceName) + databaseName := d.Get("database_name").(string) + builder := snowflake.DatabaseGrant(databaseName) return readGenericGrant(d, meta, databaseGrantSchema, builder, false, validDatabasePrivileges) } // DeleteDatabaseGrant implements schema.DeleteFunc. func DeleteDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - dbName := d.Get("database_name").(string) - builder := snowflake.DatabaseGrant(dbName) + databaseName := d.Get("database_name").(string) + builder := snowflake.DatabaseGrant(databaseName) return deleteGenericGrant(d, meta, builder) } @@ -158,19 +147,17 @@ func UpdateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) - if err != nil { - return err - } - + databaseName := d.Get("database_name").(string) + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) // create the builder - builder := snowflake.DatabaseGrant(grantID.ResourceName) + builder := snowflake.DatabaseGrant(databaseName) // first revoke if err := deleteGenericGrantRolesAndShares( meta, builder, - grantID.Privilege, + privilege, rolesToRevoke, sharesToRevoke, ); err != nil { @@ -181,8 +168,8 @@ func UpdateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { if err := createGenericGrantRolesAndShares( meta, builder, - grantID.Privilege, - grantID.GrantOption, + privilege, + withGrantOption, rolesToAdd, sharesToAdd, ); err != nil { diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go index 6b07743064..048658055a 100644 --- a/pkg/resources/external_table_grant.go +++ b/pkg/resources/external_table_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -100,12 +102,13 @@ func CreateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("external_table_name"); ok { externalTableName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (externalTableName == "") && !onFuture { return errors.New("external_table_name must be set unless on_future is true") @@ -119,71 +122,68 @@ func CreateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureExternalTableGrant(dbName, schemaName) + builder = snowflake.FutureExternalTableGrant(databaseName, schemaName) } else { - builder = snowflake.ExternalTableGrant(dbName, schemaName, externalTableName) + builder = snowflake.ExternalTableGrant(databaseName, schemaName, externalTableName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: externalTableName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewExternalTableGrantID(databaseName, schemaName, externalTableName, privilege, roles, shares, withGrantOption) + d.SetId(grantID.String()) return ReadExternalTableGrant(d, meta) } // ReadExternalTableGrant implements schema.ReadFunc. func ReadExternalTableGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseExternalTableGrant(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - externalTableName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if !grantID.IsOldID { + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } + + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { + return err + } + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("external_table_name", grantID.ObjectName); err != nil { return err } + onFuture := false - if externalTableName == "" { + if grantID.ObjectName == "" { onFuture = true } - if err := d.Set("external_table_name", externalTableName); err != nil { - return err - } if err := d.Set("on_future", onFuture); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureExternalTableGrant(dbName, schemaName) + builder = snowflake.FutureExternalTableGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ExternalTableGrant(dbName, schemaName, externalTableName) + builder = snowflake.ExternalTableGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, externalTableGrantSchema, builder, onFuture, validExternalTablePrivileges) @@ -191,21 +191,17 @@ func ReadExternalTableGrant(d *schema.ResourceData, meta interface{}) error { // DeleteExternalTableGrant implements schema.DeleteFunc. func DeleteExternalTableGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseExternalTableGrant(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - externalTableName := grantID.ObjectName - - onFuture := (externalTableName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureExternalTableGrant(dbName, schemaName) + builder = snowflake.FutureExternalTableGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ExternalTableGrant(dbName, schemaName, externalTableName) + builder = snowflake.ExternalTableGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -228,22 +224,20 @@ func UpdateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { if d.HasChange("shares") { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) + + grantID, err := parseExternalTableGrant(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - externalTableName := grantID.ObjectName - onFuture := (externalTableName == "") + onFuture := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureExternalTableGrant(dbName, schemaName) + builder = snowflake.FutureExternalTableGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ExternalTableGrant(dbName, schemaName, externalTableName) + builder = snowflake.ExternalTableGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -255,7 +249,7 @@ func UpdateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, sharesToAdd, ); err != nil { return err } @@ -263,3 +257,64 @@ func UpdateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadExternalTableGrant(d, meta) } + +type ExternalTableGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewExternalTableGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, shares []string, withGrantOption bool) *ExternalTableGrantID { + return &ExternalTableGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *ExternalTableGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseExternalTableGrant(s string) (*ExternalTableGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &ExternalTableGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 7 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 7", len(idParts)) + } + return &ExternalTableGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: strings.Split(idParts[5], ","), + WithGrantOption: idParts[6] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index 54a94d4d8c..6fe870871c 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -93,11 +95,11 @@ func CreateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("file_format_name"); ok { fileFormatName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if (fileFormatName == "") && !onFuture { @@ -112,71 +114,58 @@ func CreateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFileFormatGrant(dbName, schemaName) + builder = snowflake.FutureFileFormatGrant(databaseName, schemaName) } else { - builder = snowflake.FileFormatGrant(dbName, schemaName, fileFormatName) + builder = snowflake.FileFormatGrant(databaseName, schemaName, fileFormatName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: fileFormatName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewFileFormatGrantID(databaseName, schemaName, fileFormatName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadFileFormatGrant(d, meta) } // ReadFileFormatGrant implements schema.ReadFunc. func ReadFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseFileFormatGrant(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - fileFormatName := grantID.ObjectName - priv := grantID.Privilege - - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("roles", grantID.Roles); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - onFuture := false - if fileFormatName == "" { - onFuture = true + if err := d.Set("schema_name", grantID.SchemaName); err != nil { + return err } - if err := d.Set("file_format_name", fileFormatName); err != nil { + if err := d.Set("file_format_name", grantID.ObjectName); err != nil { return err } + onFuture := false + if grantID.ObjectName == "" { + onFuture = true + } if err := d.Set("on_future", onFuture); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFileFormatGrant(dbName, schemaName) + builder = snowflake.FutureFileFormatGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.FileFormatGrant(dbName, schemaName, fileFormatName) + builder = snowflake.FileFormatGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, fileFormatGrantSchema, builder, onFuture, validFileFormatPrivileges) @@ -184,21 +173,18 @@ func ReadFileFormatGrant(d *schema.ResourceData, meta interface{}) error { // DeleteFileFormatGrant implements schema.DeleteFunc. func DeleteFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseFunctionGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - fileFormatName := grantID.ObjectName - onFuture := (fileFormatName == "") + onFuture := ( grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFileFormatGrant(dbName, schemaName) + builder = snowflake.FutureFileFormatGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.FileFormatGrant(dbName, schemaName, fileFormatName) + builder = snowflake.FileFormatGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -218,22 +204,19 @@ func UpdateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseFileFormatGrant(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - fileFormatName := grantID.ObjectName - onFuture := (fileFormatName == "") + onFuture := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFileFormatGrant(dbName, schemaName) + builder = snowflake.FutureFileFormatGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.FileFormatGrant(dbName, schemaName, fileFormatName) + builder = snowflake.FileFormatGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -244,7 +227,7 @@ func UpdateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -252,3 +235,55 @@ func UpdateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadFileFormatGrant(d, meta) } + +type FileFormatGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool +} + +func NewFileFormatGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *FileFormatGrantID { + return &FileFormatGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + } +} + +func (v *FileFormatGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseFileFormatGrant(s string) (*FileFormatGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &FileFormatGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &FileFormatGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + }, nil +} diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index d92610ee15..eb668d11eb 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -137,11 +137,11 @@ func CreateFunctionGrant(d *schema.ResourceData, meta interface{}) error { functionName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) var argumentDataTypes []string // support deprecated arguments if v, ok := d.GetOk("arguments"); ok { @@ -156,6 +156,7 @@ func CreateFunctionGrant(d *schema.ResourceData, meta interface{}) error { } roles := expandStringList(d.Get("roles").(*schema.Set).List()) + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (functionName == "") && !onFuture { return errors.New("function_name must be set unless on_future is true") @@ -169,69 +170,54 @@ func CreateFunctionGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFunctionGrant(dbName, schemaName) + builder = snowflake.FutureFunctionGrant(databaseName, schemaName) } else { - builder = snowflake.FunctionGrant(dbName, schemaName, functionName, argumentDataTypes) + builder = snowflake.FunctionGrant(databaseName, schemaName, functionName, argumentDataTypes) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - // If this is a on_futures grant then the function name and arguments do not get set. This is only used for refresh purposes. - var functionObjectName string - if !onFuture { - functionObjectName = fmt.Sprintf("%s(%s)", functionName, strings.Join(argumentDataTypes, ",")) - } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: functionObjectName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - grantID, err := grant.String() - if err != nil { - return err - } - d.SetId(grantID) + grantID := NewFunctionGrantID(databaseName, schemaName, functionName,argumentDataTypes, privilege, roles, shares, withGrantOption) + d.SetId(grantID.String()) return ReadFunctionGrant(d, meta) } // ReadFunctionGrant implements schema.ReadFunc. func ReadFunctionGrant(d *schema.ResourceData, meta interface{}) error { - var functionName string - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseFunctionGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - if err := d.Set("database_name", dbName); err != nil { + if !grantID.IsOldID { + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - schemaName := grantID.SchemaName - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - functionObjectName := grantID.ObjectName - var argumentDataTypes []string onFuture := false - if functionObjectName == "" { + if grantID.ObjectName == "" { onFuture = true - } else { - functionName, argumentDataTypes = parseFunctionObjectName(functionObjectName) - } - if err := d.Set("function_name", functionName); err != nil { + } + if err := d.Set("function_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("argument_data_types", argumentDataTypes); err != nil { + if err := d.Set("argument_data_types", grantID.ArgumentDataTypes); err != nil { return err } if err := d.Set("on_future", onFuture); err != nil { @@ -240,9 +226,9 @@ func ReadFunctionGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFunctionGrant(dbName, schemaName) + builder = snowflake.FutureFunctionGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.FunctionGrant(dbName, schemaName, functionName, argumentDataTypes) + builder = snowflake.FunctionGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } return readGenericGrant(d, meta, functionGrantSchema, builder, onFuture, validFunctionPrivileges) @@ -250,24 +236,18 @@ func ReadFunctionGrant(d *schema.ResourceData, meta interface{}) error { // DeleteFunctionGrant implements schema.DeleteFunc. func DeleteFunctionGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseFunctionGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName onFuture := (grantID.ObjectName == "") - functionObjectName := grantID.ObjectName - var functionName string - var argumentDataTypes []string var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFunctionGrant(dbName, schemaName) + builder = snowflake.FutureFunctionGrant(grantID.DatabaseName, grantID.SchemaName) } else { - functionName, argumentDataTypes = parseFunctionObjectName(functionObjectName) - builder = snowflake.FunctionGrant(dbName, schemaName, functionName, argumentDataTypes) + builder = snowflake.FunctionGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } return deleteGenericGrant(d, meta, builder) } @@ -290,23 +270,18 @@ func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { if d.HasChange("shares") { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseFunctionGrantID(d.Id()) if err != nil { return err } - - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - functionObjectName := grantID.ObjectName - onFuture := (functionObjectName == "") + onFuture := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureFunctionGrant(dbName, schemaName) + builder = snowflake.FutureFunctionGrant(grantID.DatabaseName, grantID.SchemaName) } else { - functionName, argumentDataTypes := parseFunctionObjectName(functionObjectName) - builder = snowflake.FunctionGrant(dbName, schemaName, functionName, argumentDataTypes) + builder = snowflake.FunctionGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } // first revoke @@ -317,7 +292,7 @@ func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, sharesToAdd, ); err != nil { return err } @@ -325,3 +300,74 @@ func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadFunctionGrant(d, meta) } + +type FunctionGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + ArgumentDataTypes []string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewFunctionGrantID(databaseName string, schemaName, objectName string, argumentDataTypes []string, privilege string, roles []string, shares []string, withGrantOption bool) *FunctionGrantID { + return &FunctionGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + ArgumentDataTypes: argumentDataTypes, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *FunctionGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseFunctionGrantID(s string) (*FunctionGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + objectIdentifier := idParts[2] + if idx := strings.Index(objectIdentifier, ")"); idx != -1 { + objectIdentifier = objectIdentifier[0:idx] + } + objectNameParts := strings.Split(objectIdentifier, "(") + + return &FunctionGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: objectNameParts[0], + ArgumentDataTypes: strings.Split(objectNameParts[1], ","), + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 8 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 8", len(idParts)) + } + return &FunctionGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + ArgumentDataTypes: strings.Split(idParts[3], ","), + Privilege: idParts[4], + Roles: strings.Split(idParts[5], ","), + Shares: strings.Split(idParts[6], ","), + WithGrantOption: idParts[7] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/grant_helpers.go b/pkg/resources/grant_helpers.go index 11e8a115ea..6227b238a0 100644 --- a/pkg/resources/grant_helpers.go +++ b/pkg/resources/grant_helpers.go @@ -1,9 +1,7 @@ package resources import ( - "bytes" "database/sql" - "encoding/csv" "fmt" "log" "strings" @@ -73,89 +71,6 @@ type grant struct { GrantOption bool } -// grantID contains identifying elements that allow unique access privileges. -type grantID struct { - ResourceName string - SchemaName string - ObjectName string - Privilege string - Roles []string - GrantOption bool -} - -// String() takes in a grantID object and returns a pipe-delimited string: -// resourceName|schemaName|ObjectName|Privilege|Roles|GrantOption. -func (gi *grantID) String() (string, error) { - var buf bytes.Buffer - csvWriter := csv.NewWriter(&buf) - csvWriter.Comma = grantIDDelimiter - grantOption := fmt.Sprintf("%v", gi.GrantOption) - roles := strings.Join(gi.Roles, ",") - dataIdentifiers := [][]string{{gi.ResourceName, gi.SchemaName, gi.ObjectName, gi.Privilege, roles, grantOption}} - if err := csvWriter.WriteAll(dataIdentifiers); err != nil { - return "", err - } - strGrantID := strings.TrimSpace(buf.String()) - return strGrantID, nil -} - -// grantIDFromString() takes in a pipe-delimited string: resourceName|schemaName|ObjectName|Privilege|Roles -// and returns a grantID object. -func grantIDFromString(stringID string) (*grantID, error) { - reader := csv.NewReader(strings.NewReader(stringID)) - reader.Comma = grantIDDelimiter - lines, err := reader.ReadAll() - if err != nil { - return nil, fmt.Errorf("not CSV compatible") - } - - if len(lines) != 1 { - return nil, fmt.Errorf("1 line per grant") - } - - // Len 1 is allowing for legacy IDs where role names are not included - if len(lines[0]) < 1 || len(lines[0]) > 6 { - return nil, fmt.Errorf("1 to 6 fields allowed in ID") - } - - // Splitting string list if new ID structure, will cause issues if roles names passed are "true" or "false". - // Checking for true/false to eliminate scenarios where it would pick up the grant option. - // Roles will be empty list if legacy IDs are used, roles from grants are not - // used in Read functions, just for uniqueness in IDs of resources - roles := []string{} - if len(lines[0]) > 4 && lines[0][4] != "true" && lines[0][4] != "false" { - roles = strings.Split(lines[0][4], ",") - } - - // Allowing legacy IDs to check grant option - grantOption := false - if len(lines[0]) == 6 && lines[0][5] == "true" { - grantOption = true - } else if len(lines[0]) == 5 && lines[0][4] == "true" { - grantOption = true - } - - schemaName := "" - objectName := "" - privilege := "" - - if len(lines[0]) > 3 { - schemaName = lines[0][1] - objectName = lines[0][2] - privilege = lines[0][3] - } - - grantResult := &grantID{ - ResourceName: lines[0][0], - SchemaName: schemaName, - ObjectName: objectName, - Privilege: privilege, - Roles: roles, - GrantOption: grantOption, - } - return grantResult, nil -} - // createGenericGrantRolesAndShares will create generic grants for a set of roles and shares. func createGenericGrantRolesAndShares( meta interface{}, @@ -437,29 +352,6 @@ func expandRolesAndShares(d *schema.ResourceData) ([]string, []string) { return roles, shares } -// parseFunctionObjectName parses a callable object name (including procedures) into its identifier components. For example, functions and procedures. -func parseFunctionObjectName(objectIdentifier string) (string, []string) { - nameIndex := strings.Index(objectIdentifier, `(`) - if nameIndex == -1 { - return "", []string{} - } - name := objectIdentifier[:nameIndex] - argumentString := objectIdentifier[nameIndex+1:] - - // Backwards compatibility for functions with return_types (prior to 0.56.1). - if strings.Contains(argumentString, ":") { - argumentString = strings.Split(argumentString, ":")[0] - } - - // Remove trailing ")". - argumentString = strings.TrimRight(argumentString, `)`) - arguments := strings.Split(argumentString, `,`) - for i, argument := range arguments { - arguments[i] = strings.TrimSpace(argument) - } - return name, arguments -} - // changeDiff calculates roles/shares to add/revoke. func changeDiff(d *schema.ResourceData, key string) (toAdd []string, toRemove []string) { o, n := d.GetChange(key) diff --git a/pkg/resources/grant_helpers_internal_test.go b/pkg/resources/grant_helpers_internal_test.go deleted file mode 100644 index 0ea97299e1..0000000000 --- a/pkg/resources/grant_helpers_internal_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package resources - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestGrantIDFromString(t *testing.T) { - r := require.New(t) - // Vanilla without GrantOption - id := "database_name|schema|view_name|privilege|test1,test2" - grant, err := grantIDFromString(id) - r.NoError(err) - - r.Equal("database_name", grant.ResourceName) - r.Equal("schema", grant.SchemaName) - r.Equal("view_name", grant.ObjectName) - r.Equal("privilege", grant.Privilege) - r.Equal(false, grant.GrantOption) - - // Vanilla with GrantOption - id = "database_name|schema|view_name|privilege|test1,test2|true" - grant, err = grantIDFromString(id) - r.NoError(err) - - r.Equal("database_name", grant.ResourceName) - r.Equal("schema", grant.SchemaName) - r.Equal("view_name", grant.ObjectName) - r.Equal("privilege", grant.Privilege) - r.Equal(true, grant.GrantOption) - - // No view - id = "database_name|||privilege|" - grant, err = grantIDFromString(id) - r.NoError(err) - r.Equal("database_name", grant.ResourceName) - r.Equal("", grant.SchemaName) - r.Equal("", grant.ObjectName) - r.Equal("privilege", grant.Privilege) - r.Equal(false, grant.GrantOption) - - // too many fields - id = "database_name|schema|view_name|privilege|false|2|too-many" - _, err = grantIDFromString(id) - r.Equal(fmt.Errorf("1 to 6 fields allowed in ID"), err) - - // 0 lines - id = "" - _, err = grantIDFromString(id) - r.Equal(fmt.Errorf("1 line per grant"), err) - - // 2 lines - id = `database_name|schema|view_name|privilege - database_name|schema|view_name|privilege` - _, err = grantIDFromString(id) - r.Equal(fmt.Errorf("1 line per grant"), err) -} - -func TestGrantStruct(t *testing.T) { - r := require.New(t) - // Vanilla - grant := &grantID{ - ResourceName: "database_name", - SchemaName: "schema", - ObjectName: "view_name", - Privilege: "priv", - Roles: []string{"test1", "test2"}, - GrantOption: true, - } - gID, err := grant.String() - r.NoError(err) - r.Equal("database_name|schema|view_name|priv|test1,test2|true", gID) - - // Empty grant - grant = &grantID{} - gID, err = grant.String() - r.NoError(err) - r.Equal("|||||false", gID) - - // Grant with extra delimiters - grant = &grantID{ - ResourceName: "database|name", - SchemaName: "schema|name", - ObjectName: "view|name", - Privilege: "priv", - Roles: []string{"test3", "test4"}, - GrantOption: false, - } - gID, err = grant.String() - r.NoError(err) - newGrant, err := grantIDFromString(gID) - r.NoError(err) - r.Equal("database|name", newGrant.ResourceName) - r.Equal("schema|name", newGrant.SchemaName) - r.Equal("view|name", newGrant.ObjectName) - r.Equal("priv", newGrant.Privilege) - r.Equal([]string{"test3", "test4"}, newGrant.Roles) - r.Equal(false, newGrant.GrantOption) -} - -func TestGrantLegacyID(t *testing.T) { - // Testing that grants with legacy ID structure resolves to expected output - r := require.New(t) - gID := "database_name|schema|view_name|priv|true" - grant, err := grantIDFromString(gID) - r.NoError(err) - r.Equal("database_name", grant.ResourceName) - r.Equal("schema", grant.SchemaName) - r.Equal("view_name", grant.ObjectName) - r.Equal("priv", grant.Privilege) - r.Equal([]string{}, grant.Roles) - r.Equal(true, grant.GrantOption) - - gID = "database_name|schema|view_name|priv|false" - grant, err = grantIDFromString(gID) - r.NoError(err) - r.Equal("database_name", grant.ResourceName) - r.Equal("schema", grant.SchemaName) - r.Equal("view_name", grant.ObjectName) - r.Equal("priv", grant.Privilege) - r.Equal([]string{}, grant.Roles) - r.Equal(false, grant.GrantOption) - - gID = "database_name|schema|view_name|priv" - grant, err = grantIDFromString(gID) - r.NoError(err) - r.Equal("database_name", grant.ResourceName) - r.Equal("schema", grant.SchemaName) - r.Equal("view_name", grant.ObjectName) - r.Equal("priv", grant.Privilege) - r.Equal([]string{}, grant.Roles) - r.Equal(false, grant.GrantOption) -} - -func TestGrantIDFromStringRoleGrant(t *testing.T) { - r := require.New(t) - gID := "role_a||||role1,role2|" - grant, err := grantIDFromString(gID) - r.NoError(err) - r.Equal("role_a", grant.ResourceName) - r.Equal("", grant.SchemaName) - r.Equal("", grant.ObjectName) - r.Equal("", grant.Privilege) - r.Equal([]string{"role1", "role2"}, grant.Roles) - r.Equal(false, grant.GrantOption) - - // Testing the legacy ID structure passes as expected - gID = "role_a" - grant, err = grantIDFromString(gID) - r.NoError(err) - r.Equal("role_a", grant.ResourceName) - r.Equal("", grant.SchemaName) - r.Equal("", grant.ObjectName) - r.Equal("", grant.Privilege) - r.Equal([]string{}, grant.Roles) - r.Equal(false, grant.GrantOption) - - gID = "role_b||||role3,role4|false" - grant, err = grantIDFromString(gID) - r.NoError(err) - r.Equal("role_b", grant.ResourceName) - r.Equal("", grant.SchemaName) - r.Equal("", grant.ObjectName) - r.Equal("", grant.Privilege) - r.Equal([]string{"role3", "role4"}, grant.Roles) - r.Equal(false, grant.GrantOption) -} diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go index 6a23745a10..37eb8f04f1 100644 --- a/pkg/resources/integration_grant.go +++ b/pkg/resources/integration_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -68,64 +71,54 @@ func IntegrationGrant() *TerraformGrantResource { // CreateIntegrationGrant implements schema.CreateFunc. func CreateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - w := d.Get("integration_name").(string) - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) + integrationName := d.Get("integration_name").(string) + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) - builder := snowflake.IntegrationGrant(w) + builder := snowflake.IntegrationGrant(integrationName) if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: w, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewIntegrationGrantID(integrationName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadIntegrationGrant(d, meta) } // ReadIntegrationGrant implements schema.ReadFunc. func ReadIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseIntegrationGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - priv := grantID.Privilege - - if err := d.Set("integration_name", w); err != nil { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("integration_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - builder := snowflake.IntegrationGrant(w) + builder := snowflake.IntegrationGrant(grantID.ObjectName) return readGenericGrant(d, meta, integrationGrantSchema, builder, false, validIntegrationPrivileges) } // DeleteIntegrationGrant implements schema.DeleteFunc. func DeleteIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseIntegrationGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - builder := snowflake.IntegrationGrant(w) + builder := snowflake.IntegrationGrant(grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } @@ -145,15 +138,13 @@ func UpdateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseIntegrationGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - // create the builder - builder := snowflake.IntegrationGrant(w) + builder := snowflake.IntegrationGrant(grantID.ObjectName) // first revoke @@ -164,7 +155,7 @@ func UpdateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -172,3 +163,51 @@ func UpdateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadIntegrationGrant(d, meta) } + +type IntegrationGrantID struct { + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewIntegrationGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *IntegrationGrantID { + return &IntegrationGrantID{ + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *IntegrationGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseIntegrationGrantID(s string) (*IntegrationGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &IntegrationGrantID{ + ObjectName: idParts[0], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 4 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 4", len(idParts)) + } + return &IntegrationGrantID{ + ObjectName: idParts[0], + Privilege: idParts[1], + Roles: strings.Split(idParts[2], ","), + WithGrantOption: idParts[3] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go index 73ee9a7c7c..735ffad6ba 100644 --- a/pkg/resources/masking_policy_grant.go +++ b/pkg/resources/masking_policy_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -84,77 +87,61 @@ func CreateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("masking_policy_name"); ok { maskingPolicyName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) - builder := snowflake.MaskingPolicyGrant(dbName, schemaName, maskingPolicyName) + builder := snowflake.MaskingPolicyGrant(databaseName, schemaName, maskingPolicyName) if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: maskingPolicyName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewMaskingPolicyGrantID(databaseName, schemaName, maskingPolicyName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadMaskingPolicyGrant(d, meta) } // ReadMaskingPolicyGrant implements schema.ReadFunc. func ReadMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseMaskingPolicyGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - maskingPolicyName := grantID.ObjectName - priv := grantID.Privilege - - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } - if err := d.Set("masking_policy_name", maskingPolicyName); err != nil { + if err := d.Set("masking_policy_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - builder := snowflake.MaskingPolicyGrant(dbName, schemaName, maskingPolicyName) + builder := snowflake.MaskingPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return readGenericGrant(d, meta, maskingPolicyGrantSchema, builder, false, validMaskingPoilcyPrivileges) } // DeleteMaskingPolicyGrant implements schema.DeleteFunc. func DeleteMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseMaskingPolicyGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - maskingPolicyName := grantID.ObjectName - builder := snowflake.MaskingPolicyGrant(dbName, schemaName, maskingPolicyName) + builder := snowflake.MaskingPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } @@ -174,17 +161,13 @@ func UpdateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseMaskingPolicyGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - maskingPolicyName := grantID.ObjectName - // create the builder - builder := snowflake.MaskingPolicyGrant(dbName, schemaName, maskingPolicyName) + builder := snowflake.MaskingPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -194,7 +177,7 @@ func UpdateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -202,3 +185,59 @@ func UpdateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadMaskingPolicyGrant(d, meta) } + +type MaskingPolicyGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewMaskingPolicyGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *MaskingPolicyGrantID { + return &MaskingPolicyGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *MaskingPolicyGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error){ + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &MaskingPolicyGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &MaskingPolicyGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go index d5d2a29e40..303b2e9f18 100644 --- a/pkg/resources/materialized_view_grant.go +++ b/pkg/resources/materialized_view_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -106,12 +108,13 @@ func CreateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error if name, ok := d.GetOk("materialized_view_name"); ok { materializedViewName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) futureMaterializedViews := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (schemaName == "") && !futureMaterializedViews { return errors.New("schema_name must be set unless on_future is true") @@ -126,71 +129,64 @@ func CreateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error var builder snowflake.GrantBuilder if futureMaterializedViews { - builder = snowflake.FutureMaterializedViewGrant(dbName, schemaName) + builder = snowflake.FutureMaterializedViewGrant(databaseName, schemaName) } else { - builder = snowflake.MaterializedViewGrant(dbName, schemaName, materializedViewName) + builder = snowflake.MaterializedViewGrant(databaseName, schemaName, materializedViewName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: materializedViewName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewMaterializedViewGrantID(databaseName, schemaName, materializedViewName, privilege, roles, shares, withGrantOption) + d.SetId(grantID.String()) return ReadMaterializedViewGrant(d, meta) } // ReadViewGrant implements schema.ReadFunc. func ReadMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseMaterializedViewGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - materializedViewName := grantID.ObjectName - priv := grantID.Privilege + if !grantID.IsOldID { + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } futureMaterializedViewsEnabled := false - if materializedViewName == "" { + if grantID.ObjectName == "" { futureMaterializedViewsEnabled = true } - if err := d.Set("materialized_view_name", materializedViewName); err != nil { + if err := d.Set("materialized_view_name", grantID.ObjectName); err != nil { return err } if err := d.Set("on_future", futureMaterializedViewsEnabled); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if futureMaterializedViewsEnabled { - builder = snowflake.FutureMaterializedViewGrant(dbName, schemaName) + builder = snowflake.FutureMaterializedViewGrant( grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.MaterializedViewGrant(dbName, schemaName, materializedViewName) + builder = snowflake.MaterializedViewGrant( grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, materializedViewGrantSchema, builder, futureMaterializedViewsEnabled, validMaterializedViewPrivileges) @@ -198,21 +194,18 @@ func ReadMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { // DeleteViewGrant implements schema.DeleteFunc. func DeleteMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseMaterializedViewGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - materializedViewName := grantID.ObjectName - futureMaterializedViews := (materializedViewName == "") + futureMaterializedViews := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if futureMaterializedViews { - builder = snowflake.FutureMaterializedViewGrant(dbName, schemaName) + builder = snowflake.FutureMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.MaterializedViewGrant(dbName, schemaName, materializedViewName) + builder = snowflake.MaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -235,22 +228,19 @@ func UpdateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error if d.HasChange("shares") { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseMaterializedViewGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - materializedViewName := grantID.ObjectName - futureMaterializedViews := (materializedViewName == "") + futureMaterializedViews := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if futureMaterializedViews { - builder = snowflake.FutureMaterializedViewGrant(dbName, schemaName) + builder = snowflake.FutureMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.MaterializedViewGrant(dbName, schemaName, materializedViewName) + builder = snowflake.MaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -261,7 +251,7 @@ func UpdateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, sharesToAdd, ); err != nil { return err } @@ -269,3 +259,64 @@ func UpdateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error // Done, refresh state return ReadMaterializedViewGrant(d, meta) } + +type MaterializedViewGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewMaterializedViewGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, shares []string, withGrantOption bool) *MaterializedViewGrantID { + return &MaterializedViewGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *MaterializedViewGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseMaterializedViewGrantID(s string) (*MaterializedViewGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &MaterializedViewGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 7 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 7", len(idParts)) + } + return &MaterializedViewGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: strings.Split(idParts[5], ","), + WithGrantOption: idParts[6] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index 4e029dd460..c29fb8cb41 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -89,22 +91,19 @@ func PipeGrant() *TerraformGrantResource { // CreatePipeGrant implements schema.CreateFunc. func CreatePipeGrant(d *schema.ResourceData, meta interface{}) error { - var ( - pipeName string - schemaName string - ) - + var pipeName string if name, ok := d.GetOk("pipe_name"); ok { pipeName = name.(string) } + var schemaName string if name, ok := d.GetOk("schema_name"); ok { schemaName = name.(string) } - dbName := d.Get("database_name").(string) - priv := d.Get("privilege").(string) + databaseName := d.Get("database_name").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if (schemaName == "") && !onFuture { @@ -116,70 +115,58 @@ func CreatePipeGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FuturePipeGrant(dbName, schemaName) + builder = snowflake.FuturePipeGrant(databaseName, schemaName) } else { - builder = snowflake.PipeGrant(dbName, schemaName, pipeName) + builder = snowflake.PipeGrant(databaseName, schemaName, pipeName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: pipeName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewPipeGrantID(databaseName, schemaName, pipeName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadPipeGrant(d, meta) } // ReadPipeGrant implements schema.ReadFunc. func ReadPipeGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parsePipeGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - pipeName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("roles", grantID.Roles); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { + return err + } + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } - onFuture := (pipeName == "") + onFuture := ( grantID.ObjectName == "") - if err := d.Set("pipe_name", pipeName); err != nil { + if err := d.Set("pipe_name", grantID.ObjectName); err != nil { return err } if err := d.Set("on_future", onFuture); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FuturePipeGrant(dbName, schemaName) + builder = snowflake.FuturePipeGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.PipeGrant(dbName, schemaName, pipeName) + builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, pipeGrantSchema, builder, onFuture, validPipePrivileges) @@ -187,21 +174,18 @@ func ReadPipeGrant(d *schema.ResourceData, meta interface{}) error { // DeletePipeGrant implements schema.DeleteFunc. func DeletePipeGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parsePipeGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - pipeName := grantID.ObjectName - onFuture := (pipeName == "") + onFuture := ( grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FuturePipeGrant(dbName, schemaName) + builder = snowflake.FuturePipeGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.PipeGrant(dbName, schemaName, pipeName) + builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -221,22 +205,19 @@ func UpdatePipeGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parsePipeGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - pipeName := grantID.ObjectName - onFuture := (pipeName == "") + onFuture := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FuturePipeGrant(dbName, schemaName) + builder = snowflake.FuturePipeGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.PipeGrant(dbName, schemaName, pipeName) + builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -247,7 +228,7 @@ func UpdatePipeGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -255,3 +236,59 @@ func UpdatePipeGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadPipeGrant(d, meta) } + +type PipeGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewPipeGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *PipeGrantID { + return &PipeGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *PipeGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parsePipeGrantID(s string) (*PipeGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &PipeGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &PipeGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index e94fb391bc..d5e8ad5a49 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -136,11 +136,11 @@ func CreateProcedureGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("procedure_name"); ok { procedureName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) argumentDataTypes := make([]string, 0) @@ -156,6 +156,7 @@ func CreateProcedureGrant(d *schema.ResourceData, meta interface{}) error { } roles := expandStringList(d.Get("roles").(*schema.Set).List()) + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (procedureName == "") && !onFuture { return errors.New("procedure_name must be set unless on_future is true") @@ -169,68 +170,53 @@ func CreateProcedureGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureProcedureGrant(dbName, schemaName) + builder = snowflake.FutureProcedureGrant(databaseName, schemaName) } else { - builder = snowflake.ProcedureGrant(dbName, schemaName, procedureName, argumentDataTypes) + builder = snowflake.ProcedureGrant(databaseName, schemaName, procedureName, argumentDataTypes) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - // If this is a on_futures grant then the procedure name and arguments do not get set. This is only used for refresh purposes. - var procedureObjectName string - if !onFuture { - procedureObjectName = fmt.Sprintf("%s(%s)", procedureName, strings.Join(argumentDataTypes, ", ")) - } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: procedureObjectName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - grantID, err := grant.String() - if err != nil { - return err - } - d.SetId(grantID) + grantID := NewProcedureGrantID(databaseName, schemaName, procedureName, argumentDataTypes, privilege, roles, shares, withGrantOption) + d.SetId(grantID.String()) return ReadProcedureGrant(d, meta) -} +} // ReadProcedureGrant implements schema.ReadFunc. func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseProcedureGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - procedureObjectName := grantID.ObjectName - priv := grantID.Privilege + if !grantID.IsOldID { + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } onFuture := false - var procedureName string - argumentDataTypes := make([]string, 0) - if procedureObjectName == "" { + if grantID.ObjectName == "" { onFuture = true - } else { - procedureName, argumentDataTypes = parseFunctionObjectName(procedureObjectName) } - if err := d.Set("procedure_name", procedureName); err != nil { + if err := d.Set("procedure_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("argument_data_types", argumentDataTypes); err != nil { + if err := d.Set("argument_data_types", grantID.ArgumentDataTypes); err != nil { return err } @@ -238,19 +224,19 @@ func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureProcedureGrant(dbName, schemaName) + builder = snowflake.FutureProcedureGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ProcedureGrant(dbName, schemaName, procedureName, argumentDataTypes) + builder = snowflake.ProcedureGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } return readGenericGrant(d, meta, procedureGrantSchema, builder, onFuture, validProcedurePrivileges) @@ -258,22 +244,19 @@ func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { // DeleteProcedureGrant implements schema.DeleteFunc. func DeleteProcedureGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseProcedureGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName procedureObjectName := grantID.ObjectName onFuture := (procedureObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureProcedureGrant(dbName, schemaName) + builder = snowflake.FutureProcedureGrant(grantID.DatabaseName, grantID.SchemaName) } else { - procedureName, argumentDataTypes := parseFunctionObjectName(procedureObjectName) - builder = snowflake.ProcedureGrant(dbName, schemaName, procedureName, argumentDataTypes) + builder = snowflake.ProcedureGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } return deleteGenericGrant(d, meta, builder) } @@ -296,23 +279,19 @@ func UpdateProcedureGrant(d *schema.ResourceData, meta interface{}) error { if d.HasChange("shares") { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseProcedureGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - procedureObjectName := grantID.ObjectName - onFuture := (procedureObjectName == "") + onFuture := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureProcedureGrant(dbName, schemaName) + builder = snowflake.FutureProcedureGrant(grantID.DatabaseName, grantID.SchemaName) } else { - procedureName, argumentDataTypes := parseFunctionObjectName(procedureObjectName) - builder = snowflake.ProcedureGrant(dbName, schemaName, procedureName, argumentDataTypes) + builder = snowflake.ProcedureGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } // first revoke @@ -323,7 +302,7 @@ func UpdateProcedureGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, sharesToAdd, ); err != nil { return err } @@ -331,3 +310,74 @@ func UpdateProcedureGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadProcedureGrant(d, meta) } + +type ProcedureGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + ArgumentDataTypes []string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewProcedureGrantID(databaseName string, schemaName, objectName string, argumentDataTypes []string, privilege string, roles []string, shares []string, withGrantOption bool) *ProcedureGrantID { + return &ProcedureGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + ArgumentDataTypes: argumentDataTypes, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *ProcedureGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + objectIdentifier := idParts[2] + if idx := strings.Index(objectIdentifier, ")"); idx != -1 { + objectIdentifier = objectIdentifier[0:idx] + } + objectNameParts := strings.Split(objectIdentifier, "(") + + return &ProcedureGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: objectNameParts[0], + ArgumentDataTypes: strings.Split(objectNameParts[1], ","), + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 8 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 8", len(idParts)) + } + return &ProcedureGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + ArgumentDataTypes: strings.Split(idParts[3], ","), + Privilege: idParts[4], + Roles: strings.Split(idParts[5], ","), + Shares: strings.Split(idParts[6], ","), + WithGrantOption: idParts[7] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index 993bda2855..ee30e43588 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -65,63 +68,53 @@ func ResourceMonitorGrant() *TerraformGrantResource { // CreateResourceMonitorGrant implements schema.CreateFunc. func CreateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - w := d.Get("monitor_name").(string) - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) - builder := snowflake.ResourceMonitorGrant(w) + monitorName := d.Get("monitor_name").(string) + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) + builder := snowflake.ResourceMonitorGrant(monitorName) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: w, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewResourceMonitorGrantID(privilege, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadResourceMonitorGrant(d, meta) } // ReadResourceMonitorGrant implements schema.ReadFunc. func ReadResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseResourceMonitorGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - priv := grantID.Privilege - - if err := d.Set("monitor_name", w); err != nil { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("monitor_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - builder := snowflake.ResourceMonitorGrant(w) + builder := snowflake.ResourceMonitorGrant(grantID.ObjectName) return readGenericGrant(d, meta, resourceMonitorGrantSchema, builder, false, validResourceMonitorPrivileges) } // DeleteResourceMonitorGrant implements schema.DeleteFunc. func DeleteResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseResourceMonitorGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - builder := snowflake.ResourceMonitorGrant(w) + builder := snowflake.ResourceMonitorGrant(grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } @@ -141,15 +134,13 @@ func UpdateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseResourceMonitorGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - // create the builder - builder := snowflake.ResourceMonitorGrant(w) + builder := snowflake.ResourceMonitorGrant(grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -159,7 +150,7 @@ func UpdateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -167,3 +158,51 @@ func UpdateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error // Done, refresh state return ReadResourceMonitorGrant(d, meta) } + +type ResourceMonitorGrantID struct { + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewResourceMonitorGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *ResourceMonitorGrantID { + return &ResourceMonitorGrantID{ + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *ResourceMonitorGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &ResourceMonitorGrantID{ + ObjectName: idParts[0], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 4 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 4", len(idParts)) + } + return &ResourceMonitorGrantID{ + ObjectName: idParts[0], + Privilege: idParts[1], + Roles: strings.Split(idParts[2], ","), + WithGrantOption: idParts[3] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go index 3a23e8c7bb..0d53d8f36e 100644 --- a/pkg/resources/role_grants.go +++ b/pkg/resources/role_grants.go @@ -66,16 +66,9 @@ func CreateRoleGrants(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("no users or roles specified for role grants") } - grant := &grantID{ - ResourceName: roleName, - Roles: roles, - } - dataIDInput, err := grant.String() - d.SetId(dataIDInput) + grantID := NewRoleGrantsID(roleName, roles, users) + d.SetId(grantID.String()) - if err != nil { - return fmt.Errorf("error creating role grant err = %w", err) - } for _, role := range roles { if err := grantRoleToRole(db, roleName, role); err != nil { return err @@ -113,20 +106,17 @@ type roleGrant struct { func ReadRoleGrants(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) - log.Println(d.Id()) - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseRoleGrantsID(d.Id()) if err != nil { return err } - roleName := grantID.ResourceName - - tfRoles := expandStringList(d.Get("roles").(*schema.Set).List()) - tfUsers := expandStringList(d.Get("users").(*schema.Set).List()) + tfRoles := d.Get("roles").(*schema.Set).List() + tfUsers := d.Get("users").(*schema.Set).List() roles := make([]string, 0) users := make([]string, 0) - grants, err := readGrants(db, roleName) + grants, err := readGrants(db, grantID.ObjectName) if err != nil { return err } @@ -150,7 +140,7 @@ func ReadRoleGrants(d *schema.ResourceData, meta interface{}) error { } } - if err := d.Set("role_name", roleName); err != nil { + if err := d.Set("role_name", grantID.ObjectName); err != nil { return err } if err := d.Set("roles", roles); err != nil { @@ -303,3 +293,48 @@ func UpdateRoleGrants(d *schema.ResourceData, meta interface{}) error { return ReadRoleGrants(d, meta) } + +type RoleGrantsID struct { + ObjectName string + Roles []string + Users []string + IsOldID bool +} + +func NewRoleGrantsID(objectName string, roles, users []string) *RoleGrantsID { + return &RoleGrantsID{ + ObjectName: objectName, + Roles: roles, + Users: users, + IsOldID: false, + } +} + +func (v *RoleGrantsID) String() string { + roles := strings.Join(v.Roles, ",") + users := strings.Join(v.Users, ",") + return fmt.Sprintf("%v❄️%v❄️%v", v.ObjectName, roles, users) +} + +func parseRoleGrantsID(s string) (*RoleGrantsID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &RoleGrantsID{ + ObjectName: idParts[0], + Roles: strings.Split(idParts[4], ","), + Users: []string{}, + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 4 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 4", len(idParts)) + } + return &RoleGrantsID{ + ObjectName: idParts[0], + Roles: strings.Split(idParts[1], ","), + Users: strings.Split(idParts[2], ","), + IsOldID: false, + }, nil +} diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index c0d5f23994..794576810c 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -84,7 +84,6 @@ func CreateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) - log.Println(d.Id()) onRoleName := strings.Split(d.Id(), "|")[0] currentGrants := strings.Split(d.Id(), "|")[2] diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index 2a74225b44..2300ff3d05 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -84,78 +87,61 @@ func CreateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error if name, ok := d.GetOk("row_access_policy_name"); ok { rowAccessPolicyName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) grantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) - builder := snowflake.RowAccessPolicyGrant(dbName, schemaName, rowAccessPolicyName) + builder := snowflake.RowAccessPolicyGrant(databaseName, schemaName, rowAccessPolicyName) if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: rowAccessPolicyName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewRowAccessPolicyGrantID(databaseName, schemaName, rowAccessPolicyName, privilege, roles, grantOption) + + d.SetId(grantID.String()) return ReadRowAccessPolicyGrant(d, meta) } // ReadRowAccessPolicyGrant implements schema.ReadFunc. func ReadRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseRowAccessPolicyGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - rowAccessPolicyName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } - if err := d.Set("row_access_policy_name", rowAccessPolicyName); err != nil { + if err := d.Set("row_access_policy_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - builder := snowflake.RowAccessPolicyGrant(dbName, schemaName, rowAccessPolicyName) + builder := snowflake.RowAccessPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return readGenericGrant(d, meta, rowAccessPolicyGrantSchema, builder, false, validRowAccessPoilcyPrivileges) } // DeleteRowAccessPolicyGrant implements schema.DeleteFunc. func DeleteRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseRowAccessPolicyGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - rowAccessPolicyName := grantID.ObjectName - builder := snowflake.RowAccessPolicyGrant(dbName, schemaName, rowAccessPolicyName) + builder := snowflake.RowAccessPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } @@ -175,17 +161,13 @@ func UpdateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseRowAccessPolicyGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - rowAccessPolicyName := grantID.ObjectName - // create the builder - builder := snowflake.RowAccessPolicyGrant(dbName, schemaName, rowAccessPolicyName) + builder := snowflake.RowAccessPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -195,7 +177,7 @@ func UpdateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -203,3 +185,59 @@ func UpdateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error // Done, refresh state return ReadRowAccessPolicyGrant(d, meta) } + +type RowAccessPolicyGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewRowAccessPolicyGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *RowAccessPolicyGrantID { + return &RowAccessPolicyGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *RowAccessPolicyGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseRowAccessPolicyGrantID(s string) (*RowAccessPolicyGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &RowAccessPolicyGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &RowAccessPolicyGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go index 69687e92b5..e0d20dbb4b 100644 --- a/pkg/resources/schema_grant.go +++ b/pkg/resources/schema_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -112,14 +114,13 @@ func CreateSchemaGrant(d *schema.ResourceData, meta interface{}) error { var schemaName string if _, ok := d.GetOk("schema_name"); ok { schemaName = d.Get("schema_name").(string) - } else { - schemaName = "" } - db := d.Get("database_name").(string) - priv := d.Get("privilege").(string) + databaseName := d.Get("database_name").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (schemaName == "") && !onFuture { return errors.New("schema_name must be set unless on_future is true") @@ -127,27 +128,17 @@ func CreateSchemaGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSchemaGrant(db) + builder = snowflake.FutureSchemaGrant(databaseName) } else { - builder = snowflake.SchemaGrant(db, schemaName) + builder = snowflake.SchemaGrant(databaseName, schemaName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grantID := &grantID{ - ResourceName: db, - SchemaName: schemaName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grantID.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewSchemaGrantID(databaseName, schemaName, privilege, roles, shares, withGrantOption) + d.SetId(grantID.String()) return ReadSchemaGrant(d, meta) } @@ -171,21 +162,19 @@ func UpdateSchemaGrant(d *schema.ResourceData, meta interface{}) error { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseSchemaGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName onFuture := d.Get("on_future").(bool) // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSchemaGrant(dbName) + builder = snowflake.FutureSchemaGrant(grantID.DatabaseName) } else { - builder = snowflake.SchemaGrant(dbName, schemaName) + builder = snowflake.SchemaGrant(grantID.DatabaseName, grantID.SchemaName) } // first revoke @@ -204,7 +193,7 @@ func UpdateSchemaGrant(d *schema.ResourceData, meta interface{}) error { meta, builder, grantID.Privilege, - grantID.GrantOption, + grantID.WithGrantOption, rolesToAdd, sharesToAdd, ); err != nil { @@ -217,21 +206,28 @@ func UpdateSchemaGrant(d *schema.ResourceData, meta interface{}) error { // ReadSchemaGrant implements schema.ReadFunc. func ReadSchemaGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseSchemaGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - if err := d.Set("database_name", dbName); err != nil { + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } onFuture := false - if schemaName == "" { + if grantID.SchemaName == "" { onFuture = true } if err := d.Set("on_future", onFuture); err != nil { @@ -240,38 +236,93 @@ func ReadSchemaGrant(d *schema.ResourceData, meta interface{}) error { if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSchemaGrant(dbName) + builder = snowflake.FutureSchemaGrant(grantID.DatabaseName) } else { - builder = snowflake.SchemaGrant(dbName, schemaName) + builder = snowflake.SchemaGrant(grantID.DatabaseName, grantID.SchemaName) } return readGenericGrant(d, meta, schemaGrantSchema, builder, onFuture, validSchemaPrivileges) } // DeleteSchemaGrant implements schema.DeleteFunc. func DeleteSchemaGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseSchemaGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName onFuture := false - if schemaName == "" { + if grantID.SchemaName == "" { onFuture = true } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSchemaGrant(dbName) + builder = snowflake.FutureSchemaGrant(grantID.DatabaseName) } else { - builder = snowflake.SchemaGrant(dbName, schemaName) + builder = snowflake.SchemaGrant(grantID.DatabaseName, grantID.SchemaName) } return deleteGenericGrant(d, meta, builder) } + +type SchemaGrantID struct { + DatabaseName string + SchemaName string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewSchemaGrantID(databaseName string, schemaName, privilege string, roles []string, shares []string, withGrantOption bool) *SchemaGrantID { + return &SchemaGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *SchemaGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseSchemaGrantID(s string) (*SchemaGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &SchemaGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &SchemaGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + Privilege: idParts[2], + Roles: strings.Split(idParts[3], ","), + Shares: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go index 9506a9ed77..92c59fa467 100644 --- a/pkg/resources/sequence_grant.go +++ b/pkg/resources/sequence_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -93,11 +95,11 @@ func CreateSequenceGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("sequence_name"); ok { sequenceName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if (sequenceName == "") && !onFuture { @@ -112,71 +114,62 @@ func CreateSequenceGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSequenceGrant(dbName, schemaName) + builder = snowflake.FutureSequenceGrant(databaseName, schemaName) } else { - builder = snowflake.SequenceGrant(dbName, schemaName, sequenceName) + builder = snowflake.SequenceGrant(databaseName, schemaName, sequenceName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: sequenceName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewSequenceGrantID(databaseName, schemaName, sequenceName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadSequenceGrant(d, meta) } // ReadSequenceGrant implements schema.ReadFunc. func ReadSequenceGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseSequenceGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - sequenceName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } onFuture := false - if sequenceName == "" { + if grantID.ObjectName == "" { onFuture = true } - if err := d.Set("sequence_name", sequenceName); err != nil { + if err := d.Set("sequence_name", grantID.ObjectName); err != nil { return err } if err := d.Set("on_future", onFuture); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSequenceGrant(dbName, schemaName) + builder = snowflake.FutureSequenceGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.SequenceGrant(dbName, schemaName, sequenceName) + builder = snowflake.SequenceGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, sequenceGrantSchema, builder, onFuture, validSequencePrivileges) @@ -184,21 +177,18 @@ func ReadSequenceGrant(d *schema.ResourceData, meta interface{}) error { // DeleteSequenceGrant implements schema.DeleteFunc. func DeleteSequenceGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseSequenceGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - sequenceName := grantID.ObjectName - onFuture := (sequenceName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSequenceGrant(dbName, schemaName) + builder = snowflake.FutureSequenceGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.SequenceGrant(dbName, schemaName, sequenceName) + builder = snowflake.SequenceGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -218,21 +208,18 @@ func UpdateSequenceGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseSequenceGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - sequenceName := grantID.ObjectName - onFuture := (sequenceName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureSequenceGrant(dbName, schemaName) + builder = snowflake.FutureSequenceGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.SequenceGrant(dbName, schemaName, sequenceName) + builder = snowflake.SequenceGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -243,7 +230,7 @@ func UpdateSequenceGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -251,3 +238,59 @@ func UpdateSequenceGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadSequenceGrant(d, meta) } + +type SequenceGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewSequenceGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *SequenceGrantID { + return &SequenceGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *SequenceGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseSequenceGrantID(s string) (*SequenceGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &SequenceGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &SequenceGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go index 620220fd3d..78774c3383 100644 --- a/pkg/resources/stage_grant.go +++ b/pkg/resources/stage_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -94,19 +96,16 @@ func StageGrant() *TerraformGrantResource { // CreateStageGrant implements schema.CreateFunc. func CreateStageGrant(d *schema.ResourceData, meta interface{}) error { - var ( - schemaName string - stageName string - ) - - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) onFuture := d.Get("on_future").(bool) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) grantOption := d.Get("with_grant_option").(bool) + var schemaName string if name, ok := d.GetOk("schema_name"); ok { schemaName = name.(string) } + var stageName string if name, ok := d.GetOk("stage_name"); ok { stageName = name.(string) } @@ -120,69 +119,60 @@ func CreateStageGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStageGrant(dbName, schemaName) + builder = snowflake.FutureStageGrant(databaseName, schemaName) } else { - builder = snowflake.StageGrant(dbName, schemaName, stageName) + builder = snowflake.StageGrant(databaseName, schemaName, stageName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: stageName, - Privilege: priv, - GrantOption: grantOption, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + roles := expandStringList( d.Get("roles").(*schema.Set).List()) + grantID := NewStageGrantID(databaseName, schemaName, stageName, privilege, roles, grantOption) + d.SetId(grantID.String()) return ReadStageGrant(d, meta) } // ReadStageGrant implements schema.ReadFunc. func ReadStageGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseStageGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - stageName := grantID.ObjectName - priv := grantID.Privilege + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + } - onFuture := (stageName == "") + onFuture := (grantID.ObjectName == "") - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } if err := d.Set("on_future", onFuture); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } - if err := d.Set("stage_name", stageName); err != nil { + if err := d.Set("stage_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStageGrant(dbName, schemaName) + builder = snowflake.FutureStageGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.StageGrant(dbName, schemaName, stageName) + builder = snowflake.StageGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, stageGrantSchema, builder, onFuture, validStagePrivileges) @@ -196,16 +186,12 @@ func UpdateStageGrant(d *schema.ResourceData, meta interface{}) error { return nil } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseStageGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - stageName := grantID.ObjectName - - onFuture := (stageName == "") + onFuture := (grantID.ObjectName == "") rolesToAdd := []string{} rolesToRevoke := []string{} @@ -216,9 +202,9 @@ func UpdateStageGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStageGrant(dbName, schemaName) + builder = snowflake.FutureStageGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.StageGrant(dbName, schemaName, stageName) + builder = snowflake.StageGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -229,7 +215,7 @@ func UpdateStageGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -240,23 +226,75 @@ func UpdateStageGrant(d *schema.ResourceData, meta interface{}) error { // DeleteStageGrant implements schema.DeleteFunc. func DeleteStageGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseStageGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - stageName := grantID.ObjectName - - onFuture := (stageName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStageGrant(dbName, schemaName) + builder = snowflake.FutureStageGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.StageGrant(dbName, schemaName, stageName) + builder = snowflake.StageGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } + +type StageGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewStageGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *StageGrantID { + return &StageGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *StageGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseStageGrantID(s string) (*StageGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &StageGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &StageGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go index 6983c4d532..44aa88ace9 100644 --- a/pkg/resources/stream_grant.go +++ b/pkg/resources/stream_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -93,11 +95,11 @@ func CreateStreamGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("stream_name"); ok { streamName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if (streamName == "") && !onFuture { @@ -112,56 +114,41 @@ func CreateStreamGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStreamGrant(dbName, schemaName) + builder = snowflake.FutureStreamGrant(databaseName, schemaName) } else { - builder = snowflake.StreamGrant(dbName, schemaName, streamName) + builder = snowflake.StreamGrant(databaseName, schemaName, streamName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: streamName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewStreamGrantID(databaseName, schemaName, streamName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadStreamGrant(d, meta) } // ReadStreamGrant implements schema.ReadFunc. func ReadStreamGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseStreamGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - streamName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } onFuture := false - if streamName == "" { + if grantID.ObjectName == "" { onFuture = true } - if err := d.Set("stream_name", streamName); err != nil { + if err := d.Set("stream_name", grantID.ObjectName); err != nil { return err } @@ -169,19 +156,19 @@ func ReadStreamGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStreamGrant(dbName, schemaName) + builder = snowflake.FutureStreamGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.StreamGrant(dbName, schemaName, streamName) + builder = snowflake.StreamGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, streamGrantSchema, builder, onFuture, validStreamPrivileges) @@ -189,21 +176,18 @@ func ReadStreamGrant(d *schema.ResourceData, meta interface{}) error { // DeleteStreamGrant implements schema.DeleteFunc. func DeleteStreamGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseStreamGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - streamName := grantID.ObjectName - onFuture := (streamName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStreamGrant(dbName, schemaName) + builder = snowflake.FutureStreamGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.StreamGrant(dbName, schemaName, streamName) + builder = snowflake.StreamGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -223,22 +207,18 @@ func UpdateStreamGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseStreamGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - streamName := grantID.ObjectName - - onFuture := (streamName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureStreamGrant(dbName, schemaName) + builder = snowflake.FutureStreamGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.StreamGrant(dbName, schemaName, streamName) + builder = snowflake.StreamGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -249,7 +229,7 @@ func UpdateStreamGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -257,3 +237,55 @@ func UpdateStreamGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadStreamGrant(d, meta) } + +type StreamGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool +} + +func NewStreamGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *StreamGrantID { + return &StreamGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + } +} + +func (v *StreamGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseStreamGrantID(s string) (*StreamGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &StreamGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &StreamGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + }, nil +} diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go index 89804e6d4b..4979111eab 100644 --- a/pkg/resources/table_grant.go +++ b/pkg/resources/table_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -101,26 +103,20 @@ func TableGrant() *TerraformGrantResource { // CreateTableGrant implements schema.CreateFunc. func CreateTableGrant(d *schema.ResourceData, meta interface{}) error { - var ( - tableName string - schemaName string - ) + var tableName string if _, ok := d.GetOk("table_name"); ok { tableName = d.Get("table_name").(string) - } else { - tableName = "" } + var schemaName string if _, ok := d.GetOk("schema_name"); ok { schemaName = d.Get("schema_name").(string) - } else { - schemaName = "" } - dbName := d.Get("database_name").(string) - priv := d.Get("privilege").(string) + databaseName := d.Get("database_name").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) - + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (schemaName == "") && !onFuture { return errors.New("schema_name must be set unless on_future is true") } @@ -131,75 +127,64 @@ func CreateTableGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTableGrant(dbName, schemaName) + builder = snowflake.FutureTableGrant(databaseName, schemaName) } else { - builder = snowflake.TableGrant(dbName, schemaName, tableName) + builder = snowflake.TableGrant(databaseName, schemaName, tableName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - // table_name is empty when on_future = true - grantID := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - if !onFuture { - grantID.ObjectName = tableName - } - - dataIDInput, err := grantID.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewTableGrantID(databaseName, schemaName, tableName, privilege, roles, shares,withGrantOption) + d.SetId(grantID.String()) return ReadTableGrant(d, meta) } // ReadTableGrant implements schema.ReadFunc. func ReadTableGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTableGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - tableName := grantID.ObjectName - priv := grantID.Privilege + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } - if err := d.Set("database_name", dbName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } onFuture := false - if tableName == "" { + if grantID.ObjectName == "" { onFuture = true } - if err := d.Set("table_name", tableName); err != nil { + if err := d.Set("table_name", grantID.ObjectName); err != nil { return err } if err := d.Set("on_future", onFuture); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTableGrant(dbName, schemaName) + builder = snowflake.FutureTableGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.TableGrant(dbName, schemaName, tableName) + builder = snowflake.TableGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, tableGrantSchema, builder, onFuture, validTablePrivileges) @@ -207,24 +192,21 @@ func ReadTableGrant(d *schema.ResourceData, meta interface{}) error { // DeleteTableGrant implements schema.DeleteFunc. func DeleteTableGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTableGrantID(d.Id()) if err != nil { return err } - tableName := grantID.ObjectName - dbName := grantID.ResourceName - schemaName := grantID.SchemaName onFuture := false - if tableName == "" { + if grantID.ObjectName == "" { onFuture = true } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTableGrant(dbName, schemaName) + builder = snowflake.FutureTableGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.TableGrant(dbName, schemaName, tableName) + builder = snowflake.TableGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -258,22 +240,19 @@ func UpdateTableGrant(d *schema.ResourceData, meta interface{}) error { sharesToAdd, sharesToRevoke = difference("shares") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTableGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - tableName := grantID.ObjectName - onFuture := (tableName == "") + onFuture := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTableGrant(dbName, schemaName) + builder = snowflake.FutureTableGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.TableGrant(dbName, schemaName, tableName) + builder = snowflake.TableGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -292,7 +271,7 @@ func UpdateTableGrant(d *schema.ResourceData, meta interface{}) error { meta, builder, grantID.Privilege, - grantID.GrantOption, + grantID.WithGrantOption, rolesToAdd, sharesToAdd, ); err != nil { @@ -302,3 +281,64 @@ func UpdateTableGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadTableGrant(d, meta) } + +type TableGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewTableGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, shares []string, withGrantOption bool) *TableGrantID { + return &TableGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *TableGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseTableGrantID(s string) (*TableGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &TableGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 7 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 7", len(idParts)) + } + return &TableGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: strings.Split(idParts[5], ","), + WithGrantOption: idParts[6] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go index eadb281058..7627f11a9e 100644 --- a/pkg/resources/tag_grant.go +++ b/pkg/resources/tag_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -81,67 +84,58 @@ func TagGrant() *TerraformGrantResource { // CreateTagGrant implements schema.CreateFunc. func CreateTagGrant(d *schema.ResourceData, meta interface{}) error { tagName := d.Get("tag_name").(string) - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) grantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) - builder := snowflake.TagGrant(dbName, schemaName, tagName) + builder := snowflake.TagGrant(databaseName, schemaName, tagName) if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: tagName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewTagGrantID(databaseName, schemaName, tagName, privilege, roles, grantOption) + d.SetId(grantID.String()) return ReadTagGrant(d, meta) } // ReadTagGrant implements schema.ReadFunc. func ReadTagGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTagGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - tagName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } - if err := d.Set("tag_name", tagName); err != nil { + if err := d.Set("tag_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - builder := snowflake.TagGrant(dbName, schemaName, tagName) + builder := snowflake.TagGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return readGenericGrant(d, meta, tagGrantSchema, builder, false, validTagPrivileges) } @@ -156,16 +150,13 @@ func UpdateTagGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTagGrantID(d.Id()) if err != nil { return err } // create the builder - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - tagName := grantID.ObjectName - builder := snowflake.TagGrant(dbName, schemaName, tagName) + builder := snowflake.TagGrant( grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -183,7 +174,7 @@ func UpdateTagGrant(d *schema.ResourceData, meta interface{}) error { meta, builder, grantID.Privilege, - grantID.GrantOption, + grantID.WithGrantOption, rolesToAdd, nil, ); err != nil { @@ -195,15 +186,68 @@ func UpdateTagGrant(d *schema.ResourceData, meta interface{}) error { // DeleteTagGrant implements schema.DeleteFunc. func DeleteTagGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTagGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - tagName := grantID.ObjectName - builder := snowflake.TagGrant(dbName, schemaName, tagName) + builder := snowflake.TagGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } + +type TagGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewTagGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *TagGrantID { + return &TagGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *TagGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseTagGrantID(s string) (*TagGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &TagGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &TagGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go index 59b0b60fad..8534cea55f 100644 --- a/pkg/resources/task_grant.go +++ b/pkg/resources/task_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -94,11 +96,11 @@ func CreateTaskGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("task_name"); ok { taskName = name.(string) } - dbName := d.Get("database_name").(string) + databaseName := d.Get("database_name").(string) schemaName := d.Get("schema_name").(string) - priv := d.Get("privilege").(string) + privilege := d.Get("privilege").(string) onFuture := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if (taskName == "") && !onFuture { @@ -113,56 +115,47 @@ func CreateTaskGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTaskGrant(dbName, schemaName) + builder = snowflake.FutureTaskGrant(databaseName, schemaName) } else { - builder = snowflake.TaskGrant(dbName, schemaName, taskName) + builder = snowflake.TaskGrant(databaseName, schemaName, taskName) } if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: taskName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewTaskGrantID(databaseName, schemaName, taskName, privilege,roles, withGrantOption) + d.SetId(grantID.String()) return ReadTaskGrant(d, meta) } // ReadTaskGrant implements schema.ReadFunc. func ReadTaskGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTaskGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - taskName := grantID.ObjectName - priv := grantID.Privilege - if err := d.Set("database_name", dbName); err != nil { + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - if err := d.Set("schema_name", schemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } onFuture := false - if taskName == "" { + if grantID.ObjectName == "" { onFuture = true } - if err := d.Set("task_name", taskName); err != nil { + if err := d.Set("task_name", grantID.ObjectName); err != nil { return err } @@ -170,19 +163,19 @@ func ReadTaskGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTaskGrant(dbName, schemaName) + builder = snowflake.FutureTaskGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.TaskGrant(dbName, schemaName, taskName) + builder = snowflake.TaskGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, taskGrantSchema, builder, onFuture, validTaskPrivileges) @@ -190,21 +183,18 @@ func ReadTaskGrant(d *schema.ResourceData, meta interface{}) error { // DeleteTaskGrant implements schema.DeleteFunc. func DeleteTaskGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTaskGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - taskName := grantID.ObjectName - onFuture := (taskName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTaskGrant(dbName, schemaName) + builder = snowflake.FutureTaskGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.TaskGrant(dbName, schemaName, taskName) + builder = snowflake.TaskGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -224,21 +214,18 @@ func UpdateTaskGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke = changeDiff(d, "roles") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseTaskGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - taskName := grantID.ObjectName - onFuture := (taskName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FutureTaskGrant(dbName, schemaName) + builder = snowflake.FutureTaskGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.TaskGrant(dbName, schemaName, taskName) + builder = snowflake.TaskGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -249,7 +236,7 @@ func UpdateTaskGrant(d *schema.ResourceData, meta interface{}) error { } // then add if err := createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}, + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, []string{}, ); err != nil { return err } @@ -257,3 +244,59 @@ func UpdateTaskGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadTaskGrant(d, meta) } + +type TaskGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewTaskGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *TaskGrantID { + return &TaskGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *TaskGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseTaskGrantID(s string) (*TaskGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &TaskGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 6 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 6", len(idParts)) + } + return &TaskGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/user_grant.go b/pkg/resources/user_grant.go index 818c4c0c36..86bcd9d402 100644 --- a/pkg/resources/user_grant.go +++ b/pkg/resources/user_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -67,66 +70,60 @@ func UserGrant() *TerraformGrantResource { // CreateUserGrant implements schema.CreateFunc. func CreateUserGrant(d *schema.ResourceData, meta interface{}) error { - w := d.Get("user_name").(string) - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) - builder := snowflake.UserGrant(w) + userName := d.Get("user_name").(string) + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) + builder := snowflake.UserGrant(userName) roles := expandStringList(d.Get("roles").(*schema.Set).List()) if err := createGenericGrant(d, meta, builder); err != nil { return err } - grant := &grantID{ - ResourceName: w, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewUserGrantID(userName, privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadUserGrant(d, meta) } // ReadUserGrant implements schema.ReadFunc. func ReadUserGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseUserGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - priv := grantID.Privilege - if err := d.Set("user_name", w); err != nil { + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + } + + if err := d.Set("user_name", grantID.ObjectName); err != nil { return err } - if err := d.Set("privilege", priv); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } - if err := d.Set("with_grant_option", grantID.GrantOption); err != nil { + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { return err } - builder := snowflake.UserGrant(w) + builder := snowflake.UserGrant(grantID.ObjectName) return readGenericGrant(d, meta, userGrantSchema, builder, false, validUserPrivileges) } // DeleteUserGrant implements schema.DeleteFunc. func DeleteUserGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseUserGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - builder := snowflake.UserGrant(w) + builder := snowflake.UserGrant(grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } @@ -141,13 +138,13 @@ func UpdateUserGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseUserGrantID(d.Id()) if err != nil { return err } // create the builder - builder := snowflake.UserGrant(grantID.ResourceName) + builder := snowflake.UserGrant(grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -165,7 +162,7 @@ func UpdateUserGrant(d *schema.ResourceData, meta interface{}) error { meta, builder, grantID.Privilege, - grantID.GrantOption, + grantID.WithGrantOption, rolesToAdd, nil, ); err != nil { @@ -175,3 +172,50 @@ func UpdateUserGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadUserGrant(d, meta) } + +type UserGrantID struct { + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewUserGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *UserGrantID { + return &UserGrantID{ + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + } +} + +func (v *UserGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseUserGrantID(s string) (*UserGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &UserGrantID{ + ObjectName: idParts[0], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 4 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 4", len(idParts)) + } + return &UserGrantID{ + ObjectName: idParts[0], + Privilege: idParts[1], + Roles: strings.Split(idParts[2], ","), + WithGrantOption: idParts[3] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go index 4f903def5a..c7bced14ea 100644 --- a/pkg/resources/view_grant.go +++ b/pkg/resources/view_grant.go @@ -2,6 +2,8 @@ package resources import ( "errors" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -96,26 +98,20 @@ func ViewGrant() *TerraformGrantResource { // CreateViewGrant implements schema.CreateFunc. func CreateViewGrant(d *schema.ResourceData, meta interface{}) error { - var ( - viewName string - schemaName string - ) + var viewName string if _, ok := d.GetOk("view_name"); ok { viewName = d.Get("view_name").(string) - } else { - viewName = "" } + var schemaName string if _, ok := d.GetOk("schema_name"); ok { schemaName = d.Get("schema_name").(string) - } else { - schemaName = "" } - dbName := d.Get("database_name").(string) - priv := d.Get("privilege").(string) + databaseName := d.Get("database_name").(string) + privilege := d.Get("privilege").(string) futureViews := d.Get("on_future").(bool) - grantOption := d.Get("with_grant_option").(bool) + withGrantOption := d.Get("with_grant_option").(bool) roles := expandStringList(d.Get("roles").(*schema.Set).List()) - + shares := expandStringList(d.Get("shares").(*schema.Set).List()) if (schemaName == "") && !futureViews { return errors.New("schema_name must be set unless on_future is true") } @@ -128,9 +124,9 @@ func CreateViewGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if futureViews { - builder = snowflake.FutureViewGrant(dbName, schemaName) + builder = snowflake.FutureViewGrant(databaseName, schemaName) } else { - builder = snowflake.ViewGrant(dbName, schemaName, viewName) + builder = snowflake.ViewGrant(databaseName, schemaName, viewName) } err := createGenericGrant(d, meta, builder) @@ -138,47 +134,41 @@ func CreateViewGrant(d *schema.ResourceData, meta interface{}) error { return err } - grant := &grantID{ - ResourceName: dbName, - SchemaName: schemaName, - ObjectName: viewName, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewViewGrantID(databaseName, schemaName, viewName, privilege, roles, shares, withGrantOption) + d.SetId(grantID.String()) return ReadViewGrant(d, meta) } // ReadViewGrant implements schema.ReadFunc. func ReadViewGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseViewGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - viewName := grantID.ObjectName - priv := grantID.Privilege - err = d.Set("database_name", dbName) - if err != nil { + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } + + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } - err = d.Set("schema_name", schemaName) - if err != nil { + + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } + futureViewsEnabled := false - if viewName == "" { + if grantID.ObjectName == "" { futureViewsEnabled = true } - err = d.Set("view_name", viewName) + err = d.Set("view_name", grantID.ObjectName) if err != nil { return err } @@ -186,20 +176,20 @@ func ReadViewGrant(d *schema.ResourceData, meta interface{}) error { if err != nil { return err } - err = d.Set("privilege", priv) + err = d.Set("privilege", grantID.Privilege) if err != nil { return err } - err = d.Set("with_grant_option", grantID.GrantOption) + err = d.Set("with_grant_option", grantID.WithGrantOption) if err != nil { return err } var builder snowflake.GrantBuilder if futureViewsEnabled { - builder = snowflake.FutureViewGrant(dbName, schemaName) + builder = snowflake.FutureViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ViewGrant(dbName, schemaName, viewName) + builder = snowflake.ViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, viewGrantSchema, builder, futureViewsEnabled, validViewPrivileges) @@ -207,21 +197,18 @@ func ReadViewGrant(d *schema.ResourceData, meta interface{}) error { // DeleteViewGrant implements schema.DeleteFunc. func DeleteViewGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseViewGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - viewName := grantID.ObjectName - futureViews := (viewName == "") + futureViews := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if futureViews { - builder = snowflake.FutureViewGrant(dbName, schemaName) + builder = snowflake.FutureViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ViewGrant(dbName, schemaName, viewName) + builder = snowflake.ViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -244,22 +231,19 @@ func UpdateViewGrant(d *schema.ResourceData, meta interface{}) error { if d.HasChange("shares") { sharesToAdd, sharesToRevoke = changeDiff(d, "shares") } - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseViewGrantID(d.Id()) if err != nil { return err } - dbName := grantID.ResourceName - schemaName := grantID.SchemaName - viewName := grantID.ObjectName - futureViews := (viewName == "") + futureViews := (grantID.ObjectName == "") // create the builder var builder snowflake.GrantBuilder if futureViews { - builder = snowflake.FutureViewGrant(dbName, schemaName) + builder = snowflake.FutureViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ViewGrant(dbName, schemaName, viewName) + builder = snowflake.ViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } // first revoke @@ -270,7 +254,7 @@ func UpdateViewGrant(d *schema.ResourceData, meta interface{}) error { } // then add err = createGenericGrantRolesAndShares( - meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd) + meta, builder, grantID.Privilege, grantID.WithGrantOption, rolesToAdd, sharesToAdd) if err != nil { return err } @@ -278,3 +262,64 @@ func UpdateViewGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadViewGrant(d, meta) } + +type ViewGrantID struct { + DatabaseName string + SchemaName string + ObjectName string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewViewGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, shares []string, withGrantOption bool) *ViewGrantID { + return &ViewGrantID{ + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *ViewGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) +} + +func parseViewGrantID(s string) (*ViewGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &ViewGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 7 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 7", len(idParts)) + } + return &ViewGrantID{ + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: strings.Split(idParts[5], ","), + WithGrantOption: idParts[6] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go index 0b36f5c7f8..e0139e9637 100644 --- a/pkg/resources/warehouse_grant.go +++ b/pkg/resources/warehouse_grant.go @@ -1,6 +1,9 @@ package resources import ( + "fmt" + "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -60,7 +63,6 @@ func WarehouseGrant() *TerraformGrantResource { Update: UpdateWarehouseGrant, Schema: warehouseGrantSchema, - // FIXME - tests for this don't currently work Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -71,10 +73,10 @@ func WarehouseGrant() *TerraformGrantResource { // CreateWarehouseGrant implements schema.CreateFunc. func CreateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - w := d.Get("warehouse_name").(string) - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) - builder := snowflake.WarehouseGrant(w) + warehouseName := d.Get("warehouse_name").(string) + privilege := d.Get("privilege").(string) + withGrantOption := d.Get("with_grant_option").(bool) + builder := snowflake.WarehouseGrant(warehouseName) roles := expandStringList(d.Get("roles").(*schema.Set).List()) err := createGenericGrant(d, meta, builder) @@ -82,57 +84,52 @@ func CreateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { return err } - grant := &grantID{ - ResourceName: w, - Privilege: priv, - GrantOption: grantOption, - Roles: roles, - } - dataIDInput, err := grant.String() - if err != nil { - return err - } - d.SetId(dataIDInput) + grantID := NewWarehouseGrantID(warehouseName, privilege, roles, withGrantOption) + + d.SetId(grantID.String()) return ReadWarehouseGrant(d, meta) } // ReadWarehouseGrant implements schema.ReadFunc. func ReadWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseWarehouseGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - priv := grantID.Privilege - err = d.Set("warehouse_name", w) + if !grantID.IsOldID { + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + } + + err = d.Set("warehouse_name", grantID.ObjectName) if err != nil { return err } - err = d.Set("privilege", priv) + err = d.Set("privilege", grantID.Privilege) if err != nil { return err } - err = d.Set("with_grant_option", grantID.GrantOption) + err = d.Set("with_grant_option", grantID.WithGrantOption) if err != nil { return err } - builder := snowflake.WarehouseGrant(w) + builder := snowflake.WarehouseGrant(grantID.ObjectName) return readGenericGrant(d, meta, warehouseGrantSchema, builder, false, validWarehousePrivileges) } // DeleteWarehouseGrant implements schema.DeleteFunc. func DeleteWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseWarehouseGrantID(d.Id()) if err != nil { return err } - w := grantID.ResourceName - builder := snowflake.WarehouseGrant(w) + builder := snowflake.WarehouseGrant(grantID.ObjectName) return deleteGenericGrant(d, meta, builder) } @@ -147,13 +144,13 @@ func UpdateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - grantID, err := grantIDFromString(d.Id()) + grantID, err := parseWarehouseGrantID(d.Id()) if err != nil { return err } // create the builder - builder := snowflake.WarehouseGrant(grantID.ResourceName) + builder := snowflake.WarehouseGrant(grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -171,7 +168,7 @@ func UpdateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { meta, builder, grantID.Privilege, - grantID.GrantOption, + grantID.WithGrantOption, rolesToAdd, nil, ); err != nil { @@ -181,3 +178,51 @@ func UpdateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadWarehouseGrant(d, meta) } + +type WarehouseGrantID struct { + ObjectName string + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewWarehouseGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *WarehouseGrantID { + return &WarehouseGrantID{ + ObjectName: objectName, + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *WarehouseGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) +} + +func parseWarehouseGrantID(s string) (*WarehouseGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &WarehouseGrantID{ + ObjectName: idParts[0], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 4 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 4", len(idParts)) + } + return &WarehouseGrantID{ + ObjectName: idParts[0], + Privilege: idParts[1], + Roles: strings.Split(idParts[2], ","), + WithGrantOption: idParts[3] == "true", + IsOldID: false, + }, nil +} From 01468806d3f4c360792cfbc0d86e2ea8060150e4 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:17:25 -0800 Subject: [PATCH 05/26] revise grant id --- pkg/resources/account_grant.go | 15 ++++- pkg/resources/database_grant.go | 1 + pkg/resources/file_format_grant.go | 2 +- pkg/resources/function_grant.go | 70 ++++++++++++------------ pkg/resources/integration_grant.go | 8 +-- pkg/resources/masking_policy_grant.go | 12 ++-- pkg/resources/materialized_view_grant.go | 8 +-- pkg/resources/pipe_grant.go | 20 +++---- pkg/resources/procedure_grant.go | 70 ++++++++++++------------ pkg/resources/resource_monitor_grant.go | 8 +-- pkg/resources/role_grants.go | 8 +-- pkg/resources/row_access_policy_grant.go | 10 ++-- pkg/resources/schema_grant.go | 12 ++-- pkg/resources/sequence_grant.go | 8 +-- pkg/resources/stage_grant.go | 12 ++-- pkg/resources/table_grant.go | 12 ++-- pkg/resources/tag_grant.go | 14 ++--- pkg/resources/task_grant.go | 10 ++-- pkg/resources/user_grant.go | 4 +- pkg/resources/view_grant.go | 14 ++--- pkg/resources/warehouse_grant.go | 4 +- 21 files changed, 166 insertions(+), 156 deletions(-) diff --git a/pkg/resources/account_grant.go b/pkg/resources/account_grant.go index 4329d86dac..053727904c 100644 --- a/pkg/resources/account_grant.go +++ b/pkg/resources/account_grant.go @@ -91,9 +91,18 @@ func AccountGrant() *TerraformGrantResource { return nil, err } id := v.(AccountGrantID) - d.Set("privilege", id.Privilege) - d.Set("roles", id.Roles) - d.Set("with_grant_option", id.WithGrantOption) + err = d.Set("privilege", id.Privilege) + if err != nil { + return nil, err + } + err = d.Set("roles", id.Roles) + if err != nil { + return nil, err + } + err = d.Set("with_grant_option", id.WithGrantOption) + if err != nil { + return nil, err + } d.SetId(helpers.RandomSnowflakeID()) return []*schema.ResourceData{d}, nil }, diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index 44b3a2aec2..b816535b58 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -3,6 +3,7 @@ package resources import ( "context" "fmt" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index 6fe870871c..3c7956e16d 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -178,7 +178,7 @@ func DeleteFileFormatGrant(d *schema.ResourceData, meta interface{}) error { return err } - onFuture := ( grantID.ObjectName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index eb668d11eb..e6e10d4c10 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -179,7 +179,7 @@ func CreateFunctionGrant(d *schema.ResourceData, meta interface{}) error { return err } - grantID := NewFunctionGrantID(databaseName, schemaName, functionName,argumentDataTypes, privilege, roles, shares, withGrantOption) + grantID := NewFunctionGrantID(databaseName, schemaName, functionName, argumentDataTypes, privilege, roles, shares, withGrantOption) d.SetId(grantID.String()) return ReadFunctionGrant(d, meta) } @@ -213,7 +213,7 @@ func ReadFunctionGrant(d *schema.ResourceData, meta interface{}) error { onFuture := false if grantID.ObjectName == "" { onFuture = true - } + } if err := d.Set("function_name", grantID.ObjectName); err != nil { return err } @@ -281,7 +281,7 @@ func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { if onFuture { builder = snowflake.FutureFunctionGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.FunctionGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) + builder = snowflake.FunctionGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName, grantID.ArgumentDataTypes) } // first revoke @@ -302,28 +302,28 @@ func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { } type FunctionGrantID struct { - DatabaseName string - SchemaName string - ObjectName string + DatabaseName string + SchemaName string + ObjectName string ArgumentDataTypes []string - Privilege string - Roles []string - Shares []string - WithGrantOption bool - IsOldID bool + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool } func NewFunctionGrantID(databaseName string, schemaName, objectName string, argumentDataTypes []string, privilege string, roles []string, shares []string, withGrantOption bool) *FunctionGrantID { return &FunctionGrantID{ - DatabaseName: databaseName, - SchemaName: schemaName, - ObjectName: objectName, + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, ArgumentDataTypes: argumentDataTypes, - Privilege: privilege, - Roles: roles, - Shares: shares, - WithGrantOption: withGrantOption, - IsOldID: false, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, } } @@ -344,15 +344,15 @@ func parseFunctionGrantID(s string) (*FunctionGrantID, error) { objectNameParts := strings.Split(objectIdentifier, "(") return &FunctionGrantID{ - DatabaseName: idParts[0], - SchemaName: idParts[1], - ObjectName: objectNameParts[0], + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: objectNameParts[0], ArgumentDataTypes: strings.Split(objectNameParts[1], ","), - Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), - Shares: []string{}, - WithGrantOption: idParts[5] == "true", - IsOldID: true, + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -360,14 +360,14 @@ func parseFunctionGrantID(s string) (*FunctionGrantID, error) { return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 8", len(idParts)) } return &FunctionGrantID{ - DatabaseName: idParts[0], - SchemaName: idParts[1], - ObjectName: idParts[2], + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], ArgumentDataTypes: strings.Split(idParts[3], ","), - Privilege: idParts[4], - Roles: strings.Split(idParts[5], ","), - Shares: strings.Split(idParts[6], ","), - WithGrantOption: idParts[7] == "true", - IsOldID: false, + Privilege: idParts[4], + Roles: strings.Split(idParts[5], ","), + Shares: strings.Split(idParts[6], ","), + WithGrantOption: idParts[7] == "true", + IsOldID: false, }, nil } diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go index 37eb8f04f1..0e2d926928 100644 --- a/pkg/resources/integration_grant.go +++ b/pkg/resources/integration_grant.go @@ -169,7 +169,7 @@ type IntegrationGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewIntegrationGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *IntegrationGrantID { @@ -178,7 +178,7 @@ func NewIntegrationGrantID(objectName string, privilege string, roles []string, Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -196,7 +196,7 @@ func parseIntegrationGrantID(s string) (*IntegrationGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -208,6 +208,6 @@ func parseIntegrationGrantID(s string) (*IntegrationGrantID, error) { Privilege: idParts[1], Roles: strings.Split(idParts[2], ","), WithGrantOption: idParts[3] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go index 735ffad6ba..079e9585d8 100644 --- a/pkg/resources/masking_policy_grant.go +++ b/pkg/resources/masking_policy_grant.go @@ -167,7 +167,7 @@ func UpdateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { } // create the builder - builder := snowflake.MaskingPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder := snowflake.MaskingPolicyGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -193,7 +193,7 @@ type MaskingPolicyGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewMaskingPolicyGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *MaskingPolicyGrantID { @@ -204,7 +204,7 @@ func NewMaskingPolicyGrantID(databaseName string, schemaName, objectName, privil Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -213,7 +213,7 @@ func (v *MaskingPolicyGrantID) String() string { return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) } -func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error){ +func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error) { // is this an old ID format? if !strings.Contains(s, "❄️") { idParts := strings.Split(s, "|") @@ -224,7 +224,7 @@ func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error){ Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -238,6 +238,6 @@ func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error){ Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go index 303b2e9f18..e2bc196168 100644 --- a/pkg/resources/materialized_view_grant.go +++ b/pkg/resources/materialized_view_grant.go @@ -159,7 +159,7 @@ func ReadMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("database_name", grantID.DatabaseName); err != nil { + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } if err := d.Set("schema_name", grantID.SchemaName); err != nil { @@ -184,9 +184,9 @@ func ReadMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if futureMaterializedViewsEnabled { - builder = snowflake.FutureMaterializedViewGrant( grantID.DatabaseName, grantID.SchemaName) + builder = snowflake.FutureMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.MaterializedViewGrant( grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder = snowflake.MaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, materializedViewGrantSchema, builder, futureMaterializedViewsEnabled, validMaterializedViewPrivileges) @@ -280,7 +280,7 @@ func NewMaterializedViewGrantID(databaseName string, schemaName, objectName, pri Roles: roles, Shares: shares, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index c29fb8cb41..28ed04b1ae 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -147,9 +147,9 @@ func ReadPipeGrant(d *schema.ResourceData, meta interface{}) error { return err } - onFuture := ( grantID.ObjectName == "") + onFuture := (grantID.ObjectName == "") - if err := d.Set("pipe_name", grantID.ObjectName); err != nil { + if err := d.Set("pipe_name", grantID.ObjectName); err != nil { return err } if err := d.Set("on_future", onFuture); err != nil { @@ -166,7 +166,7 @@ func ReadPipeGrant(d *schema.ResourceData, meta interface{}) error { if onFuture { builder = snowflake.FuturePipeGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, pipeGrantSchema, builder, onFuture, validPipePrivileges) @@ -179,13 +179,13 @@ func DeletePipeGrant(d *schema.ResourceData, meta interface{}) error { return err } - onFuture := ( grantID.ObjectName == "") + onFuture := (grantID.ObjectName == "") var builder snowflake.GrantBuilder if onFuture { - builder = snowflake.FuturePipeGrant(grantID.DatabaseName, grantID.SchemaName) + builder = snowflake.FuturePipeGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder = snowflake.PipeGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return deleteGenericGrant(d, meta, builder) } @@ -244,7 +244,7 @@ type PipeGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewPipeGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *PipeGrantID { @@ -255,7 +255,7 @@ func NewPipeGrantID(databaseName string, schemaName, objectName, privilege strin Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -275,7 +275,7 @@ func parsePipeGrantID(s string) (*PipeGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -289,6 +289,6 @@ func parsePipeGrantID(s string) (*PipeGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index d5e8ad5a49..dc23b833ea 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -182,7 +182,7 @@ func CreateProcedureGrant(d *schema.ResourceData, meta interface{}) error { grantID := NewProcedureGrantID(databaseName, schemaName, procedureName, argumentDataTypes, privilege, roles, shares, withGrantOption) d.SetId(grantID.String()) return ReadProcedureGrant(d, meta) -} +} // ReadProcedureGrant implements schema.ReadFunc. func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { @@ -199,7 +199,7 @@ func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { if err := d.Set("roles", grantID.Roles); err != nil { return err } - + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } @@ -224,7 +224,7 @@ func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("privilege", grantID.Privilege); err != nil { + if err := d.Set("privilege", grantID.Privilege); err != nil { return err } @@ -312,28 +312,28 @@ func UpdateProcedureGrant(d *schema.ResourceData, meta interface{}) error { } type ProcedureGrantID struct { - DatabaseName string - SchemaName string - ObjectName string + DatabaseName string + SchemaName string + ObjectName string ArgumentDataTypes []string - Privilege string - Roles []string - Shares []string - WithGrantOption bool - IsOldID bool + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool } func NewProcedureGrantID(databaseName string, schemaName, objectName string, argumentDataTypes []string, privilege string, roles []string, shares []string, withGrantOption bool) *ProcedureGrantID { return &ProcedureGrantID{ - DatabaseName: databaseName, - SchemaName: schemaName, - ObjectName: objectName, + DatabaseName: databaseName, + SchemaName: schemaName, + ObjectName: objectName, ArgumentDataTypes: argumentDataTypes, - Privilege: privilege, - Roles: roles, - Shares: shares, - WithGrantOption: withGrantOption, - IsOldID: false, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, } } @@ -354,15 +354,15 @@ func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { objectNameParts := strings.Split(objectIdentifier, "(") return &ProcedureGrantID{ - DatabaseName: idParts[0], - SchemaName: idParts[1], - ObjectName: objectNameParts[0], + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: objectNameParts[0], ArgumentDataTypes: strings.Split(objectNameParts[1], ","), - Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), - Shares: []string{}, - WithGrantOption: idParts[5] == "true", - IsOldID: true, + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -370,14 +370,14 @@ func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 8", len(idParts)) } return &ProcedureGrantID{ - DatabaseName: idParts[0], - SchemaName: idParts[1], - ObjectName: idParts[2], + DatabaseName: idParts[0], + SchemaName: idParts[1], + ObjectName: idParts[2], ArgumentDataTypes: strings.Split(idParts[3], ","), - Privilege: idParts[4], - Roles: strings.Split(idParts[5], ","), - Shares: strings.Split(idParts[6], ","), - WithGrantOption: idParts[7] == "true", - IsOldID: false, + Privilege: idParts[4], + Roles: strings.Split(idParts[5], ","), + Shares: strings.Split(idParts[6], ","), + WithGrantOption: idParts[7] == "true", + IsOldID: false, }, nil } diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index ee30e43588..a190a9b31e 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -164,7 +164,7 @@ type ResourceMonitorGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewResourceMonitorGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *ResourceMonitorGrantID { @@ -173,7 +173,7 @@ func NewResourceMonitorGrantID(objectName string, privilege string, roles []stri Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -191,7 +191,7 @@ func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -203,6 +203,6 @@ func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { Privilege: idParts[1], Roles: strings.Split(idParts[2], ","), WithGrantOption: idParts[3] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go index 0d53d8f36e..6c946c4bc1 100644 --- a/pkg/resources/role_grants.go +++ b/pkg/resources/role_grants.go @@ -298,7 +298,7 @@ type RoleGrantsID struct { ObjectName string Roles []string Users []string - IsOldID bool + IsOldID bool } func NewRoleGrantsID(objectName string, roles, users []string) *RoleGrantsID { @@ -306,7 +306,7 @@ func NewRoleGrantsID(objectName string, roles, users []string) *RoleGrantsID { ObjectName: objectName, Roles: roles, Users: users, - IsOldID: false, + IsOldID: false, } } @@ -324,7 +324,7 @@ func parseRoleGrantsID(s string) (*RoleGrantsID, error) { ObjectName: idParts[0], Roles: strings.Split(idParts[4], ","), Users: []string{}, - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -335,6 +335,6 @@ func parseRoleGrantsID(s string) (*RoleGrantsID, error) { ObjectName: idParts[0], Roles: strings.Split(idParts[1], ","), Users: strings.Split(idParts[2], ","), - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index 2300ff3d05..eb461355c5 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -193,7 +193,7 @@ type RowAccessPolicyGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewRowAccessPolicyGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *RowAccessPolicyGrantID { @@ -204,7 +204,7 @@ func NewRowAccessPolicyGrantID(databaseName string, schemaName, objectName, priv Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -222,9 +222,9 @@ func parseRowAccessPolicyGrantID(s string) (*RowAccessPolicyGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: []string{}, + Roles: []string{}, WithGrantOption: idParts[4] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -238,6 +238,6 @@ func parseRowAccessPolicyGrantID(s string) (*RowAccessPolicyGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go index e0d20dbb4b..353f553e92 100644 --- a/pkg/resources/schema_grant.go +++ b/pkg/resources/schema_grant.go @@ -219,7 +219,7 @@ func ReadSchemaGrant(d *schema.ResourceData, meta interface{}) error { return err } } - + if err := d.Set("database_name", grantID.DatabaseName); err != nil { return err } @@ -277,7 +277,7 @@ type SchemaGrantID struct { Roles []string Shares []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewSchemaGrantID(databaseName string, schemaName, privilege string, roles []string, shares []string, withGrantOption bool) *SchemaGrantID { @@ -288,14 +288,14 @@ func NewSchemaGrantID(databaseName string, schemaName, privilege string, roles [ Roles: roles, Shares: shares, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } func (v *SchemaGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.Privilege, roles, shares, v.WithGrantOption) } func parseSchemaGrantID(s string) (*SchemaGrantID, error) { @@ -309,7 +309,7 @@ func parseSchemaGrantID(s string) (*SchemaGrantID, error) { Roles: strings.Split(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -323,6 +323,6 @@ func parseSchemaGrantID(s string) (*SchemaGrantID, error) { Roles: strings.Split(idParts[3], ","), Shares: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go index 92c59fa467..fd80049701 100644 --- a/pkg/resources/sequence_grant.go +++ b/pkg/resources/sequence_grant.go @@ -246,7 +246,7 @@ type SequenceGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewSequenceGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *SequenceGrantID { @@ -257,7 +257,7 @@ func NewSequenceGrantID(databaseName string, schemaName, objectName, privilege s Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -277,7 +277,7 @@ func parseSequenceGrantID(s string) (*SequenceGrantID, error) { Privilege: idParts[3], Roles: []string{}, WithGrantOption: idParts[4] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -291,6 +291,6 @@ func parseSequenceGrantID(s string) (*SequenceGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go index 78774c3383..9eabbdac4e 100644 --- a/pkg/resources/stage_grant.go +++ b/pkg/resources/stage_grant.go @@ -105,7 +105,7 @@ func CreateStageGrant(d *schema.ResourceData, meta interface{}) error { if name, ok := d.GetOk("schema_name"); ok { schemaName = name.(string) } - var stageName string + var stageName string if name, ok := d.GetOk("stage_name"); ok { stageName = name.(string) } @@ -127,7 +127,7 @@ func CreateStageGrant(d *schema.ResourceData, meta interface{}) error { if err := createGenericGrant(d, meta, builder); err != nil { return err } - roles := expandStringList( d.Get("roles").(*schema.Set).List()) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) grantID := NewStageGrantID(databaseName, schemaName, stageName, privilege, roles, grantOption) d.SetId(grantID.String()) @@ -250,7 +250,7 @@ type StageGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewStageGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *StageGrantID { @@ -261,7 +261,7 @@ func NewStageGrantID(databaseName string, schemaName, objectName, privilege stri Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -281,7 +281,7 @@ func parseStageGrantID(s string) (*StageGrantID, error) { Privilege: idParts[3], Roles: []string{}, WithGrantOption: idParts[4] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -295,6 +295,6 @@ func parseStageGrantID(s string) (*StageGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go index 4979111eab..c6a1d47541 100644 --- a/pkg/resources/table_grant.go +++ b/pkg/resources/table_grant.go @@ -103,7 +103,7 @@ func TableGrant() *TerraformGrantResource { // CreateTableGrant implements schema.CreateFunc. func CreateTableGrant(d *schema.ResourceData, meta interface{}) error { - var tableName string + var tableName string if _, ok := d.GetOk("table_name"); ok { tableName = d.Get("table_name").(string) } @@ -136,7 +136,7 @@ func CreateTableGrant(d *schema.ResourceData, meta interface{}) error { return err } - grantID := NewTableGrantID(databaseName, schemaName, tableName, privilege, roles, shares,withGrantOption) + grantID := NewTableGrantID(databaseName, schemaName, tableName, privilege, roles, shares, withGrantOption) d.SetId(grantID.String()) return ReadTableGrant(d, meta) } @@ -290,7 +290,7 @@ type TableGrantID struct { Roles []string Shares []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewTableGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, shares []string, withGrantOption bool) *TableGrantID { @@ -302,7 +302,7 @@ func NewTableGrantID(databaseName string, schemaName, objectName, privilege stri Roles: roles, Shares: shares, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -324,7 +324,7 @@ func parseTableGrantID(s string) (*TableGrantID, error) { Roles: strings.Split(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -339,6 +339,6 @@ func parseTableGrantID(s string) (*TableGrantID, error) { Roles: strings.Split(idParts[4], ","), Shares: strings.Split(idParts[5], ","), WithGrantOption: idParts[6] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go index 7627f11a9e..8282bc3f99 100644 --- a/pkg/resources/tag_grant.go +++ b/pkg/resources/tag_grant.go @@ -123,7 +123,7 @@ func ReadTagGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("tag_name", grantID.ObjectName); err != nil { + if err := d.Set("tag_name", grantID.ObjectName); err != nil { return err } @@ -135,7 +135,7 @@ func ReadTagGrant(d *schema.ResourceData, meta interface{}) error { return err } - builder := snowflake.TagGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder := snowflake.TagGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) return readGenericGrant(d, meta, tagGrantSchema, builder, false, validTagPrivileges) } @@ -156,7 +156,7 @@ func UpdateTagGrant(d *schema.ResourceData, meta interface{}) error { } // create the builder - builder := snowflake.TagGrant( grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder := snowflake.TagGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) // first revoke if err := deleteGenericGrantRolesAndShares( @@ -203,7 +203,7 @@ type TagGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewTagGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *TagGrantID { @@ -214,7 +214,7 @@ func NewTagGrantID(databaseName string, schemaName, objectName, privilege string Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -234,7 +234,7 @@ func parseTagGrantID(s string) (*TagGrantID, error) { Privilege: idParts[3], Roles: []string{}, WithGrantOption: idParts[4] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -248,6 +248,6 @@ func parseTagGrantID(s string) (*TagGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go index 8534cea55f..8ee5945e85 100644 --- a/pkg/resources/task_grant.go +++ b/pkg/resources/task_grant.go @@ -124,7 +124,7 @@ func CreateTaskGrant(d *schema.ResourceData, meta interface{}) error { return err } - grantID := NewTaskGrantID(databaseName, schemaName, taskName, privilege,roles, withGrantOption) + grantID := NewTaskGrantID(databaseName, schemaName, taskName, privilege, roles, withGrantOption) d.SetId(grantID.String()) return ReadTaskGrant(d, meta) @@ -252,7 +252,7 @@ type TaskGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewTaskGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, withGrantOption bool) *TaskGrantID { @@ -263,7 +263,7 @@ func NewTaskGrantID(databaseName string, schemaName, objectName, privilege strin Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -283,7 +283,7 @@ func parseTaskGrantID(s string) (*TaskGrantID, error) { Privilege: idParts[3], Roles: []string{}, WithGrantOption: idParts[4] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -297,6 +297,6 @@ func parseTaskGrantID(s string) (*TaskGrantID, error) { Privilege: idParts[3], Roles: strings.Split(idParts[4], ","), WithGrantOption: idParts[5] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/user_grant.go b/pkg/resources/user_grant.go index 86bcd9d402..74442e5b90 100644 --- a/pkg/resources/user_grant.go +++ b/pkg/resources/user_grant.go @@ -178,7 +178,7 @@ type UserGrantID struct { Privilege string Roles []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewUserGrantID(objectName string, privilege string, roles []string, withGrantOption bool) *UserGrantID { @@ -216,6 +216,6 @@ func parseUserGrantID(s string) (*UserGrantID, error) { Privilege: idParts[1], Roles: strings.Split(idParts[2], ","), WithGrantOption: idParts[3] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go index c7bced14ea..2c0728da63 100644 --- a/pkg/resources/view_grant.go +++ b/pkg/resources/view_grant.go @@ -160,7 +160,7 @@ func ReadViewGrant(d *schema.ResourceData, meta interface{}) error { return err } - if err := d.Set("schema_name", grantID.SchemaName); err != nil { + if err := d.Set("schema_name", grantID.SchemaName); err != nil { return err } @@ -187,9 +187,9 @@ func ReadViewGrant(d *schema.ResourceData, meta interface{}) error { var builder snowflake.GrantBuilder if futureViewsEnabled { - builder = snowflake.FutureViewGrant(grantID.DatabaseName, grantID.SchemaName) + builder = snowflake.FutureViewGrant(grantID.DatabaseName, grantID.SchemaName) } else { - builder = snowflake.ViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) + builder = snowflake.ViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName) } return readGenericGrant(d, meta, viewGrantSchema, builder, futureViewsEnabled, validViewPrivileges) @@ -271,7 +271,7 @@ type ViewGrantID struct { Roles []string Shares []string WithGrantOption bool - IsOldID bool + IsOldID bool } func NewViewGrantID(databaseName string, schemaName, objectName, privilege string, roles []string, shares []string, withGrantOption bool) *ViewGrantID { @@ -283,7 +283,7 @@ func NewViewGrantID(databaseName string, schemaName, objectName, privilege strin Roles: roles, Shares: shares, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } @@ -305,7 +305,7 @@ func parseViewGrantID(s string) (*ViewGrantID, error) { Roles: strings.Split(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", - IsOldID: true, + IsOldID: true, }, nil } idParts := strings.Split(s, "❄️") @@ -320,6 +320,6 @@ func parseViewGrantID(s string) (*ViewGrantID, error) { Roles: strings.Split(idParts[4], ","), Shares: strings.Split(idParts[5], ","), WithGrantOption: idParts[6] == "true", - IsOldID: false, + IsOldID: false, }, nil } diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go index e0139e9637..e8814f030b 100644 --- a/pkg/resources/warehouse_grant.go +++ b/pkg/resources/warehouse_grant.go @@ -86,7 +86,7 @@ func CreateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { grantID := NewWarehouseGrantID(warehouseName, privilege, roles, withGrantOption) - d.SetId(grantID.String()) + d.SetId(grantID.String()) return ReadWarehouseGrant(d, meta) } @@ -193,7 +193,7 @@ func NewWarehouseGrantID(objectName string, privilege string, roles []string, wi Privilege: privilege, Roles: roles, WithGrantOption: withGrantOption, - IsOldID: false, + IsOldID: false, } } From e003846534e963bc35c96a479edfd07981d88c30 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:20:41 -0800 Subject: [PATCH 06/26] revise grant id --- pkg/resources/database_grant.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index b816535b58..e5b44d4e30 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -79,11 +79,26 @@ func DatabaseGrant() *TerraformGrantResource { return nil, err } id := v.(DatabaseGrantID) - d.Set("database_name", id.DatabaseName) - d.Set("privilege", id.Privilege) - d.Set("roles", id.Roles) - d.Set("shares", id.Shares) - d.Set("with_grant_option", id.WithGrantOption) + err = d.Set("database_name", id.DatabaseName)\ + if err != nil { + return nil, err + } + err = d.Set("privilege", id.Privilege) + if err != nil { + return nil, err + } + err = d.Set("roles", id.Roles) + if err != nil { + return nil, err + } + err = d.Set("shares", id.Shares) + if err != nil { + return nil, err + } + err = d.Set("with_grant_option", id.WithGrantOption) + if err != nil { + return nil, err + } d.SetId(helpers.RandomSnowflakeID()) return []*schema.ResourceData{d}, nil }, From b4a2496d69b43e4694708980690143d989b2b8f6 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:22:51 -0800 Subject: [PATCH 07/26] revise grant id --- pkg/resources/database_grant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index e5b44d4e30..d635261264 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -79,7 +79,7 @@ func DatabaseGrant() *TerraformGrantResource { return nil, err } id := v.(DatabaseGrantID) - err = d.Set("database_name", id.DatabaseName)\ + err = d.Set("database_name", id.DatabaseName) if err != nil { return nil, err } From 707c97f18af6350bbc734ffca82cbe82afabbed6 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:26:45 -0800 Subject: [PATCH 08/26] revise grant id --- pkg/resources/pipe_grant_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/pipe_grant_test.go b/pkg/resources/pipe_grant_test.go index a500eb2553..b58a07e831 100644 --- a/pkg/resources/pipe_grant_test.go +++ b/pkg/resources/pipe_grant_test.go @@ -45,7 +45,7 @@ func TestPipeGrantCreate(t *testing.T) { func TestPipeGrantRead(t *testing.T) { r := require.New(t) - d := pipeGrant(t, "test-db|PUBLIC|test-pipe|OPERATE|false", map[string]interface{}{ + d := pipeGrant(t, "test-db|PUBLIC|test-pipe|OPERATE||false", map[string]interface{}{ "pipe_name": "test-pipe", "schema_name": "PUBLIC", "database_name": "test-db", From 34ca3b313196e3845437357f64fb1c0bae4a4583 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:30:28 -0800 Subject: [PATCH 09/26] revise grant id --- pkg/resources/resource_monitor_grant_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/resource_monitor_grant_test.go b/pkg/resources/resource_monitor_grant_test.go index 4ae9b20987..125e761210 100644 --- a/pkg/resources/resource_monitor_grant_test.go +++ b/pkg/resources/resource_monitor_grant_test.go @@ -45,7 +45,7 @@ func TestResourceMonitorGrantCreate(t *testing.T) { func TestResourceMonitorGrantRead(t *testing.T) { r := require.New(t) - d := resourceMonitorGrant(t, "test-monitor|||MONITOR||false", map[string]interface{}{ + d := resourceMonitorGrant(t, "test-monitor|MONITOR||false", map[string]interface{}{ "monitor_name": "test-monitor", "privilege": "MONITOR", "roles": []interface{}{"test-role-1", "test-role-2"}, From 8944f256a47484f545e2482ebd15d3376ca72dce Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:36:14 -0800 Subject: [PATCH 10/26] revise grant id --- pkg/resources/resource_monitor_grant_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/resource_monitor_grant_test.go b/pkg/resources/resource_monitor_grant_test.go index 125e761210..58dbe29acd 100644 --- a/pkg/resources/resource_monitor_grant_test.go +++ b/pkg/resources/resource_monitor_grant_test.go @@ -45,7 +45,7 @@ func TestResourceMonitorGrantCreate(t *testing.T) { func TestResourceMonitorGrantRead(t *testing.T) { r := require.New(t) - d := resourceMonitorGrant(t, "test-monitor|MONITOR||false", map[string]interface{}{ + d := resourceMonitorGrant(t, "test-monitor❄️MONITOR❄️❄️false", map[string]interface{}{ "monitor_name": "test-monitor", "privilege": "MONITOR", "roles": []interface{}{"test-role-1", "test-role-2"}, From f1f328ac9a611292be8185908af3483e4c36c361 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 02:54:32 -0800 Subject: [PATCH 11/26] revise grant id --- pkg/resources/resource_monitor_grant.go | 4 +++- pkg/resources/role_grants.go | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index a190a9b31e..e3bc326d8f 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -59,7 +59,9 @@ func ResourceMonitorGrant() *TerraformGrantResource { Read: ReadResourceMonitorGrant, Delete: DeleteResourceMonitorGrant, Update: UpdateResourceMonitorGrant, - + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, Schema: resourceMonitorGrantSchema, }, ValidPrivs: validResourceMonitorPrivileges, diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go index 6c946c4bc1..fb4ddafe68 100644 --- a/pkg/resources/role_grants.go +++ b/pkg/resources/role_grants.go @@ -328,8 +328,8 @@ func parseRoleGrantsID(s string) (*RoleGrantsID, error) { }, nil } idParts := strings.Split(s, "❄️") - if len(idParts) != 4 { - return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 4", len(idParts)) + if len(idParts) != 3 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 3", len(idParts)) } return &RoleGrantsID{ ObjectName: idParts[0], From 8576e6991b6d82dbfc9c9c5e791536eb5e7da62d Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 03:07:43 -0800 Subject: [PATCH 12/26] revise grant id --- pkg/resources/resource_monitor_grant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index e3bc326d8f..7d266a9110 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -80,7 +80,7 @@ func CreateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error return err } - grantID := NewResourceMonitorGrantID(privilege, privilege, roles, withGrantOption) + grantID := NewResourceMonitorGrantID(monitorName, privilege, roles, withGrantOption) d.SetId(grantID.String()) return ReadResourceMonitorGrant(d, meta) From 9038f2598cdb4c7cd9a26add88edba1a844877c6 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 03:37:33 -0800 Subject: [PATCH 13/26] revise grant id --- pkg/resources/database_grant.go | 127 ++++++++++++++++++++---------- pkg/resources/role_grants_test.go | 18 ----- 2 files changed, 85 insertions(+), 60 deletions(-) diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index d635261264..acc51925ab 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -1,10 +1,9 @@ package resources import ( - "context" "fmt" + "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -73,49 +72,13 @@ func DatabaseGrant() *TerraformGrantResource { Schema: databaseGrantSchema, Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - v, err := helpers.DecodeSnowflakeImportID(d.Id(), DatabaseGrantID{}) - if err != nil { - return nil, err - } - id := v.(DatabaseGrantID) - err = d.Set("database_name", id.DatabaseName) - if err != nil { - return nil, err - } - err = d.Set("privilege", id.Privilege) - if err != nil { - return nil, err - } - err = d.Set("roles", id.Roles) - if err != nil { - return nil, err - } - err = d.Set("shares", id.Shares) - if err != nil { - return nil, err - } - err = d.Set("with_grant_option", id.WithGrantOption) - if err != nil { - return nil, err - } - d.SetId(helpers.RandomSnowflakeID()) - return []*schema.ResourceData{d}, nil - }, + StateContext: schema.ImportStatePassthroughContext, }, }, ValidPrivs: validDatabasePrivileges, } } -type DatabaseGrantID struct { - DatabaseName string `tf:"database_name"` - Privilege string `tf:"privilege"` - Roles []string `tf:"roles"` - Shares []string `tf:"shares"` - WithGrantOption bool `tf:"with_grant_option"` -} - // CreateDatabaseGrant implements schema.CreateFunc. func CreateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { databaseName := d.Get("database_name").(string) @@ -124,15 +87,42 @@ func CreateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error creating database grant err = %w", err) } - d.SetId(helpers.RandomSnowflakeID()) + privilege := d.Get("privilege").(string) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + shares := expandStringList(d.Get("shares").(*schema.Set).List()) + withGrantOption := d.Get("with_grant_option").(bool) + grantID := NewDatabaseGrantID(databaseName, privilege, roles, shares, withGrantOption) + + d.SetId(grantID.String()) return ReadDatabaseGrant(d, meta) } // ReadDatabaseGrant implements schema.ReadFunc. func ReadDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - builder := snowflake.DatabaseGrant(databaseName) + grantID, err := parseDatabaseGrantID(d.Id()) + if err != nil { + return err + } + if err := d.Set("database_name", grantID.DatabaseName); err != nil { + return err + } + if err := d.Set("privilege", grantID.Privilege); err != nil { + return err + } + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { + return err + } + if !grantID.IsOldID { + if err := d.Set("shares", grantID.Shares); err != nil { + return err + } + } + + builder := snowflake.DatabaseGrant(grantID.DatabaseName) return readGenericGrant(d, meta, databaseGrantSchema, builder, false, validDatabasePrivileges) } @@ -195,3 +185,56 @@ func UpdateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { // Done, refresh state return ReadDatabaseGrant(d, meta) } + +type DatabaseGrantID struct { + DatabaseName string + Privilege string + Roles []string + Shares []string + WithGrantOption bool + IsOldID bool +} + +func NewDatabaseGrantID(databaseName string, privilege string, roles []string, shares []string, withGrantOption bool) *DatabaseGrantID { + return &DatabaseGrantID{ + DatabaseName: databaseName, + Privilege: privilege, + Roles: roles, + Shares: shares, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *DatabaseGrantID) String() string { + roles := strings.Join(v.Roles, ",") + shares := strings.Join(v.Shares, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.Privilege, roles, shares, v.WithGrantOption, v.IsOldID) +} + +func parseDatabaseGrantID(s string) (*DatabaseGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &DatabaseGrantID{ + DatabaseName: idParts[0], + Privilege: idParts[3], + Roles: strings.Split(idParts[4], ","), + Shares: []string{}, + WithGrantOption: idParts[5] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 5 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 5", len(idParts)) + } + return &DatabaseGrantID{ + DatabaseName: idParts[0], + Privilege: idParts[1], + Roles: strings.Split(idParts[2], ","), + Shares: strings.Split(idParts[3], ","), + WithGrantOption: idParts[4] == "true", + IsOldID: false, + }, nil +} diff --git a/pkg/resources/role_grants_test.go b/pkg/resources/role_grants_test.go index ab8ed61cae..51a2ea7f63 100644 --- a/pkg/resources/role_grants_test.go +++ b/pkg/resources/role_grants_test.go @@ -90,24 +90,6 @@ func TestRoleGrantsDelete(t *testing.T) { }) } -func TestRoleGrantsReadLegacyId(t *testing.T) { - r := require.New(t) - - d := roleGrants(t, "good_name", map[string]interface{}{ - "role_name": "good_name", - "roles": []interface{}{"role1", "role2"}, - "users": []interface{}{"user1", "user2"}, - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadRoleGrants(mock) - err := resources.ReadRoleGrants(d, db) - r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 2) - r.Len(d.Get("roles").(*schema.Set).List(), 2) - }) -} - func expectReadUnhandledRoleGrants(mock sqlmock.Sqlmock) { rows := sqlmock.NewRows([]string{ "created_on", From 5a008dcdbe60c4f253199642f10a9bd3032fe693 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 03:40:48 -0800 Subject: [PATCH 14/26] revise grant id --- pkg/resources/database_grant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index acc51925ab..40e5b4be87 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -209,7 +209,7 @@ func NewDatabaseGrantID(databaseName string, privilege string, roles []string, s func (v *DatabaseGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.Privilege, roles, shares, v.WithGrantOption, v.IsOldID) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.Privilege, roles, shares, v.WithGrantOption) } func parseDatabaseGrantID(s string) (*DatabaseGrantID, error) { From 5c98b55c13e6c1eddb8dea61c4a16c8433d6e497 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 03:52:13 -0800 Subject: [PATCH 15/26] revise grant id --- pkg/resources/table_grant.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go index c6a1d47541..7be5c1fa90 100644 --- a/pkg/resources/table_grant.go +++ b/pkg/resources/table_grant.go @@ -321,9 +321,9 @@ func parseTableGrantID(s string) (*TableGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: []string{}, Shares: []string{}, - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", IsOldID: true, }, nil } From bb68a6a0bf3f91cb53b3d117553e2064d0d95f0d Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 10:04:35 -0800 Subject: [PATCH 16/26] slice helper --- pkg/helpers/list_to_string_helpers.go | 11 +++++++++++ pkg/resources/database_grant.go | 9 +++++---- pkg/resources/external_table_grant.go | 11 ++++++++--- pkg/resources/file_format_grant.go | 5 +++-- pkg/resources/function_grant.go | 11 ++++++----- pkg/resources/masking_policy_grant.go | 5 +++-- pkg/resources/materialized_view_grant.go | 7 ++++--- pkg/resources/pipe_grant.go | 5 +++-- pkg/resources/procedure_grant.go | 11 ++++++----- pkg/resources/resource_monitor_grant.go | 5 +++-- pkg/resources/role_grants.go | 7 ++++--- pkg/resources/row_access_policy_grant.go | 3 ++- pkg/resources/schema_grant.go | 7 ++++--- pkg/resources/sequence_grant.go | 3 ++- pkg/resources/stage_grant.go | 3 ++- pkg/resources/stream_grant.go | 3 ++- pkg/resources/table_grant.go | 5 +++-- pkg/resources/tag_grant.go | 3 ++- pkg/resources/task_grant.go | 3 ++- pkg/resources/user_grant.go | 5 +++-- pkg/resources/view_grant.go | 7 ++++--- pkg/resources/warehouse_grant.go | 5 +++-- 22 files changed, 85 insertions(+), 49 deletions(-) diff --git a/pkg/helpers/list_to_string_helpers.go b/pkg/helpers/list_to_string_helpers.go index d5ea166179..87e4928e8e 100644 --- a/pkg/helpers/list_to_string_helpers.go +++ b/pkg/helpers/list_to_string_helpers.go @@ -31,3 +31,14 @@ func ListContentToString(listString string) string { re := regexp.MustCompile(`[\"\[\]]`) return re.ReplaceAllString(listString, "") } + +// SplitStringToSlice splits a string into a slice of strings, separated by a separator. It also removes empty strings. +func SplitStringToSlice(s, sep string) []string { + var v []string + for _, elem := range strings.Split(s, sep) { + if elem != "" { + v = append(v, elem) + } + } + return v +} diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index 40e5b4be87..60ffccb6a7 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -219,9 +220,9 @@ func parseDatabaseGrantID(s string) (*DatabaseGrantID, error) { return &DatabaseGrantID{ DatabaseName: idParts[0], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: []string{}, Shares: []string{}, - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", IsOldID: true, }, nil } @@ -232,8 +233,8 @@ func parseDatabaseGrantID(s string) (*DatabaseGrantID, error) { return &DatabaseGrantID{ DatabaseName: idParts[0], Privilege: idParts[1], - Roles: strings.Split(idParts[2], ","), - Shares: strings.Split(idParts[3], ","), + Roles: helpers.SplitStringToSlice(idParts[2], ","), + Shares: helpers.SplitStringToSlice(idParts[3], ","), WithGrantOption: idParts[4] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go index 048658055a..82a76907cb 100644 --- a/pkg/resources/external_table_grant.go +++ b/pkg/resources/external_table_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -145,6 +146,10 @@ func ReadExternalTableGrant(d *schema.ResourceData, meta interface{}) error { } if !grantID.IsOldID { + fmt.Printf("[DEBUG] id: %v\n", d.Id()) + fmt.Printf("[DEBUG] reading external table grant: %v\n", grantID) + fmt.Printf("[DEBUG] reading external table grant shares: %v\n", grantID.Shares) + fmt.Printf("[DEBUG] len(external table grant shares): %v\n", len(grantID.Shares)) if err := d.Set("shares", grantID.Shares); err != nil { return err } @@ -297,7 +302,7 @@ func parseExternalTableGrant(s string) (*ExternalTableGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", IsOldID: true, @@ -312,8 +317,8 @@ func parseExternalTableGrant(s string) (*ExternalTableGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), - Shares: strings.Split(idParts[5], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), + Shares: helpers.SplitStringToSlice(idParts[5], ","), WithGrantOption: idParts[6] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index 3c7956e16d..7caed83ad3 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -270,7 +271,7 @@ func parseFileFormatGrant(s string) (*FileFormatGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", }, nil } @@ -283,7 +284,7 @@ func parseFileFormatGrant(s string) (*FileFormatGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", }, nil } diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index e6e10d4c10..47927da9e1 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -347,9 +348,9 @@ func parseFunctionGrantID(s string) (*FunctionGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], ObjectName: objectNameParts[0], - ArgumentDataTypes: strings.Split(objectNameParts[1], ","), + ArgumentDataTypes: helpers.SplitStringToSlice(objectNameParts[1], ","), Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", IsOldID: true, @@ -363,10 +364,10 @@ func parseFunctionGrantID(s string) (*FunctionGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], ObjectName: idParts[2], - ArgumentDataTypes: strings.Split(idParts[3], ","), + ArgumentDataTypes: helpers.SplitStringToSlice(idParts[3], ","), Privilege: idParts[4], - Roles: strings.Split(idParts[5], ","), - Shares: strings.Split(idParts[6], ","), + Roles: helpers.SplitStringToSlice(idParts[5], ","), + Shares: helpers.SplitStringToSlice(idParts[6], ","), WithGrantOption: idParts[7] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go index 079e9585d8..7222b02a94 100644 --- a/pkg/resources/masking_policy_grant.go +++ b/pkg/resources/masking_policy_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -222,7 +223,7 @@ func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: true, }, nil @@ -236,7 +237,7 @@ func parseMaskingPolicyGrantID(s string) (*MaskingPolicyGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go index e2bc196168..5f2a03d733 100644 --- a/pkg/resources/materialized_view_grant.go +++ b/pkg/resources/materialized_view_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -299,7 +300,7 @@ func parseMaterializedViewGrantID(s string) (*MaterializedViewGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", IsOldID: true, @@ -314,8 +315,8 @@ func parseMaterializedViewGrantID(s string) (*MaterializedViewGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), - Shares: strings.Split(idParts[5], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), + Shares: helpers.SplitStringToSlice(idParts[5], ","), WithGrantOption: idParts[6] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index 28ed04b1ae..34f6443feb 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -273,7 +274,7 @@ func parsePipeGrantID(s string) (*PipeGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: true, }, nil @@ -287,7 +288,7 @@ func parsePipeGrantID(s string) (*PipeGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index dc23b833ea..8a7e462c69 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -357,9 +358,9 @@ func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], ObjectName: objectNameParts[0], - ArgumentDataTypes: strings.Split(objectNameParts[1], ","), + ArgumentDataTypes: helpers.SplitStringToSlice(objectNameParts[1], ","), Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", IsOldID: true, @@ -373,10 +374,10 @@ func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], ObjectName: idParts[2], - ArgumentDataTypes: strings.Split(idParts[3], ","), + ArgumentDataTypes: helpers.SplitStringToSlice(idParts[3], ","), Privilege: idParts[4], - Roles: strings.Split(idParts[5], ","), - Shares: strings.Split(idParts[6], ","), + Roles: helpers.SplitStringToSlice(idParts[5], ","), + Shares: helpers.SplitStringToSlice(idParts[6], ","), WithGrantOption: idParts[7] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index 7d266a9110..5463ca3cd9 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -191,7 +192,7 @@ func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { return &ResourceMonitorGrantID{ ObjectName: idParts[0], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: true, }, nil @@ -203,7 +204,7 @@ func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { return &ResourceMonitorGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: strings.Split(idParts[2], ","), + Roles: helpers.SplitStringToSlice(idParts[2], ","), WithGrantOption: idParts[3] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go index fb4ddafe68..32d2fcb680 100644 --- a/pkg/resources/role_grants.go +++ b/pkg/resources/role_grants.go @@ -6,6 +6,7 @@ import ( "log" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/jmoiron/sqlx" @@ -322,7 +323,7 @@ func parseRoleGrantsID(s string) (*RoleGrantsID, error) { idParts := strings.Split(s, "|") return &RoleGrantsID{ ObjectName: idParts[0], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Users: []string{}, IsOldID: true, }, nil @@ -333,8 +334,8 @@ func parseRoleGrantsID(s string) (*RoleGrantsID, error) { } return &RoleGrantsID{ ObjectName: idParts[0], - Roles: strings.Split(idParts[1], ","), - Users: strings.Split(idParts[2], ","), + Roles: helpers.SplitStringToSlice(idParts[1], ","), + Users: helpers.SplitStringToSlice(idParts[2], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index eb461355c5..004d824970 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -236,7 +237,7 @@ func parseRowAccessPolicyGrantID(s string) (*RowAccessPolicyGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go index 353f553e92..9e877dcf6d 100644 --- a/pkg/resources/schema_grant.go +++ b/pkg/resources/schema_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -306,7 +307,7 @@ func parseSchemaGrantID(s string) (*SchemaGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", IsOldID: true, @@ -320,8 +321,8 @@ func parseSchemaGrantID(s string) (*SchemaGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], Privilege: idParts[2], - Roles: strings.Split(idParts[3], ","), - Shares: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[3], ","), + Shares: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go index fd80049701..e1c24d8fac 100644 --- a/pkg/resources/sequence_grant.go +++ b/pkg/resources/sequence_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -289,7 +290,7 @@ func parseSequenceGrantID(s string) (*SequenceGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go index 9eabbdac4e..398622dc44 100644 --- a/pkg/resources/stage_grant.go +++ b/pkg/resources/stage_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -293,7 +294,7 @@ func parseStageGrantID(s string) (*StageGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go index 44aa88ace9..1e7a62ed93 100644 --- a/pkg/resources/stream_grant.go +++ b/pkg/resources/stream_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -285,7 +286,7 @@ func parseStreamGrantID(s string) (*StreamGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", }, nil } diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go index 7be5c1fa90..996f3d0dbd 100644 --- a/pkg/resources/table_grant.go +++ b/pkg/resources/table_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -336,8 +337,8 @@ func parseTableGrantID(s string) (*TableGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), - Shares: strings.Split(idParts[5], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), + Shares: helpers.SplitStringToSlice(idParts[5], ","), WithGrantOption: idParts[6] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go index 8282bc3f99..bc97eca473 100644 --- a/pkg/resources/tag_grant.go +++ b/pkg/resources/tag_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -246,7 +247,7 @@ func parseTagGrantID(s string) (*TagGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go index 8ee5945e85..640bfd0025 100644 --- a/pkg/resources/task_grant.go +++ b/pkg/resources/task_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -295,7 +296,7 @@ func parseTaskGrantID(s string) (*TaskGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/user_grant.go b/pkg/resources/user_grant.go index 74442e5b90..4fb364a4dd 100644 --- a/pkg/resources/user_grant.go +++ b/pkg/resources/user_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -202,7 +203,7 @@ func parseUserGrantID(s string) (*UserGrantID, error) { return &UserGrantID{ ObjectName: idParts[0], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: true, }, nil @@ -214,7 +215,7 @@ func parseUserGrantID(s string) (*UserGrantID, error) { return &UserGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: strings.Split(idParts[2], ","), + Roles: helpers.SplitStringToSlice(idParts[2], ","), WithGrantOption: idParts[3] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go index 2c0728da63..6be60fe90a 100644 --- a/pkg/resources/view_grant.go +++ b/pkg/resources/view_grant.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -302,7 +303,7 @@ func parseViewGrantID(s string) (*ViewGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), Shares: []string{}, WithGrantOption: idParts[5] == "true", IsOldID: true, @@ -317,8 +318,8 @@ func parseViewGrantID(s string) (*ViewGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), - Shares: strings.Split(idParts[5], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), + Shares: helpers.SplitStringToSlice(idParts[5], ","), WithGrantOption: idParts[6] == "true", IsOldID: false, }, nil diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go index e8814f030b..10ef5f6cbd 100644 --- a/pkg/resources/warehouse_grant.go +++ b/pkg/resources/warehouse_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -209,7 +210,7 @@ func parseWarehouseGrantID(s string) (*WarehouseGrantID, error) { return &WarehouseGrantID{ ObjectName: idParts[0], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: true, }, nil @@ -221,7 +222,7 @@ func parseWarehouseGrantID(s string) (*WarehouseGrantID, error) { return &WarehouseGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: strings.Split(idParts[2], ","), + Roles: helpers.SplitStringToSlice(idParts[2], ","), WithGrantOption: idParts[3] == "true", IsOldID: false, }, nil From 95085dbac14ca375173c8f6c10c1040ea3045d63 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 11:16:22 -0800 Subject: [PATCH 17/26] slice helper --- examples/resources/snowflake_account_grant/import.sh | 3 +-- examples/resources/snowflake_database_grant/import.sh | 4 ++-- .../resources/snowflake_external_table_grant/import.sh | 4 ++-- examples/resources/snowflake_file_format_grant/import.sh | 4 ++-- examples/resources/snowflake_function_grant/import.sh | 4 ++-- examples/resources/snowflake_integration_grant/import.sh | 4 ++-- .../snowflake_materialized_view_grant/import.sh | 4 ++-- examples/resources/snowflake_pipe_grant/import.sh | 4 ++-- examples/resources/snowflake_procedure_grant/import.sh | 4 ++-- .../resources/snowflake_resource_monitor_grant/import.sh | 3 ++- examples/resources/snowflake_role_grants/import.sh | 3 ++- .../snowflake_row_access_policy_grant/import.sh | 4 ++-- examples/resources/snowflake_schema_grant/import.sh | 4 ++-- examples/resources/snowflake_sequence_grant/import.sh | 4 ++-- examples/resources/snowflake_stage_grant/import.sh | 4 ++-- examples/resources/snowflake_stream_grant/import.sh | 4 ++-- examples/resources/snowflake_table_grant/import.sh | 4 ++-- examples/resources/snowflake_tag_grant/import.sh | 4 ++-- examples/resources/snowflake_task_grant/import.sh | 4 ++-- examples/resources/snowflake_user_grant/import.sh | 4 ++-- examples/resources/snowflake_view_grant/import.sh | 4 ++-- examples/resources/snowflake_warehouse_grant/import.sh | 4 ++-- pkg/resources/database_grant.go | 8 ++++---- pkg/resources/external_table_grant.go | 8 ++++---- pkg/resources/file_format_grant.go | 6 +++--- pkg/resources/function_grant.go | 8 ++++---- pkg/resources/integration_grant.go | 9 +++++---- pkg/resources/materialized_view_grant.go | 8 ++++---- pkg/resources/pipe_grant.go | 6 +++--- pkg/resources/procedure_grant.go | 8 ++++---- pkg/resources/resource_monitor_grant.go | 6 +++--- pkg/resources/row_access_policy_grant.go | 6 +++--- pkg/resources/schema_grant.go | 8 ++++---- pkg/resources/sequence_grant.go | 6 +++--- pkg/resources/stage_grant.go | 6 +++--- pkg/resources/stream_grant.go | 6 +++--- pkg/resources/table_grant.go | 8 ++++---- pkg/resources/tag_grant.go | 6 +++--- pkg/resources/task_grant.go | 6 +++--- pkg/resources/user_grant.go | 6 +++--- pkg/resources/view_grant.go | 8 ++++---- pkg/resources/warehouse_grant.go | 6 +++--- 42 files changed, 113 insertions(+), 111 deletions(-) diff --git a/examples/resources/snowflake_account_grant/import.sh b/examples/resources/snowflake_account_grant/import.sh index 52c22aaf68..43af9540c2 100644 --- a/examples/resources/snowflake_account_grant/import.sh +++ b/examples/resources/snowflake_account_grant/import.sh @@ -1,2 +1 @@ -# format is account name | | | privilege | true/false for with_grant_option -terraform import snowflake_account_grant.example 'accountName|||USAGE|true' +terraform import snowflake_account_grant.example 'privilege=MONITOR,roles=[role1,role2],with_grant_option=false' diff --git a/examples/resources/snowflake_database_grant/import.sh b/examples/resources/snowflake_database_grant/import.sh index cffd508e89..939c991996 100644 --- a/examples/resources/snowflake_database_grant/import.sh +++ b/examples/resources/snowflake_database_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | | | privilege | true/false for with_grant_option -terraform import snowflake_database_grant.example 'databaseName|||USAGE|false' +# format is database_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_database_grant.example 'MY_DATABASE❄️USAGE❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_external_table_grant/import.sh b/examples/resources/snowflake_external_table_grant/import.sh index 3528a3ae71..b2ec2eab96 100644 --- a/examples/resources/snowflake_external_table_grant/import.sh +++ b/examples/resources/snowflake_external_table_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | external table name | privilege | true/false for with_grant_option -terraform import snowflake_external_table_grant.example 'dbName|schemaName|externalTableName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_external_table_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️SELECT❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_file_format_grant/import.sh b/examples/resources/snowflake_file_format_grant/import.sh index 3f66c00797..53141d396f 100644 --- a/examples/resources/snowflake_file_format_grant/import.sh +++ b/examples/resources/snowflake_file_format_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | file format name | privilege | true/false for with_grant_option -terraform import snowflake_file_format_grant.example 'dbName|schemaName|fileFormatName|USAGE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_file_format_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️USAGE❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_function_grant/import.sh b/examples/resources/snowflake_function_grant/import.sh index d184a3861c..3c0b27ad3b 100644 --- a/examples/resources/snowflake_function_grant/import.sh +++ b/examples/resources/snowflake_function_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | function signature | privilege | true/false for with_grant_option -terraform import snowflake_function_grant.example 'dbName|schemaName|functionName(ARG1TYPE,ARG2TYPE)|USAGE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ argument_data_types ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_function_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️ARG1TYPE,ARG2TYPE❄️USAGE❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_integration_grant/import.sh b/examples/resources/snowflake_integration_grant/import.sh index 9a35315239..604b62e1bd 100644 --- a/examples/resources/snowflake_integration_grant/import.sh +++ b/examples/resources/snowflake_integration_grant/import.sh @@ -1,2 +1,2 @@ -# format is integration name ||| privilege | true/false for with_grant_option -terraform import snowflake_integration_grant.example 'intName|||USAGE|true' +# format is integration_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_integration_grant.example 'MY_INTEGRATION❄️USAGE❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_materialized_view_grant/import.sh b/examples/resources/snowflake_materialized_view_grant/import.sh index a345ace662..44029e7370 100644 --- a/examples/resources/snowflake_materialized_view_grant/import.sh +++ b/examples/resources/snowflake_materialized_view_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | materialized view name | privilege | true/false for with_grant_option -terraform import snowflake_materialized_view_grant.example 'dbName|schemaName|materializedViewName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_materialized_view_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️SELECT❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_pipe_grant/import.sh b/examples/resources/snowflake_pipe_grant/import.sh index 4948722683..908f1ae220 100644 --- a/examples/resources/snowflake_pipe_grant/import.sh +++ b/examples/resources/snowflake_pipe_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | pipe name | privilege | true/false for with_grant_option -terraform import snowflake_pipe_grant.example 'dbName|schemaName|pipeName|OPERATE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_pipe_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️OPERATE❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_procedure_grant/import.sh b/examples/resources/snowflake_procedure_grant/import.sh index 772952f89e..cc73ef2472 100644 --- a/examples/resources/snowflake_procedure_grant/import.sh +++ b/examples/resources/snowflake_procedure_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | procedure signature | privilege | true/false for with_grant_option -terraform import snowflake_procedure_grant.example 'dbName|schemaName|procedureName(ARG1TYPE,ARG2TYPE)|USAGE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ argument_data_types ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_procedure_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️ARG1TYPE,ARG2TYPE❄️USAGE❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_resource_monitor_grant/import.sh b/examples/resources/snowflake_resource_monitor_grant/import.sh index ea4dfb1ea7..becf19d8f1 100644 --- a/examples/resources/snowflake_resource_monitor_grant/import.sh +++ b/examples/resources/snowflake_resource_monitor_grant/import.sh @@ -1 +1,2 @@ -terraform import snowflake_resource_monitor_grant.example name +# format is resource_monitor_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_resource_monitor_grant.example 'MY_RESOURCE_MONITOR❄️MONITOR❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_role_grants/import.sh b/examples/resources/snowflake_role_grants/import.sh index 3d8fa4ee42..df5709b6fe 100644 --- a/examples/resources/snowflake_role_grants/import.sh +++ b/examples/resources/snowflake_role_grants/import.sh @@ -1 +1,2 @@ -terraform import snowflake_role_grants.example rolename +# format is role_name ❄️ roles ❄️ users +terraform import snowflake_role_grants.example "role_name❄️role1,role2❄️user1,user2" diff --git a/examples/resources/snowflake_row_access_policy_grant/import.sh b/examples/resources/snowflake_row_access_policy_grant/import.sh index a77e4e7289..b6d28eba4e 100644 --- a/examples/resources/snowflake_row_access_policy_grant/import.sh +++ b/examples/resources/snowflake_row_access_policy_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | row access policy name | privilege | true/false for with_grant_option -terraform import snowflake_row_access_policy_grant.example 'dbName|schemaName|rowAccessPolicyName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_row_access_policy_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️SELECT❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_schema_grant/import.sh b/examples/resources/snowflake_schema_grant/import.sh index bc8ee0e928..094f36a145 100644 --- a/examples/resources/snowflake_schema_grant/import.sh +++ b/examples/resources/snowflake_schema_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | | privilege | true/false for with_grant_option -terraform import snowflake_schema_grant.example 'databaseName|schemaName||MONITOR|false' +# format is database_name ❄️ schema_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_schema_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MONITOR❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_sequence_grant/import.sh b/examples/resources/snowflake_sequence_grant/import.sh index 4ef7297141..5922124706 100644 --- a/examples/resources/snowflake_sequence_grant/import.sh +++ b/examples/resources/snowflake_sequence_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | sequence name | privilege | true/false for with_grant_option -terraform import snowflake_sequence_grant.example 'dbName|schemaName|sequenceName|USAGE|false' +# format is database_name ❄️ schema_name ❄️ sequence_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_schema_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️USAGE❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_stage_grant/import.sh b/examples/resources/snowflake_stage_grant/import.sh index 7b59969b12..9d40f1870f 100644 --- a/examples/resources/snowflake_stage_grant/import.sh +++ b/examples/resources/snowflake_stage_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | stage name | privilege | true/false for with_grant_option -terraform import snowflake_stage_grant.example 'databaseName|schemaName|stageName|USAGE|true' +# format is database_name ❄️ schema_name ❄️ stage_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_stage_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️USAGE❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_stream_grant/import.sh b/examples/resources/snowflake_stream_grant/import.sh index 1869e13ccc..71d77c8cd2 100644 --- a/examples/resources/snowflake_stream_grant/import.sh +++ b/examples/resources/snowflake_stream_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | stream name | privilege | true/false for with_grant_option -terraform import snowflake_stream_grant.example 'dbName|schemaName|streamName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ stream_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_stream_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️SELECT❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_table_grant/import.sh b/examples/resources/snowflake_table_grant/import.sh index eca08030f9..a867e0e054 100644 --- a/examples/resources/snowflake_table_grant/import.sh +++ b/examples/resources/snowflake_table_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | table name | privilege | true/false for with_grant_option -terraform import snowflake_table_grant.example 'databaseName|schemaName|tableName|MODIFY|true' +# format is database_name ❄️ schema_name ❄️ table_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_table_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️MODIFY❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_tag_grant/import.sh b/examples/resources/snowflake_tag_grant/import.sh index ec8b3dc578..4019c636bc 100644 --- a/examples/resources/snowflake_tag_grant/import.sh +++ b/examples/resources/snowflake_tag_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | tag name | privilege | roles | true/false for with_grant_option -terraform import snowflake_tag_grant.example 'dbName|schemaName|tagName|APPLY|ROLE1,ROLE2|false' +# format is database_name ❄️ schema_name ❄️ tag_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_tag_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️APPLY❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_task_grant/import.sh b/examples/resources/snowflake_task_grant/import.sh index 767164e725..5b673eefc1 100644 --- a/examples/resources/snowflake_task_grant/import.sh +++ b/examples/resources/snowflake_task_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | task name | privilege | true/false for with_grant_option -terraform import snowflake_pipe_grant.example 'dbName|schemaName|taskName|OPERATE|false' +# format is database_name ❄️ schema_name ❄️ task_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_task_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️OPERATE❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_user_grant/import.sh b/examples/resources/snowflake_user_grant/import.sh index 9076ffb614..d201317f3a 100644 --- a/examples/resources/snowflake_user_grant/import.sh +++ b/examples/resources/snowflake_user_grant/import.sh @@ -1,2 +1,2 @@ -# format is user name | | | privilege | true/false for with_grant_option -terraform import snowflake_user_grant.example 'userName|||MONITOR|true' \ No newline at end of file +# format is username ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_user_grant.example 'USERNAME❄️MONITOR❄️false❄️role1,role2' diff --git a/examples/resources/snowflake_view_grant/import.sh b/examples/resources/snowflake_view_grant/import.sh index b9ab40417e..1dbeb23382 100644 --- a/examples/resources/snowflake_view_grant/import.sh +++ b/examples/resources/snowflake_view_grant/import.sh @@ -1,2 +1,2 @@ -# format is database name | schema name | view name | privilege | true/false for with_grant_option -terraform import snowflake_view_grant.example 'dbName|schemaName|viewName|USAGE|false' +# format is database_name ❄️ schema_name ❄️ view_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_view_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️USAGE❄️false❄️role1,role2❄️share1,share2' diff --git a/examples/resources/snowflake_warehouse_grant/import.sh b/examples/resources/snowflake_warehouse_grant/import.sh index a9d421f4ed..0df319cae6 100644 --- a/examples/resources/snowflake_warehouse_grant/import.sh +++ b/examples/resources/snowflake_warehouse_grant/import.sh @@ -1,2 +1,2 @@ -# format is warehouse name | | | privilege | true/false for with_grant_option -terraform import snowflake_warehouse_grant.example 'warehouseName|||MODIFY|true' +# format is warehouse_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_warehouse_grant.example 'MY_WAREHOUSE❄️MODIFY❄️false❄️role1,role2' diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index 60ffccb6a7..96362ca5ab 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -210,7 +210,7 @@ func NewDatabaseGrantID(databaseName string, privilege string, roles []string, s func (v *DatabaseGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.Privilege, v.WithGrantOption, roles, shares) } func parseDatabaseGrantID(s string) (*DatabaseGrantID, error) { @@ -233,9 +233,9 @@ func parseDatabaseGrantID(s string) (*DatabaseGrantID, error) { return &DatabaseGrantID{ DatabaseName: idParts[0], Privilege: idParts[1], - Roles: helpers.SplitStringToSlice(idParts[2], ","), - Shares: helpers.SplitStringToSlice(idParts[3], ","), - WithGrantOption: idParts[4] == "true", + WithGrantOption: idParts[2] == "true", + Roles: helpers.SplitStringToSlice(idParts[3], ","), + Shares: helpers.SplitStringToSlice(idParts[4], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go index 82a76907cb..aebc3685e2 100644 --- a/pkg/resources/external_table_grant.go +++ b/pkg/resources/external_table_grant.go @@ -290,7 +290,7 @@ func NewExternalTableGrantID(databaseName string, schemaName, objectName, privil func (v *ExternalTableGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) } func parseExternalTableGrant(s string) (*ExternalTableGrantID, error) { @@ -317,9 +317,9 @@ func parseExternalTableGrant(s string) (*ExternalTableGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - Shares: helpers.SplitStringToSlice(idParts[5], ","), - WithGrantOption: idParts[6] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), + Shares: helpers.SplitStringToSlice(idParts[6], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index 7caed83ad3..c75451d49e 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -259,7 +259,7 @@ func NewFileFormatGrantID(databaseName string, schemaName, objectName, privilege func (v *FileFormatGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseFileFormatGrant(s string) (*FileFormatGrantID, error) { @@ -284,7 +284,7 @@ func parseFileFormatGrant(s string) (*FileFormatGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), }, nil } diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index 47927da9e1..e60ded81e4 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -331,7 +331,7 @@ func NewFunctionGrantID(databaseName string, schemaName, objectName string, argu func (v *FunctionGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) } func parseFunctionGrantID(s string) (*FunctionGrantID, error) { @@ -366,9 +366,9 @@ func parseFunctionGrantID(s string) (*FunctionGrantID, error) { ObjectName: idParts[2], ArgumentDataTypes: helpers.SplitStringToSlice(idParts[3], ","), Privilege: idParts[4], - Roles: helpers.SplitStringToSlice(idParts[5], ","), - Shares: helpers.SplitStringToSlice(idParts[6], ","), - WithGrantOption: idParts[7] == "true", + WithGrantOption: idParts[5] == "true", + Roles: helpers.SplitStringToSlice(idParts[6], ","), + Shares: helpers.SplitStringToSlice(idParts[7], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go index 0e2d926928..83dd469407 100644 --- a/pkg/resources/integration_grant.go +++ b/pkg/resources/integration_grant.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -184,7 +185,7 @@ func NewIntegrationGrantID(objectName string, privilege string, roles []string, func (v *IntegrationGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseIntegrationGrantID(s string) (*IntegrationGrantID, error) { @@ -194,7 +195,7 @@ func parseIntegrationGrantID(s string) (*IntegrationGrantID, error) { return &IntegrationGrantID{ ObjectName: idParts[0], Privilege: idParts[3], - Roles: strings.Split(idParts[4], ","), + Roles: helpers.SplitStringToSlice(idParts[4], ","), WithGrantOption: idParts[5] == "true", IsOldID: true, }, nil @@ -206,8 +207,8 @@ func parseIntegrationGrantID(s string) (*IntegrationGrantID, error) { return &IntegrationGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: strings.Split(idParts[2], ","), - WithGrantOption: idParts[3] == "true", + WithGrantOption: idParts[2] == "true", + Roles: helpers.SplitStringToSlice(idParts[3], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go index 5f2a03d733..c96ab390e8 100644 --- a/pkg/resources/materialized_view_grant.go +++ b/pkg/resources/materialized_view_grant.go @@ -288,7 +288,7 @@ func NewMaterializedViewGrantID(databaseName string, schemaName, objectName, pri func (v *MaterializedViewGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) } func parseMaterializedViewGrantID(s string) (*MaterializedViewGrantID, error) { @@ -315,9 +315,9 @@ func parseMaterializedViewGrantID(s string) (*MaterializedViewGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - Shares: helpers.SplitStringToSlice(idParts[5], ","), - WithGrantOption: idParts[6] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), + Shares: helpers.SplitStringToSlice(idParts[6], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index 34f6443feb..12d1cbdc81 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -262,7 +262,7 @@ func NewPipeGrantID(databaseName string, schemaName, objectName, privilege strin func (v *PipeGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.WithGrantOption, v.Privilege, roles) } func parsePipeGrantID(s string) (*PipeGrantID, error) { @@ -288,8 +288,8 @@ func parsePipeGrantID(s string) (*PipeGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index 8a7e462c69..5c7069c9a0 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -341,7 +341,7 @@ func NewProcedureGrantID(databaseName string, schemaName, objectName string, arg func (v *ProcedureGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) } func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { @@ -376,9 +376,9 @@ func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { ObjectName: idParts[2], ArgumentDataTypes: helpers.SplitStringToSlice(idParts[3], ","), Privilege: idParts[4], - Roles: helpers.SplitStringToSlice(idParts[5], ","), - Shares: helpers.SplitStringToSlice(idParts[6], ","), - WithGrantOption: idParts[7] == "true", + WithGrantOption: idParts[5] == "true", + Roles: helpers.SplitStringToSlice(idParts[6], ","), + Shares: helpers.SplitStringToSlice(idParts[7], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index 5463ca3cd9..6cd6efe782 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -182,7 +182,7 @@ func NewResourceMonitorGrantID(objectName string, privilege string, roles []stri func (v *ResourceMonitorGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { @@ -204,8 +204,8 @@ func parseResourceMonitorGrantID(s string) (*ResourceMonitorGrantID, error) { return &ResourceMonitorGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: helpers.SplitStringToSlice(idParts[2], ","), - WithGrantOption: idParts[3] == "true", + WithGrantOption: idParts[2] == "true", + Roles: helpers.SplitStringToSlice(idParts[3], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index 004d824970..cfa120d4ed 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -211,7 +211,7 @@ func NewRowAccessPolicyGrantID(databaseName string, schemaName, objectName, priv func (v *RowAccessPolicyGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseRowAccessPolicyGrantID(s string) (*RowAccessPolicyGrantID, error) { @@ -237,8 +237,8 @@ func parseRowAccessPolicyGrantID(s string) (*RowAccessPolicyGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go index 9e877dcf6d..7f7d357f92 100644 --- a/pkg/resources/schema_grant.go +++ b/pkg/resources/schema_grant.go @@ -296,7 +296,7 @@ func NewSchemaGrantID(databaseName string, schemaName, privilege string, roles [ func (v *SchemaGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.Privilege, v.WithGrantOption, roles, shares) } func parseSchemaGrantID(s string) (*SchemaGrantID, error) { @@ -321,9 +321,9 @@ func parseSchemaGrantID(s string) (*SchemaGrantID, error) { DatabaseName: idParts[0], SchemaName: idParts[1], Privilege: idParts[2], - Roles: helpers.SplitStringToSlice(idParts[3], ","), - Shares: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[3] == "true", + Roles: helpers.SplitStringToSlice(idParts[4], ","), + Shares: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go index e1c24d8fac..4f32fa7dd6 100644 --- a/pkg/resources/sequence_grant.go +++ b/pkg/resources/sequence_grant.go @@ -264,7 +264,7 @@ func NewSequenceGrantID(databaseName string, schemaName, objectName, privilege s func (v *SequenceGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseSequenceGrantID(s string) (*SequenceGrantID, error) { @@ -290,8 +290,8 @@ func parseSequenceGrantID(s string) (*SequenceGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go index 398622dc44..0c8479ff46 100644 --- a/pkg/resources/stage_grant.go +++ b/pkg/resources/stage_grant.go @@ -268,7 +268,7 @@ func NewStageGrantID(databaseName string, schemaName, objectName, privilege stri func (v *StageGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseStageGrantID(s string) (*StageGrantID, error) { @@ -294,8 +294,8 @@ func parseStageGrantID(s string) (*StageGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go index 1e7a62ed93..bcf09c5cbd 100644 --- a/pkg/resources/stream_grant.go +++ b/pkg/resources/stream_grant.go @@ -261,7 +261,7 @@ func NewStreamGrantID(databaseName string, schemaName, objectName, privilege str func (v *StreamGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseStreamGrantID(s string) (*StreamGrantID, error) { @@ -286,7 +286,7 @@ func parseStreamGrantID(s string) (*StreamGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), }, nil } diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go index 996f3d0dbd..b7d352ff2f 100644 --- a/pkg/resources/table_grant.go +++ b/pkg/resources/table_grant.go @@ -310,7 +310,7 @@ func NewTableGrantID(databaseName string, schemaName, objectName, privilege stri func (v *TableGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) } func parseTableGrantID(s string) (*TableGrantID, error) { @@ -337,9 +337,9 @@ func parseTableGrantID(s string) (*TableGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - Shares: helpers.SplitStringToSlice(idParts[5], ","), - WithGrantOption: idParts[6] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), + Shares: helpers.SplitStringToSlice(idParts[6], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go index bc97eca473..7707d9f10f 100644 --- a/pkg/resources/tag_grant.go +++ b/pkg/resources/tag_grant.go @@ -221,7 +221,7 @@ func NewTagGrantID(databaseName string, schemaName, objectName, privilege string func (v *TagGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseTagGrantID(s string) (*TagGrantID, error) { @@ -247,8 +247,8 @@ func parseTagGrantID(s string) (*TagGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go index 640bfd0025..4088b3b6e6 100644 --- a/pkg/resources/task_grant.go +++ b/pkg/resources/task_grant.go @@ -270,7 +270,7 @@ func NewTaskGrantID(databaseName string, schemaName, objectName, privilege strin func (v *TaskGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseTaskGrantID(s string) (*TaskGrantID, error) { @@ -296,8 +296,8 @@ func parseTaskGrantID(s string) (*TaskGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - WithGrantOption: idParts[5] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/user_grant.go b/pkg/resources/user_grant.go index 4fb364a4dd..09dfe57b88 100644 --- a/pkg/resources/user_grant.go +++ b/pkg/resources/user_grant.go @@ -193,7 +193,7 @@ func NewUserGrantID(objectName string, privilege string, roles []string, withGra func (v *UserGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseUserGrantID(s string) (*UserGrantID, error) { @@ -215,8 +215,8 @@ func parseUserGrantID(s string) (*UserGrantID, error) { return &UserGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: helpers.SplitStringToSlice(idParts[2], ","), - WithGrantOption: idParts[3] == "true", + WithGrantOption: idParts[2] == "true", + Roles: helpers.SplitStringToSlice(idParts[3], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go index 6be60fe90a..4fff2ff869 100644 --- a/pkg/resources/view_grant.go +++ b/pkg/resources/view_grant.go @@ -291,7 +291,7 @@ func NewViewGrantID(databaseName string, schemaName, objectName, privilege strin func (v *ViewGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, roles, shares, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) } func parseViewGrantID(s string) (*ViewGrantID, error) { @@ -318,9 +318,9 @@ func parseViewGrantID(s string) (*ViewGrantID, error) { SchemaName: idParts[1], ObjectName: idParts[2], Privilege: idParts[3], - Roles: helpers.SplitStringToSlice(idParts[4], ","), - Shares: helpers.SplitStringToSlice(idParts[5], ","), - WithGrantOption: idParts[6] == "true", + WithGrantOption: idParts[4] == "true", + Roles: helpers.SplitStringToSlice(idParts[5], ","), + Shares: helpers.SplitStringToSlice(idParts[6], ","), IsOldID: false, }, nil } diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go index 10ef5f6cbd..62e20bdce0 100644 --- a/pkg/resources/warehouse_grant.go +++ b/pkg/resources/warehouse_grant.go @@ -200,7 +200,7 @@ func NewWarehouseGrantID(objectName string, privilege string, roles []string, wi func (v *WarehouseGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, roles, v.WithGrantOption) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v", v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parseWarehouseGrantID(s string) (*WarehouseGrantID, error) { @@ -222,8 +222,8 @@ func parseWarehouseGrantID(s string) (*WarehouseGrantID, error) { return &WarehouseGrantID{ ObjectName: idParts[0], Privilege: idParts[1], - Roles: helpers.SplitStringToSlice(idParts[2], ","), - WithGrantOption: idParts[3] == "true", + WithGrantOption: idParts[2] == "true", + Roles: helpers.SplitStringToSlice(idParts[3], ","), IsOldID: false, }, nil } From 9ee983ee66b77210334984cef7cf46d6b05801d2 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 11:19:15 -0800 Subject: [PATCH 18/26] slice helper --- pkg/resources/function_grant.go | 3 ++- pkg/resources/procedure_grant.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index e60ded81e4..99fcad58ca 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -331,7 +331,8 @@ func NewFunctionGrantID(databaseName string, schemaName, objectName string, argu func (v *FunctionGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) + argumentDataTypes := strings.Join(v.ArgumentDataTypes, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, argumentDataTypes, v.Privilege, v.WithGrantOption, roles, shares) } func parseFunctionGrantID(s string) (*FunctionGrantID, error) { diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index 5c7069c9a0..e91942a38d 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -341,7 +341,8 @@ func NewProcedureGrantID(databaseName string, schemaName, objectName string, arg func (v *ProcedureGrantID) String() string { roles := strings.Join(v.Roles, ",") shares := strings.Join(v.Shares, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles, shares) + argumentDataTypes := strings.Join(v.ArgumentDataTypes, ",") + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, argumentDataTypes, v.Privilege, v.WithGrantOption, roles, shares) } func parseProcedureGrantID(s string) (*ProcedureGrantID, error) { From a95bbe40cd6d0692ef7e90d10b4ad6695f410a64 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 11:27:24 -0800 Subject: [PATCH 19/26] update docs --- docs/resources/account_grant.md | 3 +-- docs/resources/database_grant.md | 4 ++-- docs/resources/external_table_grant.md | 4 ++-- docs/resources/file_format_grant.md | 4 ++-- docs/resources/function_grant.md | 4 ++-- docs/resources/integration_grant.md | 4 ++-- docs/resources/materialized_view_grant.md | 4 ++-- docs/resources/pipe_grant.md | 4 ++-- docs/resources/procedure_grant.md | 4 ++-- docs/resources/resource_monitor_grant.md | 3 ++- docs/resources/role_grants.md | 3 ++- docs/resources/row_access_policy_grant.md | 4 ++-- docs/resources/schema_grant.md | 4 ++-- docs/resources/sequence_grant.md | 4 ++-- docs/resources/stage_grant.md | 4 ++-- docs/resources/stream_grant.md | 4 ++-- docs/resources/table_grant.md | 4 ++-- docs/resources/tag_grant.md | 4 ++-- docs/resources/task_grant.md | 4 ++-- docs/resources/user_grant.md | 4 ++-- docs/resources/view_grant.md | 4 ++-- docs/resources/warehouse_grant.md | 4 ++-- 22 files changed, 43 insertions(+), 42 deletions(-) diff --git a/docs/resources/account_grant.md b/docs/resources/account_grant.md index d694bda430..f2dde97bd9 100644 --- a/docs/resources/account_grant.md +++ b/docs/resources/account_grant.md @@ -39,6 +39,5 @@ resource "snowflake_account_grant" "grant" { Import is supported using the following syntax: ```shell -# format is account name | | | privilege | true/false for with_grant_option -terraform import snowflake_account_grant.example 'accountName|||USAGE|true' +terraform import snowflake_account_grant.example 'privilege=MONITOR,roles=[role1,role2],with_grant_option=false' ``` diff --git a/docs/resources/database_grant.md b/docs/resources/database_grant.md index ac6f1411c8..a7ed71dc70 100644 --- a/docs/resources/database_grant.md +++ b/docs/resources/database_grant.md @@ -48,6 +48,6 @@ resource "snowflake_database_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | | | privilege | true/false for with_grant_option -terraform import snowflake_database_grant.example 'databaseName|||USAGE|false' +# format is database_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_database_grant.example 'MY_DATABASE❄️USAGE❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/external_table_grant.md b/docs/resources/external_table_grant.md index e8949db36f..4a9aae910d 100644 --- a/docs/resources/external_table_grant.md +++ b/docs/resources/external_table_grant.md @@ -55,6 +55,6 @@ resource "snowflake_external_table_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | external table name | privilege | true/false for with_grant_option -terraform import snowflake_external_table_grant.example 'dbName|schemaName|externalTableName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_external_table_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️SELECT❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/file_format_grant.md b/docs/resources/file_format_grant.md index 6e0944d575..47c0fd610c 100644 --- a/docs/resources/file_format_grant.md +++ b/docs/resources/file_format_grant.md @@ -52,6 +52,6 @@ resource "snowflake_file_format_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | file format name | privilege | true/false for with_grant_option -terraform import snowflake_file_format_grant.example 'dbName|schemaName|fileFormatName|USAGE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_file_format_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️USAGE❄️false❄️role1,role2' ``` diff --git a/docs/resources/function_grant.md b/docs/resources/function_grant.md index 714f787918..a4d95a935d 100644 --- a/docs/resources/function_grant.md +++ b/docs/resources/function_grant.md @@ -64,6 +64,6 @@ Required: Import is supported using the following syntax: ```shell -# format is database name | schema name | function signature | privilege | true/false for with_grant_option -terraform import snowflake_function_grant.example 'dbName|schemaName|functionName(ARG1TYPE,ARG2TYPE)|USAGE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ argument_data_types ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_function_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️ARG1TYPE,ARG2TYPE❄️USAGE❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/integration_grant.md b/docs/resources/integration_grant.md index f1bcc17d7b..7a13e023a3 100644 --- a/docs/resources/integration_grant.md +++ b/docs/resources/integration_grant.md @@ -46,6 +46,6 @@ resource "snowflake_integration_grant" "grant" { Import is supported using the following syntax: ```shell -# format is integration name ||| privilege | true/false for with_grant_option -terraform import snowflake_integration_grant.example 'intName|||USAGE|true' +# format is integration_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_integration_grant.example 'MY_INTEGRATION❄️USAGE❄️false❄️role1,role2' ``` diff --git a/docs/resources/materialized_view_grant.md b/docs/resources/materialized_view_grant.md index e80cb5401f..1e6133ce06 100644 --- a/docs/resources/materialized_view_grant.md +++ b/docs/resources/materialized_view_grant.md @@ -55,6 +55,6 @@ resource "snowflake_materialized_view_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | materialized view name | privilege | true/false for with_grant_option -terraform import snowflake_materialized_view_grant.example 'dbName|schemaName|materializedViewName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_materialized_view_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️SELECT❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/pipe_grant.md b/docs/resources/pipe_grant.md index 01acd0bcb2..3164ecdca8 100644 --- a/docs/resources/pipe_grant.md +++ b/docs/resources/pipe_grant.md @@ -52,6 +52,6 @@ resource "snowflake_pipe_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | pipe name | privilege | true/false for with_grant_option -terraform import snowflake_pipe_grant.example 'dbName|schemaName|pipeName|OPERATE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_pipe_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️OPERATE❄️false❄️role1,role2' ``` diff --git a/docs/resources/procedure_grant.md b/docs/resources/procedure_grant.md index 38958e0d16..526ff87f22 100644 --- a/docs/resources/procedure_grant.md +++ b/docs/resources/procedure_grant.md @@ -64,6 +64,6 @@ Required: Import is supported using the following syntax: ```shell -# format is database name | schema name | procedure signature | privilege | true/false for with_grant_option -terraform import snowflake_procedure_grant.example 'dbName|schemaName|procedureName(ARG1TYPE,ARG2TYPE)|USAGE|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ argument_data_types ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_procedure_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️ARG1TYPE,ARG2TYPE❄️USAGE❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/resource_monitor_grant.md b/docs/resources/resource_monitor_grant.md index e3143e8776..29af419223 100644 --- a/docs/resources/resource_monitor_grant.md +++ b/docs/resources/resource_monitor_grant.md @@ -44,5 +44,6 @@ resource "snowflake_resource_monitor_grant" "grant" { Import is supported using the following syntax: ```shell -terraform import snowflake_resource_monitor_grant.example name +# format is resource_monitor_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_resource_monitor_grant.example 'MY_RESOURCE_MONITOR❄️MONITOR❄️false❄️role1,role2' ``` diff --git a/docs/resources/role_grants.md b/docs/resources/role_grants.md index e5cd1b58a9..9d3ce2de3c 100644 --- a/docs/resources/role_grants.md +++ b/docs/resources/role_grants.md @@ -68,5 +68,6 @@ resource "snowflake_role_grants" "grants" { Import is supported using the following syntax: ```shell -terraform import snowflake_role_grants.example rolename +# format is role_name ❄️ roles ❄️ users +terraform import snowflake_role_grants.example "role_name❄️role1,role2❄️user1,user2" ``` diff --git a/docs/resources/row_access_policy_grant.md b/docs/resources/row_access_policy_grant.md index 599e2ec939..a599d4775b 100644 --- a/docs/resources/row_access_policy_grant.md +++ b/docs/resources/row_access_policy_grant.md @@ -50,6 +50,6 @@ resource "snowflake_row_access_policy_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | row access policy name | privilege | true/false for with_grant_option -terraform import snowflake_row_access_policy_grant.example 'dbName|schemaName|rowAccessPolicyName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ object_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_row_access_policy_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT_NAME❄️SELECT❄️false❄️role1,role2' ``` diff --git a/docs/resources/schema_grant.md b/docs/resources/schema_grant.md index 5b92a7e659..4fa3be50ea 100644 --- a/docs/resources/schema_grant.md +++ b/docs/resources/schema_grant.md @@ -52,6 +52,6 @@ resource "snowflake_schema_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | | privilege | true/false for with_grant_option -terraform import snowflake_schema_grant.example 'databaseName|schemaName||MONITOR|false' +# format is database_name ❄️ schema_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_schema_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MONITOR❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/sequence_grant.md b/docs/resources/sequence_grant.md index 65b2b5ce76..7f47ef0e42 100644 --- a/docs/resources/sequence_grant.md +++ b/docs/resources/sequence_grant.md @@ -52,6 +52,6 @@ resource "snowflake_sequence_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | sequence name | privilege | true/false for with_grant_option -terraform import snowflake_sequence_grant.example 'dbName|schemaName|sequenceName|USAGE|false' +# format is database_name ❄️ schema_name ❄️ sequence_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_schema_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️USAGE❄️false❄️role1,role2' ``` diff --git a/docs/resources/stage_grant.md b/docs/resources/stage_grant.md index fce0d38779..bf120005fb 100644 --- a/docs/resources/stage_grant.md +++ b/docs/resources/stage_grant.md @@ -53,6 +53,6 @@ resource "snowflake_stage_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | stage name | privilege | true/false for with_grant_option -terraform import snowflake_stage_grant.example 'databaseName|schemaName|stageName|USAGE|true' +# format is database_name ❄️ schema_name ❄️ stage_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_stage_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️USAGE❄️false❄️role1,role2' ``` diff --git a/docs/resources/stream_grant.md b/docs/resources/stream_grant.md index 3b1e35e242..337c02563f 100644 --- a/docs/resources/stream_grant.md +++ b/docs/resources/stream_grant.md @@ -52,6 +52,6 @@ resource "snowflake_stream_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | stream name | privilege | true/false for with_grant_option -terraform import snowflake_stream_grant.example 'dbName|schemaName|streamName|SELECT|false' +# format is database_name ❄️ schema_name ❄️ stream_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_stream_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️SELECT❄️false❄️role1,role2' ``` diff --git a/docs/resources/table_grant.md b/docs/resources/table_grant.md index b968500684..8aaca14249 100644 --- a/docs/resources/table_grant.md +++ b/docs/resources/table_grant.md @@ -54,6 +54,6 @@ resource "snowflake_table_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | table name | privilege | true/false for with_grant_option -terraform import snowflake_table_grant.example 'databaseName|schemaName|tableName|MODIFY|true' +# format is database_name ❄️ schema_name ❄️ table_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_table_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️MODIFY❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/tag_grant.md b/docs/resources/tag_grant.md index 9ae8bafdb2..a30a4f2734 100644 --- a/docs/resources/tag_grant.md +++ b/docs/resources/tag_grant.md @@ -48,6 +48,6 @@ resource "snowflake_tag_grant" "example" { Import is supported using the following syntax: ```shell -# format is database name | schema name | tag name | privilege | roles | true/false for with_grant_option -terraform import snowflake_tag_grant.example 'dbName|schemaName|tagName|APPLY|ROLE1,ROLE2|false' +# format is database_name ❄️ schema_name ❄️ tag_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_tag_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️APPLY❄️false❄️role1,role2' ``` diff --git a/docs/resources/task_grant.md b/docs/resources/task_grant.md index 4ac5afb4fa..cc0e7e3ca5 100644 --- a/docs/resources/task_grant.md +++ b/docs/resources/task_grant.md @@ -52,6 +52,6 @@ resource "snowflake_task_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | task name | privilege | true/false for with_grant_option -terraform import snowflake_pipe_grant.example 'dbName|schemaName|taskName|OPERATE|false' +# format is database_name ❄️ schema_name ❄️ task_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_task_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️OPERATE❄️false❄️role1,role2' ``` diff --git a/docs/resources/user_grant.md b/docs/resources/user_grant.md index fa51bef62c..273d11ee94 100644 --- a/docs/resources/user_grant.md +++ b/docs/resources/user_grant.md @@ -46,6 +46,6 @@ resource "snowflake_user_grant" "grant" { Import is supported using the following syntax: ```shell -# format is user name | | | privilege | true/false for with_grant_option -terraform import snowflake_user_grant.example 'userName|||MONITOR|true' +# format is username ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_user_grant.example 'USERNAME❄️MONITOR❄️false❄️role1,role2' ``` diff --git a/docs/resources/view_grant.md b/docs/resources/view_grant.md index 6d79cea975..9f026d4e5f 100644 --- a/docs/resources/view_grant.md +++ b/docs/resources/view_grant.md @@ -68,6 +68,6 @@ resource "snowflake_schema_grant" "grant" { Import is supported using the following syntax: ```shell -# format is database name | schema name | view name | privilege | true/false for with_grant_option -terraform import snowflake_view_grant.example 'dbName|schemaName|viewName|USAGE|false' +# format is database_name ❄️ schema_name ❄️ view_name ❄️ privilege ❄️ with_grant_option ❄️ roles ❄️ shares +terraform import snowflake_view_grant.example 'MY_DATABASE❄️MY_SCHEMA❄️MY_OBJECT❄️USAGE❄️false❄️role1,role2❄️share1,share2' ``` diff --git a/docs/resources/warehouse_grant.md b/docs/resources/warehouse_grant.md index 3b3637634e..4350ff4bc5 100644 --- a/docs/resources/warehouse_grant.md +++ b/docs/resources/warehouse_grant.md @@ -46,6 +46,6 @@ resource "snowflake_warehouse_grant" "grant" { Import is supported using the following syntax: ```shell -# format is warehouse name | | | privilege | true/false for with_grant_option -terraform import snowflake_warehouse_grant.example 'warehouseName|||MODIFY|true' +# format is warehouse_name ❄️ privilege ❄️ with_grant_option ❄️ roles +terraform import snowflake_warehouse_grant.example 'MY_WAREHOUSE❄️MODIFY❄️false❄️role1,role2' ``` From 691ae2d8510b4bac26c1ec3119a882736e1fb802 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 12:12:32 -0800 Subject: [PATCH 20/26] update docs --- pkg/resources/pipe_grant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index 12d1cbdc81..401552cc89 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -262,7 +262,7 @@ func NewPipeGrantID(databaseName string, schemaName, objectName, privilege strin func (v *PipeGrantID) String() string { roles := strings.Join(v.Roles, ",") - return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.WithGrantOption, v.Privilege, roles) + return fmt.Sprintf("%v❄️%v❄️%v❄️%v❄️%v❄️%v", v.DatabaseName, v.SchemaName, v.ObjectName, v.Privilege, v.WithGrantOption, roles) } func parsePipeGrantID(s string) (*PipeGrantID, error) { From 24acb493d3600a0ed4b904b58fb5b6c64163a7fe Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 13:04:52 -0800 Subject: [PATCH 21/26] update docs --- pkg/resources/file_format_grant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index c75451d49e..8d353cba24 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -174,7 +174,7 @@ func ReadFileFormatGrant(d *schema.ResourceData, meta interface{}) error { // DeleteFileFormatGrant implements schema.DeleteFunc. func DeleteFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - grantID, err := parseFunctionGrantID(d.Id()) + grantID, err := parseFileFormatGrant(d.Id()) if err != nil { return err } From f21099a92ac2440115fff4feae2a131d58a8ff9e Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 14:51:51 -0800 Subject: [PATCH 22/26] revert account grant ID --- pkg/resources/account_grant.go | 77 ++++++++++++++++++++++++++++++---- pkg/resources/role_grants.go | 6 +-- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/pkg/resources/account_grant.go b/pkg/resources/account_grant.go index 053727904c..83883548d5 100644 --- a/pkg/resources/account_grant.go +++ b/pkg/resources/account_grant.go @@ -2,6 +2,8 @@ package resources import ( "context" + "fmt" + "strings" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" @@ -86,20 +88,20 @@ func AccountGrant() *TerraformGrantResource { Schema: accountGrantSchema, Importer: &schema.ResourceImporter{ StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - v, err := helpers.DecodeSnowflakeImportID(d.Id(), AccountGrantID{}) + v, err := helpers.DecodeSnowflakeImportID(d.Id(), AccountGrantImporter{}) if err != nil { return nil, err } - id := v.(AccountGrantID) - err = d.Set("privilege", id.Privilege) + importer := v.(AccountGrantImporter) + err = d.Set("privilege", importer.Privilege) if err != nil { return nil, err } - err = d.Set("roles", id.Roles) + err = d.Set("roles", importer.Roles) if err != nil { return nil, err } - err = d.Set("with_grant_option", id.WithGrantOption) + err = d.Set("with_grant_option", importer.WithGrantOption) if err != nil { return nil, err } @@ -112,12 +114,56 @@ func AccountGrant() *TerraformGrantResource { } } -type AccountGrantID struct { +type AccountGrantImporter struct { Privilege string `tf:"privilege"` Roles []string `tf:"roles"` WithGrantOption bool `tf:"with_grant_option"` } +type AccountGrantID struct { + Privilege string + Roles []string + WithGrantOption bool + IsOldID bool +} + +func NewAccountGrantID(privilege string, roles []string, withGrantOption bool) *AccountGrantID { + return &AccountGrantID{ + Privilege: privilege, + Roles: roles, + WithGrantOption: withGrantOption, + IsOldID: false, + } +} + +func (v *AccountGrantID) String() string { + roles := strings.Join(v.Roles, ",") + return fmt.Sprintf("%v❄️%v❄️%v", v.Privilege, v.WithGrantOption, roles) +} + +func parseAccountGrantID(s string) (*AccountGrantID, error) { + // is this an old ID format? + if !strings.Contains(s, "❄️") { + idParts := strings.Split(s, "|") + return &AccountGrantID{ + Privilege: idParts[3], + Roles: []string{}, + WithGrantOption: idParts[4] == "true", + IsOldID: true, + }, nil + } + idParts := strings.Split(s, "❄️") + if len(idParts) != 5 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 5", len(idParts)) + } + return &AccountGrantID{ + Privilege: idParts[0], + WithGrantOption: idParts[1] == "true", + Roles: helpers.SplitStringToSlice(idParts[2], ","), + IsOldID: false, + }, nil +} + // CreateAccountGrant implements schema.CreateFunc. func CreateAccountGrant(d *schema.ResourceData, meta interface{}) error { builder := snowflake.AccountGrant() @@ -126,7 +172,11 @@ func CreateAccountGrant(d *schema.ResourceData, meta interface{}) error { return err } - d.SetId(helpers.RandomSnowflakeID()) + privilege := d.Get("privilege").(string) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + withGrantOption := d.Get("with_grant_option").(bool) + grantID := NewAccountGrantID(privilege, roles, withGrantOption) + d.SetId(grantID.String()) return ReadAccountGrant(d, meta) } @@ -134,6 +184,19 @@ func CreateAccountGrant(d *schema.ResourceData, meta interface{}) error { // ReadAccountGrant implements schema.ReadFunc. func ReadAccountGrant(d *schema.ResourceData, meta interface{}) error { builder := snowflake.AccountGrant() + grantID, err := parseAccountGrantID(d.Id()) + if err != nil { + return err + } + if err := d.Set("privilege", grantID.Privilege); err != nil { + return err + } + if err := d.Set("roles", grantID.Roles); err != nil { + return err + } + if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil { + return err + } return readGenericGrant(d, meta, accountGrantSchema, builder, false, validAccountPrivileges) } diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go index 32d2fcb680..21e4a82963 100644 --- a/pkg/resources/role_grants.go +++ b/pkg/resources/role_grants.go @@ -112,8 +112,6 @@ func ReadRoleGrants(d *schema.ResourceData, meta interface{}) error { return err } - tfRoles := d.Get("roles").(*schema.Set).List() - tfUsers := d.Get("users").(*schema.Set).List() roles := make([]string, 0) users := make([]string, 0) @@ -125,13 +123,13 @@ func ReadRoleGrants(d *schema.ResourceData, meta interface{}) error { for _, grant := range grants { switch grant.GrantedTo.String { case "ROLE": - for _, tfRole := range tfRoles { + for _, tfRole := range grantID.Roles { if tfRole == grant.GranteeName.String { roles = append(roles, grant.GranteeName.String) } } case "USER": - for _, tfUser := range tfUsers { + for _, tfUser := range grantID.Users { if tfUser == grant.GranteeName.String { users = append(users, grant.GranteeName.String) } From 5708fc2074e67d6b10dda3f763830c1392f5185d Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 15:33:01 -0800 Subject: [PATCH 23/26] revert account grant ID --- pkg/resources/role_grants_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/resources/role_grants_test.go b/pkg/resources/role_grants_test.go index 51a2ea7f63..514c11dee9 100644 --- a/pkg/resources/role_grants_test.go +++ b/pkg/resources/role_grants_test.go @@ -121,7 +121,7 @@ func TestIgnoreUnknownRoleGrants(t *testing.T) { expectReadUnhandledRoleGrants(mock) err := resources.ReadRoleGrants(d, db) r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 2) - r.Len(d.Get("roles").(*schema.Set).List(), 2) + r.Len(d.Get("users").(*schema.Set).List(), 0) + r.Len(d.Get("roles").(*schema.Set).List(), 0) }) } From 262d855ef5e0c178fe66382be9976c83d52a9b03 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 15:46:49 -0800 Subject: [PATCH 24/26] revert account grant ID --- pkg/resources/role_grants_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/resources/role_grants_test.go b/pkg/resources/role_grants_test.go index 514c11dee9..79690ea3fc 100644 --- a/pkg/resources/role_grants_test.go +++ b/pkg/resources/role_grants_test.go @@ -66,8 +66,8 @@ func TestRoleGrantsRead(t *testing.T) { expectReadRoleGrants(mock) err := resources.ReadRoleGrants(d, db) r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 2) - r.Len(d.Get("roles").(*schema.Set).List(), 2) + r.Len(d.Get("users").(*schema.Set).List(), 0) + r.Len(d.Get("roles").(*schema.Set).List(), 0) }) } @@ -121,7 +121,7 @@ func TestIgnoreUnknownRoleGrants(t *testing.T) { expectReadUnhandledRoleGrants(mock) err := resources.ReadRoleGrants(d, db) r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 0) - r.Len(d.Get("roles").(*schema.Set).List(), 0) + r.Len(d.Get("users").(*schema.Set).List(), 2) + r.Len(d.Get("roles").(*schema.Set).List(), 2) }) } From 2652203a84d1b66461828c7fcf7c034a1af68f44 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 16:01:08 -0800 Subject: [PATCH 25/26] revert account grant ID --- pkg/resources/role_grants_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/resources/role_grants_test.go b/pkg/resources/role_grants_test.go index 79690ea3fc..7f3c840a63 100644 --- a/pkg/resources/role_grants_test.go +++ b/pkg/resources/role_grants_test.go @@ -67,7 +67,7 @@ func TestRoleGrantsRead(t *testing.T) { err := resources.ReadRoleGrants(d, db) r.NoError(err) r.Len(d.Get("users").(*schema.Set).List(), 0) - r.Len(d.Get("roles").(*schema.Set).List(), 0) + r.Len(d.Get("roles").(*schema.Set).List(), 2) }) } @@ -121,7 +121,7 @@ func TestIgnoreUnknownRoleGrants(t *testing.T) { expectReadUnhandledRoleGrants(mock) err := resources.ReadRoleGrants(d, db) r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 2) + r.Len(d.Get("users").(*schema.Set).List(), 0) r.Len(d.Get("roles").(*schema.Set).List(), 2) }) } From 1f3fd2a9ce78369af70f1c1623e68b319a8c1708 Mon Sep 17 00:00:00 2001 From: Scott Winkler Date: Thu, 16 Feb 2023 16:13:38 -0800 Subject: [PATCH 26/26] revert account grant ID --- pkg/resources/account_grant.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/resources/account_grant.go b/pkg/resources/account_grant.go index 83883548d5..216da64cc9 100644 --- a/pkg/resources/account_grant.go +++ b/pkg/resources/account_grant.go @@ -153,8 +153,8 @@ func parseAccountGrantID(s string) (*AccountGrantID, error) { }, nil } idParts := strings.Split(s, "❄️") - if len(idParts) != 5 { - return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 5", len(idParts)) + if len(idParts) != 3 { + return nil, fmt.Errorf("unexpected number of ID parts (%d), expected 3", len(idParts)) } return &AccountGrantID{ Privilege: idParts[0],