Skip to content

Commit

Permalink
Merge branch 'main' into add-row-access-policy-to-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-asawicki committed Jan 18, 2024
2 parents 7b860a3 + c4837d6 commit 37b08f0
Show file tree
Hide file tree
Showing 12 changed files with 482 additions and 3 deletions.
7 changes: 6 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
builds:
- env:
- CGO_ENABLED=0
- >-
{{- if or (eq .Os "darwin") (eq .Os "windows") }}
CGO_ENABLED=1
{{- else }}
CGO_ENABLED=0
{{- end }}
goos:
- windows
- linux
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export SKIP_EMAIL_INTEGRATION_TESTS=true
export SKIP_NOTIFICATION_INTEGRATION_TESTS=true
export SKIP_SAML_INTEGRATION_TESTS=true
export SKIP_STREAM_TEST=true
export SKIP_MANAGED_ACCOUNT_INT_TEST=true
export BASE_BINARY_NAME=terraform-provider-snowflake
export TERRAFORM_PLUGINS_DIR=$(HOME)/.terraform.d/plugins
export TERRAFORM_PLUGIN_LOCAL_INSTALL=$(TERRAFORM_PLUGINS_DIR)/$(BASE_BINARY_NAME)
Expand Down
75 changes: 75 additions & 0 deletions docs/resources/grant_account_role.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "snowflake_grant_account_role Resource - terraform-provider-snowflake"
subcategory: ""
description: |-
---

# snowflake_grant_account_role (Resource)



## Example Usage

```terraform
##################################
### grant account role to account role
##################################
resource "snowflake_role" "role" {
name = var.role_name
}
resource "snowflake_role" "parent_role" {
name = var.parent_role_name
}
resource "snowflake_grant_account_role" "g" {
role_name = snowflake_role.role.name
parent_role_name = snowflake_role.parent_role.name
}
##################################
### grant account role to user
##################################
resource "snowflake_role" "role" {
name = var.role_name
}
resource "snowflake_user" "user" {
name = var.user_name
}
resource "snowflake_grant_account_role" "g" {
role_name = snowflake_role.role.name
user_name = snowflake_user.user.name
}
```

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

### Required

- `role_name` (String) The fully qualified name of the role which will be granted to the user or parent role.

### Optional

- `parent_role_name` (String) The fully qualified name of the parent role which will create a parent-child relationship between the roles.
- `user_name` (String) The fully qualified name of the user on which specified role will be granted.

### Read-Only

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

## Import

Import is supported using the following syntax:

```shell
# format is role_name (string) | grantee_object_type (ROLE|USER) | grantee_name (string)
terraform import "\"test_role\"|ROLE|\"test_parent_role\""
```
2 changes: 2 additions & 0 deletions examples/resources/snowflake_grant_account_role/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# format is role_name (string) | grantee_object_type (ROLE|USER) | grantee_name (string)
terraform import "\"test_role\"|ROLE|\"test_parent_role\""
34 changes: 34 additions & 0 deletions examples/resources/snowflake_grant_account_role/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
##################################
### grant account role to account role
##################################

resource "snowflake_role" "role" {
name = var.role_name
}

resource "snowflake_role" "parent_role" {
name = var.parent_role_name
}

resource "snowflake_grant_account_role" "g" {
role_name = snowflake_role.role.name
parent_role_name = snowflake_role.parent_role.name
}


##################################
### grant account role to user
##################################

resource "snowflake_role" "role" {
name = var.role_name
}

resource "snowflake_user" "user" {
name = var.user_name
}

resource "snowflake_grant_account_role" "g" {
role_name = snowflake_role.role.name
user_name = snowflake_user.user.name
}
1 change: 1 addition & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ func getResources() map[string]*schema.Resource {
"snowflake_failover_group": resources.FailoverGroup(),
"snowflake_file_format": resources.FileFormat(),
"snowflake_function": resources.Function(),
"snowflake_grant_account_role": resources.GrantAccountRole(),
"snowflake_grant_privileges_to_role": resources.GrantPrivilegesToRole(),
"snowflake_grant_privileges_to_database_role": resources.GrantPrivilegesToDatabaseRole(),
"snowflake_managed_account": resources.ManagedAccount(),
Expand Down
181 changes: 181 additions & 0 deletions pkg/resources/grant_account_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package resources

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

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

var grantAccountRoleSchema = map[string]*schema.Schema{
"role_name": {
Type: schema.TypeString,
Required: true,
Description: "The fully qualified name of the role which will be granted to the user or parent role.",
ForceNew: true,
ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
},
"user_name": {
Type: schema.TypeString,
Optional: true,
Description: "The fully qualified name of the user on which specified role will be granted.",
ForceNew: true,
ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
ExactlyOneOf: []string{
"user_name",
"parent_role_name",
},
},
"parent_role_name": {
Type: schema.TypeString,
Optional: true,
Description: "The fully qualified name of the parent role which will create a parent-child relationship between the roles.",
ForceNew: true,
ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
ExactlyOneOf: []string{
"user_name",
"parent_role_name",
},
},
}

func GrantAccountRole() *schema.Resource {
return &schema.Resource{
Create: CreateGrantAccountRole,
Read: ReadGrantAccountRole,
Delete: DeleteGrantAccountRole,
Schema: grantAccountRoleSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), helpers.IDDelimiter)
if len(parts) != 3 {
return nil, fmt.Errorf("invalid ID specified: %v, expected <role_name>|<grantee_object_type>|<grantee_identifier>", d.Id())
}
if err := d.Set("role_name", strings.Trim(parts[0], "\"")); err != nil {
return nil, err
}
switch parts[1] {
case "ROLE":
if err := d.Set("parent_role_name", strings.Trim(parts[2], "\"")); err != nil {
return nil, err
}
case "USER":
if err := d.Set("user_name", strings.Trim(parts[2], "\"")); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("invalid object type specified: %v, expected ROLE or USER", parts[1])
}

return []*schema.ResourceData{d}, nil
},
},
}
}

// CreateGrantAccountRole implements schema.CreateFunc.
func CreateGrantAccountRole(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
client := sdk.NewClientFromDB(db)
ctx := context.Background()
roleName := d.Get("role_name").(string)
roleIdentifier := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(roleName)
// format of snowflakeResourceID is <role_identifier>|<object type>|<target_identifier>
var snowflakeResourceID string
if parentRoleName, ok := d.GetOk("parent_role_name"); ok && parentRoleName.(string) != "" {
parentRoleIdentifier := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(parentRoleName.(string))
snowflakeResourceID = helpers.EncodeSnowflakeID(roleIdentifier.FullyQualifiedName(), sdk.ObjectTypeRole.String(), parentRoleIdentifier.FullyQualifiedName())
req := sdk.NewGrantRoleRequest(roleIdentifier, sdk.GrantRole{
Role: &parentRoleIdentifier,
})
if err := client.Roles.Grant(ctx, req); err != nil {
return err
}
} else if userName, ok := d.GetOk("user_name"); ok && userName.(string) != "" {
userIdentifier := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(userName.(string))
snowflakeResourceID = helpers.EncodeSnowflakeID(roleIdentifier.FullyQualifiedName(), sdk.ObjectTypeUser.String(), userIdentifier.FullyQualifiedName())
req := sdk.NewGrantRoleRequest(roleIdentifier, sdk.GrantRole{
User: &userIdentifier,
})
if err := client.Roles.Grant(ctx, req); err != nil {
return err
}
} else {
return fmt.Errorf("invalid role grant specified: %v", d)
}
d.SetId(snowflakeResourceID)
return ReadGrantAccountRole(d, meta)
}

func ReadGrantAccountRole(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
client := sdk.NewClientFromDB(db)
parts := strings.Split(d.Id(), helpers.IDDelimiter)
if len(parts) != 3 {
return fmt.Errorf("invalid ID specified: %v, expected <role_name>|<grantee_object_type>|<grantee_identifier>", d.Id())
}
roleName := parts[0]
roleIdentifier := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(roleName)
objectType := parts[1]
targetIdentifier := parts[2]
ctx := context.Background()
grants, err := client.Grants.Show(ctx, &sdk.ShowGrantOptions{
Of: &sdk.ShowGrantsOf{
Role: roleIdentifier,
},
})
if err != nil {
log.Printf("[DEBUG] role (%s) not found", roleIdentifier.FullyQualifiedName())
d.SetId("")
return nil
}

var found bool
for _, grant := range grants {
if grant.GrantedTo == sdk.ObjectType(objectType) {
if grant.GranteeName.FullyQualifiedName() == targetIdentifier {
found = true
break
}
}
}
if !found {
log.Printf("[DEBUG] role grant (%s) not found", d.Id())
d.SetId("")
}

return nil
}

func DeleteGrantAccountRole(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
client := sdk.NewClientFromDB(db)
parts := strings.Split(d.Id(), helpers.IDDelimiter)
if len(parts) != 3 {
return fmt.Errorf("invalid ID specified: %v, expected <role_name>|<grantee_object_type>|<grantee_identifier>", d.Id())
}
id := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(parts[0])
objectType := parts[1]
granteeName := parts[2]
ctx := context.Background()
granteeIdentifier := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(granteeName)
switch objectType {
case "ROLE":
if err := client.Roles.Revoke(ctx, sdk.NewRevokeRoleRequest(id, sdk.RevokeRole{Role: &granteeIdentifier})); err != nil {
return err
}
case "USER":
if err := client.Roles.Revoke(ctx, sdk.NewRevokeRoleRequest(id, sdk.RevokeRole{User: &granteeIdentifier})); err != nil {
return err
}
default:
return fmt.Errorf("invalid object type specified: %v, expected ROLE or USER", objectType)
}
d.SetId("")
return nil
}
Loading

0 comments on commit 37b08f0

Please sign in to comment.