From 57c3c3778dfcae33c8075902133d49045981e7d7 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Sat, 12 Mar 2022 12:32:07 -0700 Subject: [PATCH 01/15] create snowflake_role_ownership_grants resource --- .../snowflake_role_ownership_grants/import.sh | 1 + .../resource.tf | 30 +++ pkg/provider/provider.go | 1 + pkg/resources/role_ownership_grants.go | 236 ++++++++++++++++++ pkg/snowflake/role_ownership_grant.go | 41 +++ 5 files changed, 309 insertions(+) create mode 100644 examples/resources/snowflake_role_ownership_grants/import.sh create mode 100644 examples/resources/snowflake_role_ownership_grants/resource.tf create mode 100644 pkg/resources/role_ownership_grants.go create mode 100644 pkg/snowflake/role_ownership_grant.go diff --git a/examples/resources/snowflake_role_ownership_grants/import.sh b/examples/resources/snowflake_role_ownership_grants/import.sh new file mode 100644 index 0000000000..27ab4d842f --- /dev/null +++ b/examples/resources/snowflake_role_ownership_grants/import.sh @@ -0,0 +1 @@ +terraform import snowflake_role_ownership_grants.example rolename diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf new file mode 100644 index 0000000000..a6ce19bed5 --- /dev/null +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -0,0 +1,30 @@ +resource "snowflake_role" "role" { + name = "rking_test_role" + comment = "for testing" +} + +resource "snowflake_user" "user" { + name = "rking_test_user" + comment = "for testing" +} + +resource "snowflake_user" "user2" { + name = "rking_test_user2" + comment = "for testing" +} + +resource "snowflake_role" "other_role" { + name = "rking_test_role2" +} + +resource "snowflake_role_ownership_grants" "grants" { + role_name = "${snowflake_role.role.name}" + + roles = [ + "${snowflake_role.other_role.name}", + ] + + users = [ + "${snowflake_user.user.name}", + ] +} \ No newline at end of file diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 03fb510000..f34e7a9efb 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -184,6 +184,7 @@ func getResources() map[string]*schema.Resource { "snowflake_resource_monitor": resources.ResourceMonitor(), "snowflake_role": resources.Role(), "snowflake_role_grants": resources.RoleGrants(), + "snowflake_role_ownership_grants": resources.RoleOwnershipGrants(), "snowflake_row_access_policy": resources.RowAccessPolicy(), "snowflake_saml_integration": resources.SAMLIntegration(), "snowflake_schema": resources.Schema(), diff --git a/pkg/resources/role_ownership_grants.go b/pkg/resources/role_ownership_grants.go new file mode 100644 index 0000000000..262483b838 --- /dev/null +++ b/pkg/resources/role_ownership_grants.go @@ -0,0 +1,236 @@ +package resources + +import ( + "database/sql" + "fmt" + "log" + + "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/pkg/errors" +) + +func RoleOwnershipGrants() *schema.Resource { + return &schema.Resource{ + Create: CreateRoleOwnershipGrants, + Read: ReadRoleOwnershipGrants, + Delete: DeleteRoleOwnershipGrants, + Update: UpdateRoleOwnershipGrants, + + Schema: map[string]*schema.Schema{ + "role_name": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Required: true, + Description: "The name of the role to grant ownership to. Please ensure that the role that terraform is using is granted access.", + ValidateFunc: func(val interface{}, key string) ([]string, []error) { + return snowflake.ValidateIdentifier(val) + }, + }, + "roles": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "Grants role to this specified role.", + }, + "users": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "Grants role to this specified user.", + }, + }, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + } +} + +func CreateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + roleName := d.Get("role_name").(string) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + users := expandStringList(d.Get("users").(*schema.Set).List()) + + if len(roles) == 0 && len(users) == 0 { + return fmt.Errorf("no users or roles specified for role grants") + } + + grant := &grantID{ + ResourceName: roleName, + Roles: roles, + } + dataIDInput, err := grant.String() + d.SetId(dataIDInput) + + if err != nil { + return errors.Wrap(err, "error creating role grant") + } + for _, role := range roles { + err := grantRoleOwnershipToRole(db, roleName, role) + if err != nil { + return err + } + } + + for _, user := range users { + err := grantRoleOwnershipToUser(db, roleName, user) + if err != nil { + return err + } + } + + return ReadRoleOwnershipGrants(d, meta) +} + +func grantRoleOwnershipToRole(db *sql.DB, role1, role2 string) error { + g := snowflake.RoleOwnershipGrant(role1) + err := snowflake.Exec(db, g.Role(role2).Grant()) + return err +} + +func grantRoleOwnershipToUser(db *sql.DB, role1, user string) error { + g := snowflake.RoleOwnershipGrant(role1) + err := snowflake.Exec(db, g.User(user).Grant()) + return err +} + +func ReadRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + log.Println(d.Id()) + grantID, err := grantIDFromString(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()) + + roles := make([]string, 0) + users := make([]string, 0) + + grants, err := readGrants(db, roleName) + if err != nil { + return err + } + + for _, grant := range grants { + switch grant.GrantedTo.String { + case "ROLE": + for _, tfRole := range tfRoles { + if tfRole == grant.GranteeName.String { + roles = append(roles, grant.GranteeName.String) + } + } + case "USER": + for _, tfUser := range tfUsers { + if tfUser == grant.GranteeName.String { + users = append(users, grant.GranteeName.String) + } + } + default: + return fmt.Errorf("unknown grant type %s", grant.GrantedTo.String) + } + } + + err = d.Set("role_name", roleName) + if err != nil { + return err + } + err = d.Set("roles", roles) + if err != nil { + return err + } + err = d.Set("users", users) + if err != nil { + return err + } + + return nil +} + +func DeleteRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + roleName := d.Get("role_name").(string) + + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + users := expandStringList(d.Get("users").(*schema.Set).List()) + + for _, role := range roles { + err := revokeRoleFromRole(db, roleName, role) + if err != nil { + return err + } + } + + for _, user := range users { + err := revokeRoleFromUser(db, roleName, user) + if err != nil { + return err + } + } + + d.SetId("") + return nil +} + +func revokeRoleOwnershipFromRole(db *sql.DB, role1, role2 string) error { + rg := snowflake.RoleOwnershipGrant(role1).Role(role2) + err := snowflake.Exec(db, rg.Revoke()) + return err +} + +func revokeRoleOwnershipFromUser(db *sql.DB, role1, user string) error { + rg := snowflake.RoleOwnershipGrant(role1).User(user) + err := snowflake.Exec(db, rg.Revoke()) + return err +} + +func UpdateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + roleName := d.Get("role_name").(string) + + x := func(resource string, grant func(db *sql.DB, role string, target string) error, revoke func(db *sql.DB, role string, target string) error) error { + o, n := d.GetChange(resource) + + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) + } + os := o.(*schema.Set) + ns := n.(*schema.Set) + + remove := expandStringList(os.Difference(ns).List()) + add := expandStringList(ns.Difference(os).List()) + + for _, user := range remove { + err := revoke(db, roleName, user) + if err != nil { + return err + } + } + for _, user := range add { + err := grant(db, roleName, user) + if err != nil { + return err + } + } + return nil + } + + err := x("users", grantRoleOwnershipToUser, revokeRoleOwnershipFromUser) + if err != nil { + return err + } + + err = x("roles", grantRoleOwnershipToRole, revokeRoleOwnershipFromRole) + if err != nil { + return err + } + + return ReadRoleOwnershipGrants(d, meta) +} diff --git a/pkg/snowflake/role_ownership_grant.go b/pkg/snowflake/role_ownership_grant.go new file mode 100644 index 0000000000..7095c1643b --- /dev/null +++ b/pkg/snowflake/role_ownership_grant.go @@ -0,0 +1,41 @@ +package snowflake + +import "fmt" + +type RoleOwnershipGrantBuilder struct { + name string +} + +type RoleOwnershipGrantExecutable struct { + name string + granteeType granteeType + grantee string +} + +func RoleOwnershipGrant(name string) *RoleOwnershipGrantBuilder { + return &RoleOwnershipGrantBuilder{name: name} +} + +func (gb *RoleOwnershipGrantBuilder) User(user string) *RoleOwnershipGrantExecutable { + return &RoleOwnershipGrantExecutable{ + name: gb.name, + granteeType: userType, + grantee: user, + } +} + +func (gb *RoleOwnershipGrantBuilder) Role(role string) *RoleOwnershipGrantExecutable { + return &RoleOwnershipGrantExecutable{ + name: gb.name, + granteeType: roleType, + grantee: role, + } +} + +func (gr *RoleOwnershipGrantExecutable) Grant() string { + return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" COPY CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.name) // nolint: gosec +} + +func (gr *RoleOwnershipGrantExecutable) Revoke() string { + return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`, gr.granteeType, gr.grantee) // nolint: gosec +} From c6d698b7ef326a4a20990b6248fd10769cfe8855 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Sat, 12 Mar 2022 13:01:17 -0700 Subject: [PATCH 02/15] fixed issue where snowflake_role_ownership_grant example would fail because terraform would lose ownership of the role. --- .../snowflake_role_ownership_grants/resource.tf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index a6ce19bed5..d572c3e14b 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -17,6 +17,15 @@ resource "snowflake_role" "other_role" { name = "rking_test_role2" } +# ensure Terraform user has privileges +resource "snowflake_role_grants" "grants" { + role_name = "${snowflake_role.role.name}" + + roles = [ + "ACCOUNTADMIN", + ] +} + resource "snowflake_role_ownership_grants" "grants" { role_name = "${snowflake_role.role.name}" From 896af15f2a09c37c43f35ec1ad4be525b4225391 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Sat, 12 Mar 2022 13:08:17 -0700 Subject: [PATCH 03/15] added comment to example --- examples/resources/snowflake_role_ownership_grants/resource.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index d572c3e14b..beb44f39d0 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -17,7 +17,8 @@ resource "snowflake_role" "other_role" { name = "rking_test_role2" } -# ensure Terraform user has privileges +# ensure the Terraform user inherits ownership privileges for the rking_test_user role +# otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges resource "snowflake_role_grants" "grants" { role_name = "${snowflake_role.role.name}" From 4ef110b94c51ddbb6ffcdd1b3c282e71036c8cd4 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Sat, 12 Mar 2022 14:37:52 -0700 Subject: [PATCH 04/15] updated arguement descriptions for clarity. --- pkg/resources/role_ownership_grants.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/resources/role_ownership_grants.go b/pkg/resources/role_ownership_grants.go index 262483b838..94a87eeec3 100644 --- a/pkg/resources/role_ownership_grants.go +++ b/pkg/resources/role_ownership_grants.go @@ -22,7 +22,7 @@ func RoleOwnershipGrants() *schema.Resource { Type: schema.TypeString, Elem: &schema.Schema{Type: schema.TypeString}, Required: true, - Description: "The name of the role to grant ownership to. Please ensure that the role that terraform is using is granted access.", + Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", ValidateFunc: func(val interface{}, key string) ([]string, []error) { return snowflake.ValidateIdentifier(val) }, @@ -31,13 +31,13 @@ func RoleOwnershipGrants() *schema.Resource { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, - Description: "Grants role to this specified role.", + Description: "Grants role ownership to these specified roles.", }, "users": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, - Description: "Grants role to this specified user.", + Description: "Grants role ownership to these specified users.", }, }, From 77617ae53af11aca8e28a09c56a72cfb27e1ae5f Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Sun, 13 Mar 2022 23:08:54 -0600 Subject: [PATCH 05/15] read not working. --- .../resource.tf | 20 +- pkg/resources/helpers_test.go | 8 + pkg/resources/role_ownership_grant.go | 171 +++++++++++++ pkg/resources/role_ownership_grants.go | 236 ------------------ pkg/snowflake/role_ownership_grant.go | 33 ++- 5 files changed, 196 insertions(+), 272 deletions(-) create mode 100644 pkg/resources/role_ownership_grant.go delete mode 100644 pkg/resources/role_ownership_grants.go diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index beb44f39d0..7923c8d7b3 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -3,16 +3,6 @@ resource "snowflake_role" "role" { comment = "for testing" } -resource "snowflake_user" "user" { - name = "rking_test_user" - comment = "for testing" -} - -resource "snowflake_user" "user2" { - name = "rking_test_user2" - comment = "for testing" -} - resource "snowflake_role" "other_role" { name = "rking_test_role2" } @@ -28,13 +18,9 @@ resource "snowflake_role_grants" "grants" { } resource "snowflake_role_ownership_grants" "grants" { - role_name = "${snowflake_role.role.name}" + on_role_name = "${snowflake_role.role.name}" - roles = [ - "${snowflake_role.other_role.name}", - ] + to_role_name = "${snowflake_role.other_role.name}" - users = [ - "${snowflake_user.user.name}", - ] + current_grants = "COPY" } \ No newline at end of file diff --git a/pkg/resources/helpers_test.go b/pkg/resources/helpers_test.go index 8a0e2a33d9..5943112ab5 100644 --- a/pkg/resources/helpers_test.go +++ b/pkg/resources/helpers_test.go @@ -192,6 +192,14 @@ func roleGrants(t *testing.T, id string, params map[string]interface{}) *schema. return d } +func roleOwnershipGrants(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { + r := require.New(t) + d := schema.TestResourceDataRaw(t, resources.RoleOwnershipGrants().Schema, params) + r.NotNil(d) + d.SetId(id) + return d +} + func apiIntegration(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { r := require.New(t) d := schema.TestResourceDataRaw(t, resources.APIIntegration().Schema, params) diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go new file mode 100644 index 0000000000..ffdca7c625 --- /dev/null +++ b/pkg/resources/role_ownership_grant.go @@ -0,0 +1,171 @@ +package resources + +import ( + "database/sql" + "fmt" + "log" + "strings" + + "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/jmoiron/sqlx" +) + +func RoleOwnershipGrants() *schema.Resource { + return &schema.Resource{ + Create: CreateRoleOwnershipGrants, + Read: ReadRoleOwnershipGrants, + Delete: DeleteRoleOwnershipGrants, + Update: UpdateRoleOwnershipGrants, + + Schema: map[string]*schema.Schema{ + "on_role_name": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Required: true, + Description: "The name of the role ownership is granted on.", + ValidateFunc: func(val interface{}, key string) ([]string, []error) { + return snowflake.ValidateIdentifier(val) + }, + }, + "to_role_name": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Required: true, + Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", + ValidateFunc: func(val interface{}, key string) ([]string, []error) { + return snowflake.ValidateIdentifier(val) + }, + }, + "current_grants": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role.", + Default: "COPY", + ValidateFunc: validation.StringInSlice([]string{ + "COPY", + "REVOKE", + }, true), + }, + }, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + } +} + +func CreateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + onRoleName := d.Get("on_role_name").(string) + toRoleName := d.Get("to_role_name").(string) + currentGrants := d.Get("current_grants").(string) + + g := snowflake.RoleOwnershipGrant(onRoleName) + err := snowflake.Exec(db, g.Role(toRoleName, currentGrants).Grant()) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) + + return ReadRoleOwnershipGrants(d, meta) +} + +func ReadRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + log.Println(d.Id()) + onRoleName := strings.Split(d.Id(), "|")[0] + toRoleName := strings.Split(d.Id(), "|")[1] + currentGrants := strings.Split(d.Id(), "|")[2] + + err := readOwnershipGrants(db, onRoleName) + if err != nil { + return err + } + + err = d.Set("on_role_name", onRoleName) + if err != nil { + return err + } + + err = d.Set("to_role_name", toRoleName) + if err != nil { + return err + } + + err = d.Set("current_grants", currentGrants) + if err != nil { + return err + } + + return nil +} + +type roleOwnershipGrant struct { + CreatedOn sql.RawBytes `db:"created_on"` + Name sql.NullString `db:"name"` + IsDefault sql.NullString `db:"is_default"` + IsCurrent sql.NullString `db:"is_current"` + IsInherited sql.NullString `db:"is_inherited"` + AssignedToUsers sql.NullString `db:"assigned_to_users"` + GrantedToRoles sql.NullString `db:"granted_to_roles"` + GrantedRoles sql.NullString `db:"granted_roles"` + Owner sql.NullString `db:"owner"` + Comment sql.NullString `db:"comment"` +} + +func readOwnershipGrants(db *sql.DB, onRoleName string) error { + sdb := sqlx.NewDb(db, "snowflake") + + stmt := fmt.Sprintf(`SHOW ROLES LIKE '%s'`, onRoleName) + + row := sdb.QueryRowx(stmt) + + g := &roleOwnershipGrant{} + err := row.StructScan(g) + if err != nil { + return err + } + + if g.Owner.Valid { + s := g.Owner.String + s = strings.TrimPrefix(s, `"`) + s = strings.TrimSuffix(s, `"`) + g.Owner = sql.NullString{String: s} + } + + return nil +} + +func DeleteRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + onRoleName := d.Get("on_role_name").(string) + currentGrants := d.Get("current_grants").(string) + + g := snowflake.RoleOwnershipGrant(onRoleName, currentGrants) + err := snowflake.Exec(db, g.Role("ACCOUNTADMIN").Revoke()) + if err != nil { + return err + } + + d.SetId("") + return nil +} + +func UpdateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + onRoleName := d.Get("on_role_name").(string) + toRoleName := d.Get("to_role_name").(string) + currentGrants := d.Get("current_grants").(string) + + g := snowflake.RoleOwnershipGrant(onRoleName, currentGrants) + err := snowflake.Exec(db, g.Role(toRoleName).Revoke()) + if err != nil { + return err + } + + return ReadRoleOwnershipGrants(d, meta) +} diff --git a/pkg/resources/role_ownership_grants.go b/pkg/resources/role_ownership_grants.go deleted file mode 100644 index 94a87eeec3..0000000000 --- a/pkg/resources/role_ownership_grants.go +++ /dev/null @@ -1,236 +0,0 @@ -package resources - -import ( - "database/sql" - "fmt" - "log" - - "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/pkg/errors" -) - -func RoleOwnershipGrants() *schema.Resource { - return &schema.Resource{ - Create: CreateRoleOwnershipGrants, - Read: ReadRoleOwnershipGrants, - Delete: DeleteRoleOwnershipGrants, - Update: UpdateRoleOwnershipGrants, - - Schema: map[string]*schema.Schema{ - "role_name": { - Type: schema.TypeString, - Elem: &schema.Schema{Type: schema.TypeString}, - Required: true, - Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - return snowflake.ValidateIdentifier(val) - }, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants role ownership to these specified roles.", - }, - "users": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants role ownership to these specified users.", - }, - }, - - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - } -} - -func CreateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { - db := meta.(*sql.DB) - roleName := d.Get("role_name").(string) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - users := expandStringList(d.Get("users").(*schema.Set).List()) - - if len(roles) == 0 && len(users) == 0 { - return fmt.Errorf("no users or roles specified for role grants") - } - - grant := &grantID{ - ResourceName: roleName, - Roles: roles, - } - dataIDInput, err := grant.String() - d.SetId(dataIDInput) - - if err != nil { - return errors.Wrap(err, "error creating role grant") - } - for _, role := range roles { - err := grantRoleOwnershipToRole(db, roleName, role) - if err != nil { - return err - } - } - - for _, user := range users { - err := grantRoleOwnershipToUser(db, roleName, user) - if err != nil { - return err - } - } - - return ReadRoleOwnershipGrants(d, meta) -} - -func grantRoleOwnershipToRole(db *sql.DB, role1, role2 string) error { - g := snowflake.RoleOwnershipGrant(role1) - err := snowflake.Exec(db, g.Role(role2).Grant()) - return err -} - -func grantRoleOwnershipToUser(db *sql.DB, role1, user string) error { - g := snowflake.RoleOwnershipGrant(role1) - err := snowflake.Exec(db, g.User(user).Grant()) - return err -} - -func ReadRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { - db := meta.(*sql.DB) - log.Println(d.Id()) - grantID, err := grantIDFromString(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()) - - roles := make([]string, 0) - users := make([]string, 0) - - grants, err := readGrants(db, roleName) - if err != nil { - return err - } - - for _, grant := range grants { - switch grant.GrantedTo.String { - case "ROLE": - for _, tfRole := range tfRoles { - if tfRole == grant.GranteeName.String { - roles = append(roles, grant.GranteeName.String) - } - } - case "USER": - for _, tfUser := range tfUsers { - if tfUser == grant.GranteeName.String { - users = append(users, grant.GranteeName.String) - } - } - default: - return fmt.Errorf("unknown grant type %s", grant.GrantedTo.String) - } - } - - err = d.Set("role_name", roleName) - if err != nil { - return err - } - err = d.Set("roles", roles) - if err != nil { - return err - } - err = d.Set("users", users) - if err != nil { - return err - } - - return nil -} - -func DeleteRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { - db := meta.(*sql.DB) - roleName := d.Get("role_name").(string) - - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - users := expandStringList(d.Get("users").(*schema.Set).List()) - - for _, role := range roles { - err := revokeRoleFromRole(db, roleName, role) - if err != nil { - return err - } - } - - for _, user := range users { - err := revokeRoleFromUser(db, roleName, user) - if err != nil { - return err - } - } - - d.SetId("") - return nil -} - -func revokeRoleOwnershipFromRole(db *sql.DB, role1, role2 string) error { - rg := snowflake.RoleOwnershipGrant(role1).Role(role2) - err := snowflake.Exec(db, rg.Revoke()) - return err -} - -func revokeRoleOwnershipFromUser(db *sql.DB, role1, user string) error { - rg := snowflake.RoleOwnershipGrant(role1).User(user) - err := snowflake.Exec(db, rg.Revoke()) - return err -} - -func UpdateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { - db := meta.(*sql.DB) - roleName := d.Get("role_name").(string) - - x := func(resource string, grant func(db *sql.DB, role string, target string) error, revoke func(db *sql.DB, role string, target string) error) error { - o, n := d.GetChange(resource) - - if o == nil { - o = new(schema.Set) - } - if n == nil { - n = new(schema.Set) - } - os := o.(*schema.Set) - ns := n.(*schema.Set) - - remove := expandStringList(os.Difference(ns).List()) - add := expandStringList(ns.Difference(os).List()) - - for _, user := range remove { - err := revoke(db, roleName, user) - if err != nil { - return err - } - } - for _, user := range add { - err := grant(db, roleName, user) - if err != nil { - return err - } - } - return nil - } - - err := x("users", grantRoleOwnershipToUser, revokeRoleOwnershipFromUser) - if err != nil { - return err - } - - err = x("roles", grantRoleOwnershipToRole, revokeRoleOwnershipFromRole) - if err != nil { - return err - } - - return ReadRoleOwnershipGrants(d, meta) -} diff --git a/pkg/snowflake/role_ownership_grant.go b/pkg/snowflake/role_ownership_grant.go index 7095c1643b..e8ed7c2ec8 100644 --- a/pkg/snowflake/role_ownership_grant.go +++ b/pkg/snowflake/role_ownership_grant.go @@ -3,39 +3,34 @@ package snowflake import "fmt" type RoleOwnershipGrantBuilder struct { - name string + role string + currentGrants string } type RoleOwnershipGrantExecutable struct { - name string - granteeType granteeType - grantee string + grantor string + granteeType granteeType + grantee string + currentGrants string } -func RoleOwnershipGrant(name string) *RoleOwnershipGrantBuilder { - return &RoleOwnershipGrantBuilder{name: name} -} - -func (gb *RoleOwnershipGrantBuilder) User(user string) *RoleOwnershipGrantExecutable { - return &RoleOwnershipGrantExecutable{ - name: gb.name, - granteeType: userType, - grantee: user, - } +func RoleOwnershipGrant(role string, currentGrants string) *RoleOwnershipGrantBuilder { + return &RoleOwnershipGrantBuilder{role: role, currentGrants: currentGrants} } func (gb *RoleOwnershipGrantBuilder) Role(role string) *RoleOwnershipGrantExecutable { return &RoleOwnershipGrantExecutable{ - name: gb.name, - granteeType: roleType, - grantee: role, + grantor: gb.role, + granteeType: "Role", + grantee: role, + currentGrants: gb.currentGrants, } } func (gr *RoleOwnershipGrantExecutable) Grant() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" COPY CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.name) // nolint: gosec + return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.grantor, gr.currentGrants) // nolint: gosec } func (gr *RoleOwnershipGrantExecutable) Revoke() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`, gr.granteeType, gr.grantee) // nolint: gosec + return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "ACCOUNTADMIN" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.currentGrants) // nolint: gosec } From bd27bc64bdc187400abe320457a3389a6d013128 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Sun, 13 Mar 2022 23:16:20 -0600 Subject: [PATCH 06/15] renamed resource to be singular. --- .../snowflake_role_ownership_grants/import.sh | 2 +- .../resource.tf | 2 +- pkg/provider/provider.go | 2 +- pkg/resources/role_ownership_grant.go | 26 +++++++++---------- pkg/snowflake/role_ownership_grant.go | 8 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/resources/snowflake_role_ownership_grants/import.sh b/examples/resources/snowflake_role_ownership_grants/import.sh index 27ab4d842f..d626d8ce1e 100644 --- a/examples/resources/snowflake_role_ownership_grants/import.sh +++ b/examples/resources/snowflake_role_ownership_grants/import.sh @@ -1 +1 @@ -terraform import snowflake_role_ownership_grants.example rolename +terraform import snowflake_role_ownership_grant.example rolename diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index 7923c8d7b3..7a53a257fa 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -17,7 +17,7 @@ resource "snowflake_role_grants" "grants" { ] } -resource "snowflake_role_ownership_grants" "grants" { +resource "snowflake_role_ownership_grant" "grant" { on_role_name = "${snowflake_role.role.name}" to_role_name = "${snowflake_role.other_role.name}" diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index f34e7a9efb..5862bba618 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -184,7 +184,7 @@ func getResources() map[string]*schema.Resource { "snowflake_resource_monitor": resources.ResourceMonitor(), "snowflake_role": resources.Role(), "snowflake_role_grants": resources.RoleGrants(), - "snowflake_role_ownership_grants": resources.RoleOwnershipGrants(), + "snowflake_role_ownership_grant": resources.RoleOwnershipGrant(), "snowflake_row_access_policy": resources.RowAccessPolicy(), "snowflake_saml_integration": resources.SAMLIntegration(), "snowflake_schema": resources.Schema(), diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index ffdca7c625..6e4a914f23 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -12,12 +12,12 @@ import ( "github.com/jmoiron/sqlx" ) -func RoleOwnershipGrants() *schema.Resource { +func RoleOwnershipGrant() *schema.Resource { return &schema.Resource{ - Create: CreateRoleOwnershipGrants, - Read: ReadRoleOwnershipGrants, - Delete: DeleteRoleOwnershipGrants, - Update: UpdateRoleOwnershipGrants, + Create: CreateRoleOwnershipGrant, + Read: ReadRoleOwnershipGrant, + Delete: DeleteRoleOwnershipGrant, + Update: UpdateRoleOwnershipGrant, Schema: map[string]*schema.Schema{ "on_role_name": { @@ -57,24 +57,24 @@ func RoleOwnershipGrants() *schema.Resource { } } -func CreateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { +func CreateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) onRoleName := d.Get("on_role_name").(string) toRoleName := d.Get("to_role_name").(string) currentGrants := d.Get("current_grants").(string) - g := snowflake.RoleOwnershipGrant(onRoleName) - err := snowflake.Exec(db, g.Role(toRoleName, currentGrants).Grant()) + g := snowflake.RoleOwnershipGrant(onRoleName, currentGrants) + err := snowflake.Exec(db, g.Role(toRoleName).Grant()) if err != nil { return err } d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) - return ReadRoleOwnershipGrants(d, meta) + return ReadRoleOwnershipGrant(d, meta) } -func ReadRoleOwnershipGrants(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] @@ -140,7 +140,7 @@ func readOwnershipGrants(db *sql.DB, onRoleName string) error { return nil } -func DeleteRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { +func DeleteRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) onRoleName := d.Get("on_role_name").(string) currentGrants := d.Get("current_grants").(string) @@ -155,7 +155,7 @@ func DeleteRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { return nil } -func UpdateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { +func UpdateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) onRoleName := d.Get("on_role_name").(string) toRoleName := d.Get("to_role_name").(string) @@ -167,5 +167,5 @@ func UpdateRoleOwnershipGrants(d *schema.ResourceData, meta interface{}) error { return err } - return ReadRoleOwnershipGrants(d, meta) + return ReadRoleOwnershipGrant(d, meta) } diff --git a/pkg/snowflake/role_ownership_grant.go b/pkg/snowflake/role_ownership_grant.go index e8ed7c2ec8..1369220556 100644 --- a/pkg/snowflake/role_ownership_grant.go +++ b/pkg/snowflake/role_ownership_grant.go @@ -8,7 +8,7 @@ type RoleOwnershipGrantBuilder struct { } type RoleOwnershipGrantExecutable struct { - grantor string + role string granteeType granteeType grantee string currentGrants string @@ -20,7 +20,7 @@ func RoleOwnershipGrant(role string, currentGrants string) *RoleOwnershipGrantBu func (gb *RoleOwnershipGrantBuilder) Role(role string) *RoleOwnershipGrantExecutable { return &RoleOwnershipGrantExecutable{ - grantor: gb.role, + role: gb.role, granteeType: "Role", grantee: role, currentGrants: gb.currentGrants, @@ -28,9 +28,9 @@ func (gb *RoleOwnershipGrantBuilder) Role(role string) *RoleOwnershipGrantExecut } func (gr *RoleOwnershipGrantExecutable) Grant() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.grantor, gr.currentGrants) // nolint: gosec + return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec } func (gr *RoleOwnershipGrantExecutable) Revoke() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "ACCOUNTADMIN" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.currentGrants) // nolint: gosec + return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec } From b5d56a074210362084d1e38435cb0443cc3c8ead Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Mon, 14 Mar 2022 08:56:54 -0600 Subject: [PATCH 07/15] fixed ReadRoleOwnershipGrant --- pkg/resources/role_ownership_grant.go | 62 ++++++++++----------------- pkg/snowflake/role_ownership_grant.go | 6 +-- 2 files changed, 25 insertions(+), 43 deletions(-) diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index 6e4a914f23..fc3ba147d5 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -9,7 +9,6 @@ import ( "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/jmoiron/sqlx" ) func RoleOwnershipGrant() *schema.Resource { @@ -74,6 +73,19 @@ func CreateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { return ReadRoleOwnershipGrant(d, meta) } +type roleOwnershipGrant struct { + CreatedOn sql.RawBytes `db:"created_on"` + Name sql.NullString `db:"name"` + IsDefault sql.NullBool `db:"is_default"` + IsCurrent sql.NullBool `db:"is_current"` + IsInherited sql.NullBool `db:"is_inherited"` + AssignedToUsers sql.NullString `db:"assigned_to_users"` + GrantedToRoles sql.NullString `db:"granted_to_roles"` + GrantedRoles sql.NullString `db:"granted_roles"` + Owner sql.NullString `db:"owner"` + Comment sql.NullString `db:"comment"` +} + func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) log.Println(d.Id()) @@ -81,9 +93,13 @@ func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { toRoleName := strings.Split(d.Id(), "|")[1] currentGrants := strings.Split(d.Id(), "|")[2] - err := readOwnershipGrants(db, onRoleName) - if err != nil { - return err + row := snowflake.QueryRow(db, fmt.Sprintf("SHOW ROLES LIKE '%s'", onRoleName)) + err := row.StructScan(&roleOwnershipGrant{}) + if err == sql.ErrNoRows { + // If not found, mark resource to be removed from statefile during apply or refresh + log.Printf("[DEBUG] role (%s) not found", onRoleName) + d.SetId("") + return nil } err = d.Set("on_role_name", onRoleName) @@ -104,42 +120,6 @@ func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { return nil } -type roleOwnershipGrant struct { - CreatedOn sql.RawBytes `db:"created_on"` - Name sql.NullString `db:"name"` - IsDefault sql.NullString `db:"is_default"` - IsCurrent sql.NullString `db:"is_current"` - IsInherited sql.NullString `db:"is_inherited"` - AssignedToUsers sql.NullString `db:"assigned_to_users"` - GrantedToRoles sql.NullString `db:"granted_to_roles"` - GrantedRoles sql.NullString `db:"granted_roles"` - Owner sql.NullString `db:"owner"` - Comment sql.NullString `db:"comment"` -} - -func readOwnershipGrants(db *sql.DB, onRoleName string) error { - sdb := sqlx.NewDb(db, "snowflake") - - stmt := fmt.Sprintf(`SHOW ROLES LIKE '%s'`, onRoleName) - - row := sdb.QueryRowx(stmt) - - g := &roleOwnershipGrant{} - err := row.StructScan(g) - if err != nil { - return err - } - - if g.Owner.Valid { - s := g.Owner.String - s = strings.TrimPrefix(s, `"`) - s = strings.TrimSuffix(s, `"`) - g.Owner = sql.NullString{String: s} - } - - return nil -} - func DeleteRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) onRoleName := d.Get("on_role_name").(string) @@ -161,6 +141,8 @@ func UpdateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { toRoleName := d.Get("to_role_name").(string) currentGrants := d.Get("current_grants").(string) + d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) + g := snowflake.RoleOwnershipGrant(onRoleName, currentGrants) err := snowflake.Exec(db, g.Role(toRoleName).Revoke()) if err != nil { diff --git a/pkg/snowflake/role_ownership_grant.go b/pkg/snowflake/role_ownership_grant.go index 1369220556..2c54d81c22 100644 --- a/pkg/snowflake/role_ownership_grant.go +++ b/pkg/snowflake/role_ownership_grant.go @@ -20,9 +20,9 @@ func RoleOwnershipGrant(role string, currentGrants string) *RoleOwnershipGrantBu func (gb *RoleOwnershipGrantBuilder) Role(role string) *RoleOwnershipGrantExecutable { return &RoleOwnershipGrantExecutable{ - role: gb.role, - granteeType: "Role", - grantee: role, + role: role, + granteeType: "ROLE", + grantee: gb.role, currentGrants: gb.currentGrants, } } From 7589d374d6ba51af1e12518275f49039e1aeca07 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Mon, 14 Mar 2022 18:27:55 -0600 Subject: [PATCH 08/15] added unittests --- pkg/resources/helpers_test.go | 4 +- pkg/resources/role_ownership_grant.go | 34 ++++----- pkg/resources/role_ownership_grants_test.go | 84 +++++++++++++++++++++ pkg/snowflake/role_ownership_grant.go | 26 ++++++- pkg/snowflake/role_ownership_grant_test.go | 26 +++++++ 5 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 pkg/resources/role_ownership_grants_test.go create mode 100644 pkg/snowflake/role_ownership_grant_test.go diff --git a/pkg/resources/helpers_test.go b/pkg/resources/helpers_test.go index 5943112ab5..515044ff37 100644 --- a/pkg/resources/helpers_test.go +++ b/pkg/resources/helpers_test.go @@ -192,9 +192,9 @@ func roleGrants(t *testing.T, id string, params map[string]interface{}) *schema. return d } -func roleOwnershipGrants(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { +func roleOwnershipGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.RoleOwnershipGrants().Schema, params) + d := schema.TestResourceDataRaw(t, resources.RoleOwnershipGrant().Schema, params) r.NotNil(d) d.SetId(id) return d diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index fc3ba147d5..34002c05f0 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -73,41 +73,37 @@ func CreateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { return ReadRoleOwnershipGrant(d, meta) } -type roleOwnershipGrant struct { - CreatedOn sql.RawBytes `db:"created_on"` - Name sql.NullString `db:"name"` - IsDefault sql.NullBool `db:"is_default"` - IsCurrent sql.NullBool `db:"is_current"` - IsInherited sql.NullBool `db:"is_inherited"` - AssignedToUsers sql.NullString `db:"assigned_to_users"` - GrantedToRoles sql.NullString `db:"granted_to_roles"` - GrantedRoles sql.NullString `db:"granted_roles"` - Owner sql.NullString `db:"owner"` - Comment sql.NullString `db:"comment"` -} - func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) log.Println(d.Id()) onRoleName := strings.Split(d.Id(), "|")[0] - toRoleName := strings.Split(d.Id(), "|")[1] + // toRoleName := strings.Split(d.Id(), "|")[1] currentGrants := strings.Split(d.Id(), "|")[2] - row := snowflake.QueryRow(db, fmt.Sprintf("SHOW ROLES LIKE '%s'", onRoleName)) - err := row.StructScan(&roleOwnershipGrant{}) + stmt := fmt.Sprintf("SHOW ROLES LIKE '%s'", onRoleName) + row := snowflake.QueryRow(db, stmt) + + grant, err := snowflake.ScanRoleOwnershipGrant(row) if err == sql.ErrNoRows { // If not found, mark resource to be removed from statefile during apply or refresh - log.Printf("[DEBUG] role (%s) not found", onRoleName) + log.Printf("[DEBUG] role (%s) not found", d.Id()) d.SetId("") return nil } + if err != nil { + return err + } + + if onRoleName != grant.Name.String { + return fmt.Errorf("no role found like '%s'", onRoleName) + } - err = d.Set("on_role_name", onRoleName) + err = d.Set("on_role_name", grant.Name.String) if err != nil { return err } - err = d.Set("to_role_name", toRoleName) + err = d.Set("to_role_name", grant.Owner.String) if err != nil { return err } diff --git a/pkg/resources/role_ownership_grants_test.go b/pkg/resources/role_ownership_grants_test.go new file mode 100644 index 0000000000..7ed3801793 --- /dev/null +++ b/pkg/resources/role_ownership_grants_test.go @@ -0,0 +1,84 @@ +package resources_test + +import ( + "database/sql" + "testing" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/provider" + "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/resources" + . "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/testhelpers" + "github.com/stretchr/testify/require" +) + +func TestRoleOwnershipGrant(t *testing.T) { + r := require.New(t) + err := resources.RoleOwnershipGrant().InternalValidate(provider.Provider().Schema, true) + r.NoError(err) +} + +func TestRoleOwnershipGrantCreate(t *testing.T) { + r := require.New(t) + + d := roleOwnershipGrant(t, "good_name", map[string]interface{}{ + "on_role_name": "good_name", + "to_role_name": "other_good_name", + "current_grants": "COPY", + }) + + WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { + mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "other_good_name"`).WillReturnResult(sqlmock.NewResult(1, 1)) + expectReadRoleOwnershipGrant(mock) + err := resources.CreateRoleOwnershipGrant(d, db) + r.NoError(err) + }) +} + +func TestRoleOwnershipGrantRead(t *testing.T) { + r := require.New(t) + + d := roleOwnershipGrant(t, "good_name|other_good_name|COPY", map[string]interface{}{ + "on_role_name": "good_name", + "to_role_name": "other_good_name", + "current_grants": "COPY", + }) + + WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { + expectReadRoleOwnershipGrant(mock) + err := resources.ReadRoleOwnershipGrant(d, db) + r.NoError(err) + }) +} + +func expectReadRoleOwnershipGrant(mock sqlmock.Sqlmock) { + rows := sqlmock.NewRows([]string{ + "created_on", + "name", + "is_default", + "is_current", + "is_inherited", + "assigned_to_users", + "granted_to_roles", + "granted_roles", + "owner", + "comment", + }).AddRow("_", "good_name", "", "", "", "", "", "", "other_good_name", "") + mock.ExpectQuery(`SHOW ROLES LIKE 'good_name'`).WillReturnRows(rows) +} + +func TestRoleOwnershipGrantDelete(t *testing.T) { + r := require.New(t) + + d := roleOwnershipGrant(t, "good_name|other_good_name|COPY", map[string]interface{}{ + "on_role_name": "good_name", + "to_role_name": "other_good_name", + "current_grants": "COPY", + }) + + WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { + + mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "ACCOUNTADMIN"`).WillReturnResult(sqlmock.NewResult(1, 1)) + err := resources.DeleteRoleOwnershipGrant(d, db) + r.NoError(err) + }) +} diff --git a/pkg/snowflake/role_ownership_grant.go b/pkg/snowflake/role_ownership_grant.go index 2c54d81c22..3f1e0c1ed7 100644 --- a/pkg/snowflake/role_ownership_grant.go +++ b/pkg/snowflake/role_ownership_grant.go @@ -1,6 +1,11 @@ package snowflake -import "fmt" +import ( + "database/sql" + "fmt" + + "github.com/jmoiron/sqlx" +) type RoleOwnershipGrantBuilder struct { role string @@ -34,3 +39,22 @@ func (gr *RoleOwnershipGrantExecutable) Grant() string { func (gr *RoleOwnershipGrantExecutable) Revoke() string { return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec } + +type roleOwnershipGrant struct { + CreatedOn sql.NullString `db:"created_on"` + Name sql.NullString `db:"name"` + IsDefault sql.NullString `db:"is_default"` + IsCurrent sql.NullString `db:"is_current"` + IsInherited sql.NullString `db:"is_inherited"` + AssignedToUsers sql.NullString `db:"assigned_to_users"` + GrantedToRoles sql.NullString `db:"granted_to_roles"` + GrantedRoles sql.NullString `db:"granted_roles"` + Owner sql.NullString `db:"owner"` + Comment sql.NullString `db:"comment"` +} + +func ScanRoleOwnershipGrant(row *sqlx.Row) (*roleOwnershipGrant, error) { + rog := &roleOwnershipGrant{} + err := row.StructScan(rog) + return rog, err +} diff --git a/pkg/snowflake/role_ownership_grant_test.go b/pkg/snowflake/role_ownership_grant_test.go new file mode 100644 index 0000000000..18aa42d4f9 --- /dev/null +++ b/pkg/snowflake/role_ownership_grant_test.go @@ -0,0 +1,26 @@ +package snowflake_test + +import ( + "testing" + + "github.com/chanzuckerberg/terraform-provider-snowflake/pkg/snowflake" + "github.com/stretchr/testify/require" +) + +func TestRoleOwnershipGrantQuery(t *testing.T) { + r := require.New(t) + copy := snowflake.RoleOwnershipGrant("role1", "COPY") + revoke := snowflake.RoleOwnershipGrant("role1", "REVOKE") + + g1 := copy.Role("role2").Grant() + r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "role2" COPY CURRENT GRANTS`, g1) + + r1 := copy.Role("ACCOUNTADMIN").Revoke() + r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`, r1) + + g2 := revoke.Role("role2").Grant() + r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "role2" REVOKE CURRENT GRANTS`, g2) + + r2 := revoke.Role("ACCOUNTADMIN").Revoke() + r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "ACCOUNTADMIN" REVOKE CURRENT GRANTS`, r2) +} From 959605ff861d9a201c1e28ac7ea95baa14408072 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Mon, 14 Mar 2022 19:09:47 -0600 Subject: [PATCH 09/15] make docs --- docs/resources/role_ownership_grant.md | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/resources/role_ownership_grant.md diff --git a/docs/resources/role_ownership_grant.md b/docs/resources/role_ownership_grant.md new file mode 100644 index 0000000000..adc68bc80f --- /dev/null +++ b/docs/resources/role_ownership_grant.md @@ -0,0 +1,28 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "snowflake_role_ownership_grant Resource - terraform-provider-snowflake" +subcategory: "" +description: |- + +--- + +# snowflake_role_ownership_grant (Resource) + + + + + + +## Schema + +### Required + +- **on_role_name** (String) The name of the role ownership is granted on. +- **to_role_name** (String) The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access. + +### Optional + +- **current_grants** (String) Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role. +- **id** (String) The ID of this resource. + + From c76f39c009176eee127fda1eadf156d48587fea9 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Mon, 14 Mar 2022 21:05:37 -0600 Subject: [PATCH 10/15] added role_ownership_grant_acceptance_test --- .../resource.tf | 6 +- pkg/resources/role_ownership_grant.go | 5 +- .../role_ownership_grant_acceptance_test.go | 57 +++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 pkg/resources/role_ownership_grant_acceptance_test.go diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index 7a53a257fa..a990105daa 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -10,7 +10,7 @@ resource "snowflake_role" "other_role" { # ensure the Terraform user inherits ownership privileges for the rking_test_user role # otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges resource "snowflake_role_grants" "grants" { - role_name = "${snowflake_role.role.name}" + role_name = snowflake_role.role.name roles = [ "ACCOUNTADMIN", @@ -18,9 +18,9 @@ resource "snowflake_role_grants" "grants" { } resource "snowflake_role_ownership_grant" "grant" { - on_role_name = "${snowflake_role.role.name}" + on_role_name = snowflake_role.role.name - to_role_name = "${snowflake_role.other_role.name}" + to_role_name = snowflake_role.other_role.name current_grants = "COPY" } \ No newline at end of file diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index 34002c05f0..85fb80b80c 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -77,7 +77,6 @@ func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) log.Println(d.Id()) onRoleName := strings.Split(d.Id(), "|")[0] - // toRoleName := strings.Split(d.Id(), "|")[1] currentGrants := strings.Split(d.Id(), "|")[2] stmt := fmt.Sprintf("SHOW ROLES LIKE '%s'", onRoleName) @@ -98,11 +97,15 @@ func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("no role found like '%s'", onRoleName) } + grant.Name.String = strings.TrimPrefix(grant.Name.String, `"`) + grant.Name.String = strings.TrimSuffix(grant.Name.String, `"`) err = d.Set("on_role_name", grant.Name.String) if err != nil { return err } + grant.Owner.String = strings.TrimPrefix(grant.Owner.String, `"`) + grant.Owner.String = strings.TrimSuffix(grant.Owner.String, `"`) err = d.Set("to_role_name", grant.Owner.String) if err != nil { return err diff --git a/pkg/resources/role_ownership_grant_acceptance_test.go b/pkg/resources/role_ownership_grant_acceptance_test.go new file mode 100644 index 0000000000..8dd53a524c --- /dev/null +++ b/pkg/resources/role_ownership_grant_acceptance_test.go @@ -0,0 +1,57 @@ +package resources_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccRoleOwnershipGrant_defaults(t *testing.T) { + onRoleName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + toRoleName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + + resource.ParallelTest(t, resource.TestCase{ + Providers: providers(), + Steps: []resource.TestStep{ + { + Config: roleOwnershipGrantConfig(onRoleName, toRoleName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("snowflake_role_ownership_grant.grant", "on_role_name", onRoleName), + resource.TestCheckResourceAttr("snowflake_role_ownership_grant.grant", "to_role_name", toRoleName), + resource.TestCheckResourceAttr("snowflake_role_ownership_grant.grant", "current_grants", "COPY"), + ), + }, + }, + }) +} + +func roleOwnershipGrantConfig(onRoleName, toRoleName string) string { + return fmt.Sprintf(` + +resource "snowflake_role" "role" { + name = "%v" +} + +resource "snowflake_role" "other_role" { + name = "%v" +} + +resource "snowflake_role_grants" "grants" { + role_name = snowflake_role.role.name + + roles = [ + "ACCOUNTADMIN", + ] +} + +resource "snowflake_role_ownership_grant" "grant" { + on_role_name = snowflake_role.role.name + + to_role_name = snowflake_role.other_role.name + + current_grants = "COPY" +} +`, onRoleName, toRoleName) +} From 90e686d3113fc23fb078497d445d693c39e4d8e7 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Mon, 14 Mar 2022 21:08:05 -0600 Subject: [PATCH 11/15] added example to snowflake_role_ownership_grant docs. --- docs/resources/role_ownership_grant.md | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/resources/role_ownership_grant.md b/docs/resources/role_ownership_grant.md index adc68bc80f..ff0aa9740a 100644 --- a/docs/resources/role_ownership_grant.md +++ b/docs/resources/role_ownership_grant.md @@ -9,7 +9,36 @@ description: |- # snowflake_role_ownership_grant (Resource) +## Example Usage +```terraform +resource "snowflake_role" "role" { + name = "rking_test_role" + comment = "for testing" +} + +resource "snowflake_role" "other_role" { + name = "rking_test_role2" +} + +# ensure the Terraform user inherits ownership privileges for the rking_test_user role +# otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges +resource "snowflake_role_grants" "grants" { + role_name = snowflake_role.role.name + + roles = [ + "ACCOUNTADMIN", + ] +} + +resource "snowflake_role_ownership_grant" "grant" { + on_role_name = snowflake_role.role.name + + to_role_name = snowflake_role.other_role.name + + current_grants = "COPY" +} +``` From 83dc3d02f36db76610a1d9cf4d48d751338fb80e Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Mon, 14 Mar 2022 22:28:41 -0600 Subject: [PATCH 12/15] format example --- docs/resources/role_ownership_grant.md | 2 -- examples/resources/snowflake_role_ownership_grants/resource.tf | 2 -- 2 files changed, 4 deletions(-) diff --git a/docs/resources/role_ownership_grant.md b/docs/resources/role_ownership_grant.md index ff0aa9740a..71fa34cd54 100644 --- a/docs/resources/role_ownership_grant.md +++ b/docs/resources/role_ownership_grant.md @@ -33,9 +33,7 @@ resource "snowflake_role_grants" "grants" { resource "snowflake_role_ownership_grant" "grant" { on_role_name = snowflake_role.role.name - to_role_name = snowflake_role.other_role.name - current_grants = "COPY" } ``` diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index a990105daa..247b9e84c9 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -19,8 +19,6 @@ resource "snowflake_role_grants" "grants" { resource "snowflake_role_ownership_grant" "grant" { on_role_name = snowflake_role.role.name - to_role_name = snowflake_role.other_role.name - current_grants = "COPY" } \ No newline at end of file From 8473b43966c5d866e59658624290b6c6c80a6715 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Tue, 15 Mar 2022 17:50:04 -0600 Subject: [PATCH 13/15] re-ran make docs. I also fixed a tiny bug in the unittest --- docs/resources/role_ownership_grant.md | 8 -- .../resource.tf | 2 +- pkg/resources/role_ownership_grant.go | 86 +++++++++---------- pkg/resources/role_ownership_grants_test.go | 4 +- 4 files changed, 46 insertions(+), 54 deletions(-) diff --git a/docs/resources/role_ownership_grant.md b/docs/resources/role_ownership_grant.md index 71fa34cd54..9a82f57fe7 100644 --- a/docs/resources/role_ownership_grant.md +++ b/docs/resources/role_ownership_grant.md @@ -8,29 +8,22 @@ description: |- # snowflake_role_ownership_grant (Resource) - -## Example Usage - ```terraform resource "snowflake_role" "role" { name = "rking_test_role" comment = "for testing" } - resource "snowflake_role" "other_role" { name = "rking_test_role2" } - # ensure the Terraform user inherits ownership privileges for the rking_test_user role # otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges resource "snowflake_role_grants" "grants" { role_name = snowflake_role.role.name - roles = [ "ACCOUNTADMIN", ] } - resource "snowflake_role_ownership_grant" "grant" { on_role_name = snowflake_role.role.name to_role_name = snowflake_role.other_role.name @@ -38,7 +31,6 @@ resource "snowflake_role_ownership_grant" "grant" { } ``` - ## Schema diff --git a/examples/resources/snowflake_role_ownership_grants/resource.tf b/examples/resources/snowflake_role_ownership_grants/resource.tf index 247b9e84c9..82dbf48dc8 100644 --- a/examples/resources/snowflake_role_ownership_grants/resource.tf +++ b/examples/resources/snowflake_role_ownership_grants/resource.tf @@ -7,7 +7,7 @@ resource "snowflake_role" "other_role" { name = "rking_test_role2" } -# ensure the Terraform user inherits ownership privileges for the rking_test_user role +# ensure the Terraform user inherits ownership privileges for the rking_test_role role # otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges resource "snowflake_role_grants" "grants" { role_name = snowflake_role.role.name diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index 85fb80b80c..b5d64b08a0 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -11,45 +11,45 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) +var roleOwnershipGrantSchema = map[string]*schema.Schema{ + "on_role_name": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Required: true, + Description: "The name of the role ownership is granted on.", + ValidateFunc: func(val interface{}, key string) ([]string, []error) { + return snowflake.ValidateIdentifier(val) + }, + }, + "to_role_name": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Required: true, + Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", + ValidateFunc: func(val interface{}, key string) ([]string, []error) { + return snowflake.ValidateIdentifier(val) + }, + }, + "current_grants": { + Type: schema.TypeString, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Description: "Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role.", + Default: "COPY", + ValidateFunc: validation.StringInSlice([]string{ + "COPY", + "REVOKE", + }, true), + }, +} + func RoleOwnershipGrant() *schema.Resource { return &schema.Resource{ Create: CreateRoleOwnershipGrant, Read: ReadRoleOwnershipGrant, Delete: DeleteRoleOwnershipGrant, Update: UpdateRoleOwnershipGrant, - - Schema: map[string]*schema.Schema{ - "on_role_name": { - Type: schema.TypeString, - Elem: &schema.Schema{Type: schema.TypeString}, - Required: true, - Description: "The name of the role ownership is granted on.", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - return snowflake.ValidateIdentifier(val) - }, - }, - "to_role_name": { - Type: schema.TypeString, - Elem: &schema.Schema{Type: schema.TypeString}, - Required: true, - Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - return snowflake.ValidateIdentifier(val) - }, - }, - "current_grants": { - Type: schema.TypeString, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role.", - Default: "COPY", - ValidateFunc: validation.StringInSlice([]string{ - "COPY", - "REVOKE", - }, true), - }, - }, - + Schema: roleOwnershipGrantSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -119,34 +119,34 @@ func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { return nil } -func DeleteRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { +func UpdateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) onRoleName := d.Get("on_role_name").(string) + toRoleName := d.Get("to_role_name").(string) currentGrants := d.Get("current_grants").(string) + d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) + g := snowflake.RoleOwnershipGrant(onRoleName, currentGrants) - err := snowflake.Exec(db, g.Role("ACCOUNTADMIN").Revoke()) + err := snowflake.Exec(db, g.Role(toRoleName).Grant()) if err != nil { return err } - d.SetId("") - return nil + return ReadRoleOwnershipGrant(d, meta) } -func UpdateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { +func DeleteRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) onRoleName := d.Get("on_role_name").(string) - toRoleName := d.Get("to_role_name").(string) currentGrants := d.Get("current_grants").(string) - d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) - g := snowflake.RoleOwnershipGrant(onRoleName, currentGrants) - err := snowflake.Exec(db, g.Role(toRoleName).Revoke()) + err := snowflake.Exec(db, g.Role("ACCOUNTADMIN").Revoke()) if err != nil { return err } - return ReadRoleOwnershipGrant(d, meta) + d.SetId("") + return nil } diff --git a/pkg/resources/role_ownership_grants_test.go b/pkg/resources/role_ownership_grants_test.go index 7ed3801793..4b71da82a5 100644 --- a/pkg/resources/role_ownership_grants_test.go +++ b/pkg/resources/role_ownership_grants_test.go @@ -27,7 +27,7 @@ func TestRoleOwnershipGrantCreate(t *testing.T) { }) WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "other_good_name"`).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "other_good_name" COPY CURRENT GRANTS`).WillReturnResult(sqlmock.NewResult(1, 1)) expectReadRoleOwnershipGrant(mock) err := resources.CreateRoleOwnershipGrant(d, db) r.NoError(err) @@ -77,7 +77,7 @@ func TestRoleOwnershipGrantDelete(t *testing.T) { WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "ACCOUNTADMIN"`).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`).WillReturnResult(sqlmock.NewResult(1, 1)) err := resources.DeleteRoleOwnershipGrant(d, db) r.NoError(err) }) From 04b1260ceb7b632c09b694d367e301e84ad285b3 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Tue, 15 Mar 2022 20:52:46 -0600 Subject: [PATCH 14/15] removed example from snowflake_role_ownership_grant docs. re-ran 'make docs' --- docs/resources/role_ownership_grant.md | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/docs/resources/role_ownership_grant.md b/docs/resources/role_ownership_grant.md index 9a82f57fe7..adc68bc80f 100644 --- a/docs/resources/role_ownership_grant.md +++ b/docs/resources/role_ownership_grant.md @@ -8,28 +8,9 @@ description: |- # snowflake_role_ownership_grant (Resource) -```terraform -resource "snowflake_role" "role" { - name = "rking_test_role" - comment = "for testing" -} -resource "snowflake_role" "other_role" { - name = "rking_test_role2" -} -# ensure the Terraform user inherits ownership privileges for the rking_test_user role -# otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - roles = [ - "ACCOUNTADMIN", - ] -} -resource "snowflake_role_ownership_grant" "grant" { - on_role_name = snowflake_role.role.name - to_role_name = snowflake_role.other_role.name - current_grants = "COPY" -} -``` + + + ## Schema From d734035b6200507a364e024ebf37bd1340094334 Mon Sep 17 00:00:00 2001 From: aidanmelen Date: Wed, 16 Mar 2022 14:32:22 -0600 Subject: [PATCH 15/15] empty