Skip to content

Commit

Permalink
Add unsafe exec resource
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-jcieslak committed Nov 27, 2023
1 parent 43277a4 commit 16d1d7f
Show file tree
Hide file tree
Showing 7 changed files with 516 additions and 0 deletions.
62 changes: 62 additions & 0 deletions docs/resources/unsafe_execute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "snowflake_unsafe_execute Resource - terraform-provider-snowflake"
subcategory: ""
description: |-
Experimental resource used for testing purposes only. Allows to execute ANY SQL statement.
---

# snowflake_unsafe_execute (Resource)

!> **Warning** This is a dangerous resource that allows executing **ANY** SQL statement. It may destroy resources if used incorrectly. It may behave incorrectly combined with other resources. Will be deleted in the upcoming versions. Use at your own risk.

Experimental resource used for testing purposes only. Allows to execute ANY SQL statement.

## Example Usage

```terraform
# create and destroy resource
resource "snowflake_unsafe_execute" "test" {
execute = "CREATE DATABASE ABC"
revert = "DROP DATABASE ABC"
}
# create and destroy resource using qualified name
resource "snowflake_unsafe_execute" "test" {
execute = "CREATE DATABASE \"abc\""
revert = "DROP DATABASE \"abc\""
}
# grant and revoke privilege USAGE to ROLE on database
resource "snowflake_unsafe_execute" "test" {
execute = "GRANT USAGE ON DATABASE ABC TO ROLE XYZ"
revert = "REVOKE USAGE ON DATABASE ABC FROM ROLE XYZ"
}
# grant and revoke with for_each
variable "database_grants" {
type = list(object({
database_name = string
role_id = string
privileges = list(string)
}))
}
resource "snowflake_unsafe_execute" "test" {
for_each = { for index, db_grant in var.database_grants : index => db_grant }
execute = "GRANT ${join(",", each.value.privileges)} ON DATABASE ${each.value.database_name} TO ROLE ${each.value.role_id}"
revert = "REVOKE ${join(",", each.value.privileges)} ON DATABASE ${each.value.database_name} FROM ROLE ${each.value.role_id}"
}
```

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

### Required

- `execute` (String) SQL statement to execute.
- `revert` (String) SQL statement to revert the execute statement. Invoked when resource is deleted.

### Read-Only

- `id` (String) The ID of this resource.
32 changes: 32 additions & 0 deletions examples/resources/snowflake_unsafe_execute/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# create and destroy resource
resource "snowflake_unsafe_execute" "test" {
execute = "CREATE DATABASE ABC"
revert = "DROP DATABASE ABC"
}

# create and destroy resource using qualified name
resource "snowflake_unsafe_execute" "test" {
execute = "CREATE DATABASE \"abc\""
revert = "DROP DATABASE \"abc\""
}

# grant and revoke privilege USAGE to ROLE on database
resource "snowflake_unsafe_execute" "test" {
execute = "GRANT USAGE ON DATABASE ABC TO ROLE XYZ"
revert = "REVOKE USAGE ON DATABASE ABC FROM ROLE XYZ"
}

# grant and revoke with for_each
variable "database_grants" {
type = list(object({
database_name = string
role_id = string
privileges = list(string)
}))
}

resource "snowflake_unsafe_execute" "test" {
for_each = { for index, db_grant in var.database_grants : index => db_grant }
execute = "GRANT ${join(",", each.value.privileges)} ON DATABASE ${each.value.database_name} TO ROLE ${each.value.role_id}"
revert = "REVOKE ${join(",", each.value.privileges)} ON DATABASE ${each.value.database_name} FROM ROLE ${each.value.role_id}"
}
1 change: 1 addition & 0 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ func getResources() map[string]*schema.Resource {
"snowflake_tag_association": resources.TagAssociation(),
"snowflake_tag_masking_policy_association": resources.TagMaskingPolicyAssociation(),
"snowflake_task": resources.Task(),
"snowflake_unsafe_execute": resources.UnsafeExecute(),
"snowflake_user": resources.User(),
"snowflake_user_ownership_grant": resources.UserOwnershipGrant(),
"snowflake_user_public_keys": resources.UserPublicKeys(),
Expand Down
78 changes: 78 additions & 0 deletions pkg/resources/unsafe_execute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package resources

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

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

var unsafeExecuteSchema = map[string]*schema.Schema{
"execute": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "SQL statement to execute.",
},
"revert": {
Type: schema.TypeString,
Required: true,
Description: "SQL statement to revert the execute statement. Invoked when resource is deleted.",
},
}

func UnsafeExecute() *schema.Resource {
return &schema.Resource{
Create: ExecuteUnsafeSQLStatement,
Read: schema.Noop,
Delete: RevertUnsafeSQLStatement,
Update: schema.Noop,

Schema: unsafeExecuteSchema,

DeprecationMessage: "Experimental resource. Will be deleted in the upcoming versions. Use at your own risk.",
Description: "Experimental resource used for testing purposes only. Allows to execute ANY SQL statement.",
}
}

func ExecuteUnsafeSQLStatement(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
ctx := context.Background()
client := sdk.NewClientFromDB(db)

id, err := uuid.GenerateUUID()
if err != nil {
return err
}

executeStatement := d.Get("execute").(string)
_, err = client.ExecUnsafe(ctx, executeStatement)
if err != nil {
return err
}

d.SetId(id)
log.Printf(`[DEBUG] SQL "%s" applied successfully\n`, executeStatement)

return nil
}

func RevertUnsafeSQLStatement(d *schema.ResourceData, meta interface{}) error {
db := meta.(*sql.DB)
ctx := context.Background()
client := sdk.NewClientFromDB(db)

revertStatement := d.Get("revert").(string)
_, err := client.ExecUnsafe(ctx, revertStatement)
if err != nil {
return err
}

d.SetId("")
log.Printf(`[DEBUG] SQL "%s" applied successfully\n`, revertStatement)

return nil
}
Loading

0 comments on commit 16d1d7f

Please sign in to comment.