diff --git a/docs/resources/grant_privileges_to_account_role.md b/docs/resources/grant_privileges_to_account_role.md
new file mode 100644
index 0000000000..ff4b2755fc
--- /dev/null
+++ b/docs/resources/grant_privileges_to_account_role.md
@@ -0,0 +1,396 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "snowflake_grant_privileges_to_account_role Resource - terraform-provider-snowflake"
+subcategory: ""
+description: |-
+
+---
+
+~> **Note** This is a preview resource. It's ready for general use. In case of any errors, please file an issue in our GitHub repository.
+
+
+!> **Warning** Be careful when using `always_apply` field. It will always produce a plan (even when no changes were made) and can be harmful in some setups. For more details why we decided to introduce it to go our document explaining those design decisions (coming soon).
+
+# snowflake_grant_privileges_to_account_role (Resource)
+
+
+
+## Example Usage
+
+```terraform
+resource "snowflake_database" "db" {
+ name = "database"
+}
+
+resource "snowflake_role" "db_role" {
+ name = "role_name"
+}
+
+##################################
+### on account privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["CREATE DATABASE", "CREATE USER"]
+ account_role_name = snowflake_role.db_role.name
+ on_account = true
+}
+
+## ID: "\"role_name\"|false|false|CREATE DATABASE,CREATE USER|OnAccount"
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account = true
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|ALL|OnAccount"
+
+# all privileges + grant option + always apply
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account = true
+ always_apply = true
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|true|ALL|OnAccount"
+
+##################################
+### on account object privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["CREATE SCHEMA", "CREATE DATABASE ROLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = snowflake_database.db.name
+ }
+}
+
+## ID: "\"role_name\"|false|false|CREATE SCHEMA,CREATE DATABASE ROLE|OnAccountObject|DATABASE|\"database\""
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = snowflake_database.db.name
+ }
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|ALL|OnAccountObject|DATABASE|\"database\""
+
+# all privileges + grant option + always apply
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = snowflake_database.db.name
+ }
+ always_apply = true
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|true|ALL|OnAccountObject|DATABASE|\"database\""
+
+##################################
+### schema privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["MODIFY", "CREATE TABLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ schema_name = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+}
+
+## ID: "\"role_name\"|false|false|MODIFY,CREATE TABLE|OnSchema|OnSchema|\"database\".\"my_schema\""
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ schema_name = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|MODIFY,CREATE TABLE|OnSchema|OnSchema|\"database\".\"my_schema\""
+
+# all schemas in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["MODIFY", "CREATE TABLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ all_schemas_in_database = snowflake_database.db.name
+ }
+}
+
+## ID: "\"role_name\"|false|false|MODIFY,CREATE TABLE|OnSchema|OnAllSchemasInDatabase|\"database\""
+
+# future schemas in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["MODIFY", "CREATE TABLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ future_schemas_in_database = snowflake_database.db.name
+ }
+}
+
+## ID: "\"role_name\"|false|false|MODIFY,CREATE TABLE|OnSchema|OnFutureSchemasInDatabase|\"database\""
+
+##################################
+### schema object privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "REFERENCES"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ object_type = "VIEW"
+ object_name = "\"${snowflake_database.db.name}\".\"my_schema\".\"my_view\"" # note this is a fully qualified name!
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,REFERENCES|OnSchemaObject|VIEW|\"database\".\"my_schema\".\"my_view\""
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ object_type = "VIEW"
+ object_name = "\"${snowflake_database.db.name}\".\"my_schema\".\"my_view\"" # note this is a fully qualified name!
+ }
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|ALL|OnSchemaObject|OnObject|VIEW|\"database\".\"my_schema\".\"my_view\""
+
+# all in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ all {
+ object_type_plural = "TABLES"
+ in_database = snowflake_database.db.name
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnAll|TABLES|InDatabase|\"database\""
+
+# all in schema
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ all {
+ object_type_plural = "TABLES"
+ in_schema = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnAll|TABLES|InSchema|\"database\".\"my_schema\""
+
+# future in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ future {
+ object_type_plural = "TABLES"
+ in_database = snowflake_database.db.name
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnFuture|TABLES|InDatabase|\"database\""
+
+# future in schema
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ future {
+ object_type_plural = "TABLES"
+ in_schema = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnFuture|TABLES|InSchema|\"database\".\"my_schema\""
+```
+
+
+## Schema
+
+### Required
+
+- `account_role_name` (String) The fully qualified name of the account role to which privileges will be granted.
+
+### Optional
+
+- `all_privileges` (Boolean) Grant all privileges on the account role.
+- `always_apply` (Boolean) If true, the resource will always produce a “plan” and on “apply” it will re-grant defined privileges. It is supposed to be used only in “grant privileges on all X’s in database / schema Y” or “grant all privileges to X” scenarios to make sure that every new object in a given database / schema is granted by the account role and every new privilege is granted to the database role. Important note: this flag is not compliant with the Terraform assumptions of the config being eventually convergent (producing an empty plan).
+- `always_apply_trigger` (String) This is a helper field and should not be set. Its main purpose is to help to achieve the functionality described by the always_apply field.
+- `on_account` (Boolean) If true, the privileges will be granted on the account.
+- `on_account_object` (Block List, Max: 1) Specifies the account object on which privileges will be granted (see [below for nested schema](#nestedblock--on_account_object))
+- `on_schema` (Block List, Max: 1) Specifies the schema on which privileges will be granted. (see [below for nested schema](#nestedblock--on_schema))
+- `on_schema_object` (Block List, Max: 1) Specifies the schema object on which privileges will be granted. (see [below for nested schema](#nestedblock--on_schema_object))
+- `privileges` (Set of String) The privileges to grant on the account role.
+- `with_grant_option` (Boolean) Specifies whether the grantee can grant the privileges to other users.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `on_account_object`
+
+Required:
+
+- `object_name` (String) The fully qualified name of the object on which privileges will be granted.
+- `object_type` (String) The object type of the account object on which privileges will be granted. Valid values are: USER | RESOURCE MONITOR | WAREHOUSE | COMPUTE POOL | DATABASE | INTEGRATION | FAILOVER GROUP | REPLICATION GROUP | EXTERNAL VOLUME
+
+
+
+### Nested Schema for `on_schema`
+
+Optional:
+
+- `all_schemas_in_database` (String) The fully qualified name of the database.
+- `future_schemas_in_database` (String) The fully qualified name of the database.
+- `schema_name` (String) The fully qualified name of the schema.
+
+
+
+### Nested Schema for `on_schema_object`
+
+Optional:
+
+- `all` (Block List, Max: 1) Configures the privilege to be granted on all objects in either a database or schema. (see [below for nested schema](#nestedblock--on_schema_object--all))
+- `future` (Block List, Max: 1) Configures the privilege to be granted on all objects in either a database or schema. (see [below for nested schema](#nestedblock--on_schema_object--future))
+- `object_name` (String) The fully qualified name of the object on which privileges will be granted.
+- `object_type` (String) The object type of the schema object on which privileges will be granted. Valid values are: ALERT | DYNAMIC TABLE | EVENT TABLE | FILE FORMAT | FUNCTION | PROCEDURE | SECRET | SEQUENCE | PIPE | MASKING POLICY | PASSWORD POLICY | ROW ACCESS POLICY | SESSION POLICY | TAG | STAGE | STREAM | TABLE | EXTERNAL TABLE | TASK | VIEW | MATERIALIZED VIEW | NETWORK RULE | PACKAGES POLICY | ICEBERG TABLE
+
+
+### Nested Schema for `on_schema_object.all`
+
+Required:
+
+- `object_type_plural` (String) The plural object type of the schema object on which privileges will be granted. Valid values are: ALERTS | DYNAMIC TABLES | EVENT TABLES | FILE FORMATS | FUNCTIONS | PROCEDURES | SECRETS | SEQUENCES | PIPES | MASKING POLICIES | PASSWORD POLICIES | ROW ACCESS POLICIES | SESSION POLICIES | TAGS | STAGES | STREAMS | TABLES | EXTERNAL TABLES | TASKS | VIEWS | MATERIALIZED VIEWS | NETWORK RULES | PACKAGES POLICIES | ICEBERG TABLES
+
+Optional:
+
+- `in_database` (String)
+- `in_schema` (String)
+
+
+
+### Nested Schema for `on_schema_object.future`
+
+Required:
+
+- `object_type_plural` (String) The plural object type of the schema object on which privileges will be granted. Valid values are: ALERTS | DYNAMIC TABLES | EVENT TABLES | FILE FORMATS | FUNCTIONS | PROCEDURES | SECRETS | SEQUENCES | PIPES | MASKING POLICIES | PASSWORD POLICIES | ROW ACCESS POLICIES | SESSION POLICIES | TAGS | STAGES | STREAMS | TABLES | EXTERNAL TABLES | TASKS | VIEWS | MATERIALIZED VIEWS | NETWORK RULES | PACKAGES POLICIES | ICEBERG TABLES
+
+Optional:
+
+- `in_database` (String)
+- `in_schema` (String)
+
+## Import
+
+~> **Note** All the ..._name parts should be fully qualified names, e.g. for schema object it is `""."".""`
+~> **Note** To import all_privileges write ALL or ALL PRIVILEGES in place of ``
+
+Import is supported using the following syntax:
+
+`terraform import "|||||"`
+
+where:
+- account_role_name - fully qualified identifier
+- with_grant_option - boolean
+- always_apply - boolean
+- privileges - list of privileges, comma separated; to import all_privileges write "ALL" or "ALL PRIVILEGES"
+- grant_type - enum
+- grant_data - enum data
+
+It has varying number of parts, depending on grant_type. All the possible types are:
+
+### OnAccount
+`terraform import "||||OnAccount`
+
+### OnAccountObject
+`terraform import "||||OnAccountObject||`
+
+### OnSchema
+
+On schema contains inner types for all options.
+
+#### OnSchema
+`terraform import "||||OnSchema|OnSchema|"`
+
+#### OnAllSchemasInDatabase
+`terraform import "||||OnSchema|OnAllSchemasInDatabase|"`
+
+#### OnFutureSchemasInDatabase
+`terraform import "||||OnSchema|OnFutureSchemasInDatabase|"`
+
+### OnSchemaObject
+
+On schema object contains inner types for all options.
+
+#### OnObject
+`terraform import "||||OnSchemaObject|OnObject||"`
+
+#### OnAll
+
+On all contains inner types for all options.
+
+##### InDatabase
+`terraform import "||||OnSchemaObject|OnAll||InDatabase|"`
+
+##### InSchema
+`terraform import "||||OnSchemaObject|OnAll||InSchema|"`
+
+#### OnFuture
+
+On future contains inner types for all options.
+
+##### InDatabase
+`terraform import "||||OnSchemaObject|OnFuture||InDatabase|"`
+
+##### InSchema
+`terraform import "||||OnSchemaObject|OnFuture||InSchema|"`
+
+### Import examples
+
+#### Grant all privileges OnAccountObject (Database)
+`terraform import "\"test_db_role\"|false|false|ALL|OnAccountObject|DATABASE|\"test_db\""`
+
+#### Grant list of privileges OnAllSchemasInDatabase
+`terraform import "\"test_db_role\"|false|false|CREATE TAG,CREATE TABLE|OnSchema|OnAllSchemasInDatabase|\"test_db\""`
+
+#### Grant list of privileges on table
+`terraform import "\"test_db_role\"|false|false|SELECT,DELETE,INSERT|OnSchemaObject|OnObject|TABLE|\"test_db\".\"test_schema\".\"test_table\""`
+
+#### Grant list of privileges OnAll tables in schema
+`terraform import "\"test_db_role\"|false|false|SELECT,DELETE,INSERT|OnSchemaObject|OnAll|TABLES|InSchema|\"test_db\".\"test_schema\""`
+
diff --git a/docs/resources/grant_privileges_to_database_role.md b/docs/resources/grant_privileges_to_database_role.md
index 067ee9caea..104bcdc9ab 100644
--- a/docs/resources/grant_privileges_to_database_role.md
+++ b/docs/resources/grant_privileges_to_database_role.md
@@ -6,6 +6,8 @@ description: |-
---
+~> **Note** This is a preview resource. It's ready for general use. In case of any errors, please file an issue in our GitHub repository.
+
!> **Warning** Be careful when using `always_apply` field. It will always produce a plan (even when no changes were made) and can be harmful in some setups. For more details why we decided to introduce it to go our document explaining those design decisions (coming soon).
@@ -175,7 +177,7 @@ resource "snowflake_grant_privileges_to_database_role" "example" {
- `all_privileges` (Boolean) Grant all privileges on the database role.
- `always_apply` (Boolean) If true, the resource will always produce a “plan” and on “apply” it will re-grant defined privileges. It is supposed to be used only in “grant privileges on all X’s in database / schema Y” or “grant all privileges to X” scenarios to make sure that every new object in a given database / schema is granted by the account role and every new privilege is granted to the database role. Important note: this flag is not compliant with the Terraform assumptions of the config being eventually convergent (producing an empty plan).
-- `always_apply_trigger` (String) This field should not be set and its main purpose is to achieve the functionality described by always_apply field. This is value will be flipped to the opposite value on every terraform apply, thus creating a new plan that will re-apply grants.
+- `always_apply_trigger` (String) This is a helper field and should not be set. Its main purpose is to help to achieve the functionality described by the always_apply field.
- `on_database` (String) The fully qualified name of the database on which privileges will be granted.
- `on_schema` (Block List, Max: 1) Specifies the schema on which privileges will be granted. (see [below for nested schema](#nestedblock--on_schema))
- `on_schema_object` (Block List, Max: 1) Specifies the schema object on which privileges will be granted. (see [below for nested schema](#nestedblock--on_schema_object))
diff --git a/examples/resources/snowflake_grant_privileges_to_account_role/resource.tf b/examples/resources/snowflake_grant_privileges_to_account_role/resource.tf
new file mode 100644
index 0000000000..7b7bf3e228
--- /dev/null
+++ b/examples/resources/snowflake_grant_privileges_to_account_role/resource.tf
@@ -0,0 +1,218 @@
+resource "snowflake_database" "db" {
+ name = "database"
+}
+
+resource "snowflake_role" "db_role" {
+ name = "role_name"
+}
+
+##################################
+### on account privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["CREATE DATABASE", "CREATE USER"]
+ account_role_name = snowflake_role.db_role.name
+ on_account = true
+}
+
+## ID: "\"role_name\"|false|false|CREATE DATABASE,CREATE USER|OnAccount"
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account = true
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|ALL|OnAccount"
+
+# all privileges + grant option + always apply
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account = true
+ always_apply = true
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|true|ALL|OnAccount"
+
+##################################
+### on account object privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["CREATE SCHEMA", "CREATE DATABASE ROLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = snowflake_database.db.name
+ }
+}
+
+## ID: "\"role_name\"|false|false|CREATE SCHEMA,CREATE DATABASE ROLE|OnAccountObject|DATABASE|\"database\""
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = snowflake_database.db.name
+ }
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|ALL|OnAccountObject|DATABASE|\"database\""
+
+# all privileges + grant option + always apply
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = snowflake_database.db.name
+ }
+ always_apply = true
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|true|ALL|OnAccountObject|DATABASE|\"database\""
+
+##################################
+### schema privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["MODIFY", "CREATE TABLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ schema_name = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+}
+
+## ID: "\"role_name\"|false|false|MODIFY,CREATE TABLE|OnSchema|OnSchema|\"database\".\"my_schema\""
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ schema_name = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|MODIFY,CREATE TABLE|OnSchema|OnSchema|\"database\".\"my_schema\""
+
+# all schemas in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["MODIFY", "CREATE TABLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ all_schemas_in_database = snowflake_database.db.name
+ }
+}
+
+## ID: "\"role_name\"|false|false|MODIFY,CREATE TABLE|OnSchema|OnAllSchemasInDatabase|\"database\""
+
+# future schemas in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["MODIFY", "CREATE TABLE"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema {
+ future_schemas_in_database = snowflake_database.db.name
+ }
+}
+
+## ID: "\"role_name\"|false|false|MODIFY,CREATE TABLE|OnSchema|OnFutureSchemasInDatabase|\"database\""
+
+##################################
+### schema object privileges
+##################################
+
+# list of privileges
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "REFERENCES"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ object_type = "VIEW"
+ object_name = "\"${snowflake_database.db.name}\".\"my_schema\".\"my_view\"" # note this is a fully qualified name!
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,REFERENCES|OnSchemaObject|VIEW|\"database\".\"my_schema\".\"my_view\""
+
+# all privileges + grant option
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ object_type = "VIEW"
+ object_name = "\"${snowflake_database.db.name}\".\"my_schema\".\"my_view\"" # note this is a fully qualified name!
+ }
+ all_privileges = true
+ with_grant_option = true
+}
+
+## ID: "\"role_name\"|true|false|ALL|OnSchemaObject|OnObject|VIEW|\"database\".\"my_schema\".\"my_view\""
+
+# all in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ all {
+ object_type_plural = "TABLES"
+ in_database = snowflake_database.db.name
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnAll|TABLES|InDatabase|\"database\""
+
+# all in schema
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ all {
+ object_type_plural = "TABLES"
+ in_schema = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnAll|TABLES|InSchema|\"database\".\"my_schema\""
+
+# future in database
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ future {
+ object_type_plural = "TABLES"
+ in_database = snowflake_database.db.name
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnFuture|TABLES|InDatabase|\"database\""
+
+# future in schema
+resource "snowflake_grant_privileges_to_account_role" "example" {
+ privileges = ["SELECT", "INSERT"]
+ account_role_name = snowflake_role.db_role.name
+ on_schema_object {
+ future {
+ object_type_plural = "TABLES"
+ in_schema = "\"${snowflake_database.db.name}\".\"my_schema\"" # note this is a fully qualified name!
+ }
+ }
+}
+
+## ID: "\"role_name\"|false|false|SELECT,INSERT|OnSchemaObject|OnFuture|TABLES|InSchema|\"database\".\"my_schema\""
diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go
index b72a7f76bb..ac77870a3c 100644
--- a/pkg/provider/provider.go
+++ b/pkg/provider/provider.go
@@ -446,6 +446,7 @@ func getResources() map[string]*schema.Resource {
"snowflake_grant_account_role": resources.GrantAccountRole(),
"snowflake_grant_database_role": resources.GrantDatabaseRole(),
"snowflake_grant_privileges_to_role": resources.GrantPrivilegesToRole(),
+ "snowflake_grant_privileges_to_account_role": resources.GrantPrivilegesToAccountRole(),
"snowflake_grant_privileges_to_database_role": resources.GrantPrivilegesToDatabaseRole(),
"snowflake_managed_account": resources.ManagedAccount(),
"snowflake_masking_policy": resources.MaskingPolicy(),
diff --git a/pkg/resources/account_grant.go b/pkg/resources/account_grant.go
index 00cb2b6594..e85577e64c 100644
--- a/pkg/resources/account_grant.go
+++ b/pkg/resources/account_grant.go
@@ -88,7 +88,7 @@ func AccountGrant() *TerraformGrantResource {
Delete: DeleteAccountGrant,
Update: UpdateAccountGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: accountGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go
index 6179b2e0a7..e83061ca36 100644
--- a/pkg/resources/external_table_grant.go
+++ b/pkg/resources/external_table_grant.go
@@ -107,7 +107,8 @@ func ExternalTableGrant() *TerraformGrantResource {
Read: ReadExternalTableGrant,
Delete: DeleteExternalTableGrant,
Update: UpdateExternalTableGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.", Schema: externalTableGrantSchema,
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
+ Schema: externalTableGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), helpers.IDDelimiter)
diff --git a/pkg/resources/failover_group_grant.go b/pkg/resources/failover_group_grant.go
index 3bc267a700..bfdd6c8938 100644
--- a/pkg/resources/failover_group_grant.go
+++ b/pkg/resources/failover_group_grant.go
@@ -76,7 +76,8 @@ func FailoverGroupGrant() *TerraformGrantResource {
Read: ReadFailoverGroupGrant,
Delete: DeleteFailoverGroupGrant,
Update: UpdateFailoverGroupGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.", Schema: failoverGroupGrantSchema,
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
+ Schema: failoverGroupGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), helpers.IDDelimiter)
diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go
index 46564f878f..390dfcf59f 100644
--- a/pkg/resources/file_format_grant.go
+++ b/pkg/resources/file_format_grant.go
@@ -103,7 +103,7 @@ func FileFormatGrant() *TerraformGrantResource {
Read: ReadFileFormatGrant,
Delete: DeleteFileFormatGrant,
Update: UpdateFileFormatGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: fileFormatGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go
index ee661e486a..12fd864cbb 100644
--- a/pkg/resources/function_grant.go
+++ b/pkg/resources/function_grant.go
@@ -115,7 +115,7 @@ func FunctionGrant() *TerraformGrantResource {
Read: ReadFunctionGrant,
Delete: DeleteFunctionGrant,
Update: UpdateFunctionGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: functionGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/grant_helpers.go b/pkg/resources/grant_helpers.go
index dcaa284cb5..df015d0fa6 100644
--- a/pkg/resources/grant_helpers.go
+++ b/pkg/resources/grant_helpers.go
@@ -6,6 +6,10 @@ import (
"strings"
"time"
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+ "github.com/hashicorp/go-cty/cty"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/jmoiron/sqlx"
@@ -386,3 +390,78 @@ func changeDiff(d *schema.ResourceData, key string) (toAdd []string, toRemove []
toRemove = expandStringList(oldSet.Difference(newSet).List())
return
}
+
+func isNotOwnershipGrant() func(value any, path cty.Path) diag.Diagnostics {
+ return func(value any, path cty.Path) diag.Diagnostics {
+ var diags diag.Diagnostics
+ if privilege, ok := value.(string); ok && strings.ToUpper(privilege) == "OWNERSHIP" {
+ diags = append(diags, diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Unsupported privilege 'OWNERSHIP'",
+ // TODO: Change when a new resource for granting ownership will be available (SNOW-991423)
+ Detail: "Granting ownership is only allowed in dedicated resources (snowflake_user_ownership_grant, snowflake_role_ownership_grant)",
+ AttributePath: nil,
+ })
+ }
+ return diags
+ }
+}
+
+func ValidGrantedObjectType() schema.SchemaValidateDiagFunc {
+ return StringInSlice([]string{
+ sdk.ObjectTypeAlert.String(),
+ sdk.ObjectTypeDynamicTable.String(),
+ sdk.ObjectTypeEventTable.String(),
+ sdk.ObjectTypeFileFormat.String(),
+ sdk.ObjectTypeFunction.String(),
+ sdk.ObjectTypeProcedure.String(),
+ sdk.ObjectTypeSecret.String(),
+ sdk.ObjectTypeSequence.String(),
+ sdk.ObjectTypePipe.String(),
+ sdk.ObjectTypeMaskingPolicy.String(),
+ sdk.ObjectTypePasswordPolicy.String(),
+ sdk.ObjectTypeRowAccessPolicy.String(),
+ sdk.ObjectTypeSessionPolicy.String(),
+ sdk.ObjectTypeTag.String(),
+ sdk.ObjectTypeStage.String(),
+ sdk.ObjectTypeStream.String(),
+ sdk.ObjectTypeTable.String(),
+ sdk.ObjectTypeExternalTable.String(),
+ sdk.ObjectTypeTask.String(),
+ sdk.ObjectTypeView.String(),
+ sdk.ObjectTypeMaterializedView.String(),
+ sdk.ObjectTypeNetworkRule.String(),
+ sdk.ObjectTypePackagesPolicy.String(),
+ sdk.ObjectTypeIcebergTable.String(),
+ }, true)
+}
+
+func ValidGrantedPluralObjectType() schema.SchemaValidateDiagFunc {
+ return StringInSlice(
+ []string{
+ sdk.PluralObjectTypeAlerts.String(),
+ sdk.PluralObjectTypeDynamicTables.String(),
+ sdk.PluralObjectTypeEventTables.String(),
+ sdk.PluralObjectTypeFileFormats.String(),
+ sdk.PluralObjectTypeFunctions.String(),
+ sdk.PluralObjectTypeProcedures.String(),
+ sdk.PluralObjectTypeSecrets.String(),
+ sdk.PluralObjectTypeSequences.String(),
+ sdk.PluralObjectTypePipes.String(),
+ sdk.PluralObjectTypeMaskingPolicies.String(),
+ sdk.PluralObjectTypePasswordPolicies.String(),
+ sdk.PluralObjectTypeRowAccessPolicies.String(),
+ sdk.PluralObjectTypeSessionPolicies.String(),
+ sdk.PluralObjectTypeTags.String(),
+ sdk.PluralObjectTypeStages.String(),
+ sdk.PluralObjectTypeStreams.String(),
+ sdk.PluralObjectTypeTables.String(),
+ sdk.PluralObjectTypeExternalTables.String(),
+ sdk.PluralObjectTypeTasks.String(),
+ sdk.PluralObjectTypeViews.String(),
+ sdk.PluralObjectTypeMaterializedViews.String(),
+ sdk.PluralObjectTypeNetworkRules.String(),
+ sdk.PluralObjectTypePackagesPolicies.String(),
+ sdk.PluralObjectTypeIcebergTables.String(),
+ }, true)
+}
diff --git a/pkg/resources/grant_privileges_identifier_commons.go b/pkg/resources/grant_privileges_identifier_commons.go
new file mode 100644
index 0000000000..e8057f7dfb
--- /dev/null
+++ b/pkg/resources/grant_privileges_identifier_commons.go
@@ -0,0 +1,117 @@
+package resources
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+)
+
+type OnSchemaGrantKind string
+
+const (
+ OnSchemaSchemaGrantKind OnSchemaGrantKind = "OnSchema"
+ OnAllSchemasInDatabaseSchemaGrantKind OnSchemaGrantKind = "OnAllSchemasInDatabase"
+ OnFutureSchemasInDatabaseSchemaGrantKind OnSchemaGrantKind = "OnFutureSchemasInDatabase"
+)
+
+type OnSchemaObjectGrantKind string
+
+const (
+ OnObjectSchemaObjectGrantKind OnSchemaObjectGrantKind = "OnObject"
+ OnAllSchemaObjectGrantKind OnSchemaObjectGrantKind = "OnAll"
+ OnFutureSchemaObjectGrantKind OnSchemaObjectGrantKind = "OnFuture"
+)
+
+type OnSchemaGrantData struct {
+ Kind OnSchemaGrantKind
+ SchemaName *sdk.DatabaseObjectIdentifier
+ DatabaseName *sdk.AccountObjectIdentifier
+}
+
+func (d *OnSchemaGrantData) String() string {
+ var parts []string
+ parts = append(parts, string(d.Kind))
+ switch d.Kind {
+ case OnSchemaSchemaGrantKind:
+ parts = append(parts, d.SchemaName.FullyQualifiedName())
+ case OnAllSchemasInDatabaseSchemaGrantKind, OnFutureSchemasInDatabaseSchemaGrantKind:
+ parts = append(parts, d.DatabaseName.FullyQualifiedName())
+ }
+ return strings.Join(parts, helpers.IDDelimiter)
+}
+
+type OnSchemaObjectGrantData struct {
+ Kind OnSchemaObjectGrantKind
+ Object *sdk.Object
+ OnAllOrFuture *BulkOperationGrantData
+}
+
+func (d *OnSchemaObjectGrantData) String() string {
+ var parts []string
+ parts = append(parts, string(d.Kind))
+ switch d.Kind {
+ case OnObjectSchemaObjectGrantKind:
+ parts = append(parts, fmt.Sprintf("%s|%s", d.Object.ObjectType, d.Object.Name.FullyQualifiedName()))
+ case OnAllSchemaObjectGrantKind, OnFutureSchemaObjectGrantKind:
+ parts = append(parts, d.OnAllOrFuture.ObjectNamePlural.String())
+ parts = append(parts, string(d.OnAllOrFuture.Kind))
+ switch d.OnAllOrFuture.Kind {
+ case InDatabaseBulkOperationGrantKind:
+ parts = append(parts, d.OnAllOrFuture.Database.FullyQualifiedName())
+ case InSchemaBulkOperationGrantKind:
+ parts = append(parts, d.OnAllOrFuture.Schema.FullyQualifiedName())
+ }
+ }
+ return strings.Join(parts, helpers.IDDelimiter)
+}
+
+type BulkOperationGrantKind string
+
+const (
+ InDatabaseBulkOperationGrantKind BulkOperationGrantKind = "InDatabase"
+ InSchemaBulkOperationGrantKind BulkOperationGrantKind = "InSchema"
+)
+
+type BulkOperationGrantData struct {
+ ObjectNamePlural sdk.PluralObjectType
+ Kind BulkOperationGrantKind
+ Database *sdk.AccountObjectIdentifier
+ Schema *sdk.DatabaseObjectIdentifier
+}
+
+func getBulkOperationGrantData(in *sdk.GrantOnSchemaObjectIn) *BulkOperationGrantData {
+ bulkOperationGrantData := &BulkOperationGrantData{
+ ObjectNamePlural: in.PluralObjectType,
+ }
+
+ if in.InDatabase != nil {
+ bulkOperationGrantData.Kind = InDatabaseBulkOperationGrantKind
+ bulkOperationGrantData.Database = in.InDatabase
+ }
+
+ if in.InSchema != nil {
+ bulkOperationGrantData.Kind = InSchemaBulkOperationGrantKind
+ bulkOperationGrantData.Schema = in.InSchema
+ }
+
+ return bulkOperationGrantData
+}
+
+func getGrantOnSchemaObjectIn(allOrFuture map[string]any) *sdk.GrantOnSchemaObjectIn {
+ pluralObjectType := sdk.PluralObjectType(allOrFuture["object_type_plural"].(string))
+ grantOnSchemaObjectIn := &sdk.GrantOnSchemaObjectIn{
+ PluralObjectType: pluralObjectType,
+ }
+
+ if inDatabase, ok := allOrFuture["in_database"].(string); ok && len(inDatabase) > 0 {
+ grantOnSchemaObjectIn.InDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(inDatabase))
+ }
+
+ if inSchema, ok := allOrFuture["in_schema"].(string); ok && len(inSchema) > 0 {
+ grantOnSchemaObjectIn.InSchema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(inSchema))
+ }
+
+ return grantOnSchemaObjectIn
+}
diff --git a/pkg/resources/grant_privileges_to_account_role.go b/pkg/resources/grant_privileges_to_account_role.go
new file mode 100644
index 0000000000..01b42e18c3
--- /dev/null
+++ b/pkg/resources/grant_privileges_to_account_role.go
@@ -0,0 +1,1111 @@
+package resources
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "slices"
+
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/logging"
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+ "github.com/hashicorp/go-uuid"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+)
+
+var grantPrivilegesToAccountRoleSchema = map[string]*schema.Schema{
+ "account_role_name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "The fully qualified name of the account role to which privileges will be granted.",
+ ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+ },
+ "privileges": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Description: "The privileges to grant on the account role.",
+ ExactlyOneOf: []string{
+ "privileges",
+ "all_privileges",
+ },
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ ValidateDiagFunc: isNotOwnershipGrant(),
+ },
+ },
+ "all_privileges": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ Description: "Grant all privileges on the account role.",
+ ExactlyOneOf: []string{
+ "privileges",
+ "all_privileges",
+ },
+ },
+ "with_grant_option": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ ForceNew: true,
+ Description: "Specifies whether the grantee can grant the privileges to other users.",
+ },
+ "always_apply": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ Description: "If true, the resource will always produce a “plan” and on “apply” it will re-grant defined privileges. It is supposed to be used only in “grant privileges on all X’s in database / schema Y” or “grant all privileges to X” scenarios to make sure that every new object in a given database / schema is granted by the account role and every new privilege is granted to the database role. Important note: this flag is not compliant with the Terraform assumptions of the config being eventually convergent (producing an empty plan).",
+ },
+ "always_apply_trigger": {
+ Type: schema.TypeString,
+ Optional: true,
+ Default: "",
+ Description: "This is a helper field and should not be set. Its main purpose is to help to achieve the functionality described by the always_apply field.",
+ },
+ "on_account": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ ForceNew: true,
+ Description: "If true, the privileges will be granted on the account.",
+ ExactlyOneOf: []string{
+ "on_account",
+ "on_account_object",
+ "on_schema",
+ "on_schema_object",
+ },
+ },
+ "on_account_object": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: "Specifies the account object on which privileges will be granted ",
+ MaxItems: 1,
+ ExactlyOneOf: []string{
+ "on_account",
+ "on_account_object",
+ "on_schema",
+ "on_schema_object",
+ },
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "object_type": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "The object type of the account object on which privileges will be granted. Valid values are: USER | RESOURCE MONITOR | WAREHOUSE | COMPUTE POOL | DATABASE | INTEGRATION | FAILOVER GROUP | REPLICATION GROUP | EXTERNAL VOLUME",
+ ValidateFunc: validation.StringInSlice([]string{
+ "USER",
+ "RESOURCE MONITOR",
+ "WAREHOUSE",
+ "COMPUTE POOL",
+ "DATABASE",
+ "INTEGRATION",
+ "FAILOVER GROUP",
+ "REPLICATION GROUP",
+ "EXTERNAL VOLUME",
+ }, true),
+ },
+ "object_name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "The fully qualified name of the object on which privileges will be granted.",
+ ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+ },
+ },
+ },
+ },
+ "on_schema": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: "Specifies the schema on which privileges will be granted.",
+ MaxItems: 1,
+ ExactlyOneOf: []string{
+ "on_account",
+ "on_account_object",
+ "on_schema",
+ "on_schema_object",
+ },
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "schema_name": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "The fully qualified name of the schema.",
+ ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](),
+ ExactlyOneOf: []string{
+ "on_schema.0.schema_name",
+ "on_schema.0.all_schemas_in_database",
+ "on_schema.0.future_schemas_in_database",
+ },
+ },
+ "all_schemas_in_database": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "The fully qualified name of the database.",
+ ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+ ExactlyOneOf: []string{
+ "on_schema.0.schema_name",
+ "on_schema.0.all_schemas_in_database",
+ "on_schema.0.future_schemas_in_database",
+ },
+ },
+ "future_schemas_in_database": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "The fully qualified name of the database.",
+ ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+ ExactlyOneOf: []string{
+ "on_schema.0.schema_name",
+ "on_schema.0.all_schemas_in_database",
+ "on_schema.0.future_schemas_in_database",
+ },
+ },
+ },
+ },
+ },
+ "on_schema_object": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: "Specifies the schema object on which privileges will be granted.",
+ MaxItems: 1,
+ ExactlyOneOf: []string{
+ "on_account",
+ "on_account_object",
+ "on_schema",
+ "on_schema_object",
+ },
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "object_type": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "The object type of the schema object on which privileges will be granted. Valid values are: ALERT | DYNAMIC TABLE | EVENT TABLE | FILE FORMAT | FUNCTION | PROCEDURE | SECRET | SEQUENCE | PIPE | MASKING POLICY | PASSWORD POLICY | ROW ACCESS POLICY | SESSION POLICY | TAG | STAGE | STREAM | TABLE | EXTERNAL TABLE | TASK | VIEW | MATERIALIZED VIEW | NETWORK RULE | PACKAGES POLICY | ICEBERG TABLE",
+ RequiredWith: []string{
+ "on_schema_object.0.object_name",
+ },
+ ConflictsWith: []string{
+ "on_schema_object.0.all",
+ "on_schema_object.0.future",
+ },
+ ValidateDiagFunc: ValidGrantedObjectType(),
+ },
+ "object_name": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ Description: "The fully qualified name of the object on which privileges will be granted.",
+ RequiredWith: []string{
+ "on_schema_object.0.object_type",
+ },
+ ExactlyOneOf: []string{
+ "on_schema_object.0.object_name",
+ "on_schema_object.0.all",
+ "on_schema_object.0.future",
+ },
+ ValidateDiagFunc: IsValidIdentifier[sdk.SchemaObjectIdentifier](),
+ },
+ "all": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: "Configures the privilege to be granted on all objects in either a database or schema.",
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: grantPrivilegesOnAccountRoleBulkOperationSchema,
+ },
+ ConflictsWith: []string{
+ "on_schema_object.0.object_type",
+ },
+ ExactlyOneOf: []string{
+ "on_schema_object.0.object_name",
+ "on_schema_object.0.all",
+ "on_schema_object.0.future",
+ },
+ },
+ "future": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Description: "Configures the privilege to be granted on all objects in either a database or schema.",
+ MaxItems: 1,
+ Elem: &schema.Resource{
+ Schema: grantPrivilegesOnAccountRoleBulkOperationSchema,
+ },
+ ConflictsWith: []string{
+ "on_schema_object.0.object_type",
+ },
+ ExactlyOneOf: []string{
+ "on_schema_object.0.object_name",
+ "on_schema_object.0.all",
+ "on_schema_object.0.future",
+ },
+ },
+ },
+ },
+ },
+}
+
+var grantPrivilegesOnAccountRoleBulkOperationSchema = map[string]*schema.Schema{
+ "object_type_plural": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "The plural object type of the schema object on which privileges will be granted. Valid values are: ALERTS | DYNAMIC TABLES | EVENT TABLES | FILE FORMATS | FUNCTIONS | PROCEDURES | SECRETS | SEQUENCES | PIPES | MASKING POLICIES | PASSWORD POLICIES | ROW ACCESS POLICIES | SESSION POLICIES | TAGS | STAGES | STREAMS | TABLES | EXTERNAL TABLES | TASKS | VIEWS | MATERIALIZED VIEWS | NETWORK RULES | PACKAGES POLICIES | ICEBERG TABLES",
+ ValidateDiagFunc: ValidGrantedPluralObjectType(),
+ },
+ "in_database": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](),
+ },
+ "in_schema": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](),
+ },
+}
+
+func GrantPrivilegesToAccountRole() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: CreateGrantPrivilegesToAccountRole,
+ UpdateContext: UpdateGrantPrivilegesToAccountRole,
+ DeleteContext: DeleteGrantPrivilegesToAccountRole,
+ ReadContext: ReadGrantPrivilegesToAccountRole,
+
+ Schema: grantPrivilegesToAccountRoleSchema,
+ Importer: &schema.ResourceImporter{
+ StateContext: ImportGrantPrivilegesToAccountRole(),
+ },
+ }
+}
+
+func ImportGrantPrivilegesToAccountRole() func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
+ return func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
+ logging.DebugLogger.Printf("[DEBUG] Entering import grant privileges to account role")
+ id, err := ParseGrantPrivilegesToAccountRoleId(d.Id())
+ if err != nil {
+ return nil, err
+ }
+ logging.DebugLogger.Printf("[DEBUG] Imported identifier: %s", id.String())
+ if err := d.Set("account_role_name", id.RoleName.FullyQualifiedName()); err != nil {
+ return nil, err
+ }
+ if err := d.Set("with_grant_option", id.WithGrantOption); err != nil {
+ return nil, err
+ }
+ if err := d.Set("always_apply", id.AlwaysApply); err != nil {
+ return nil, err
+ }
+ if err := d.Set("all_privileges", id.AllPrivileges); err != nil {
+ return nil, err
+ }
+ if err := d.Set("privileges", id.Privileges); err != nil {
+ return nil, err
+ }
+ if err := d.Set("on_account", false); err != nil {
+ return nil, err
+ }
+
+ switch id.Kind {
+ case OnAccountAccountRoleGrantKind:
+ if err := d.Set("on_account", true); err != nil {
+ return nil, err
+ }
+ case OnAccountObjectAccountRoleGrantKind:
+ data := id.Data.(*OnAccountObjectGrantData)
+ onAccountObject := make(map[string]any)
+ onAccountObject["object_type"] = data.ObjectType.String()
+ onAccountObject["object_name"] = data.ObjectName.FullyQualifiedName()
+
+ if err := d.Set("on_account_object", []any{onAccountObject}); err != nil {
+ return nil, err
+ }
+ case OnSchemaAccountRoleGrantKind:
+ data := id.Data.(*OnSchemaGrantData)
+ onSchema := make(map[string]any)
+
+ switch data.Kind {
+ case OnSchemaSchemaGrantKind:
+ onSchema["schema_name"] = data.SchemaName.FullyQualifiedName()
+ case OnAllSchemasInDatabaseSchemaGrantKind:
+ onSchema["all_schemas_in_database"] = data.DatabaseName.FullyQualifiedName()
+ case OnFutureSchemasInDatabaseSchemaGrantKind:
+ onSchema["future_schemas_in_database"] = data.DatabaseName.FullyQualifiedName()
+ }
+
+ if err := d.Set("on_schema", []any{onSchema}); err != nil {
+ return nil, err
+ }
+ case OnSchemaObjectAccountRoleGrantKind:
+ data := id.Data.(*OnSchemaObjectGrantData)
+ onSchemaObject := make(map[string]any)
+
+ switch data.Kind {
+ case OnObjectSchemaObjectGrantKind:
+ onSchemaObject["object_type"] = data.Object.ObjectType.String()
+ onSchemaObject["object_name"] = data.Object.Name.FullyQualifiedName()
+ case OnAllSchemaObjectGrantKind:
+ onAll := make(map[string]any)
+
+ onAll["object_type_plural"] = data.OnAllOrFuture.ObjectNamePlural.String()
+ switch data.OnAllOrFuture.Kind {
+ case InDatabaseBulkOperationGrantKind:
+ onAll["in_database"] = data.OnAllOrFuture.Database.FullyQualifiedName()
+ case InSchemaBulkOperationGrantKind:
+ onAll["in_schema"] = data.OnAllOrFuture.Schema.FullyQualifiedName()
+ }
+
+ onSchemaObject["all"] = []any{onAll}
+ case OnFutureSchemaObjectGrantKind:
+ onFuture := make(map[string]any)
+
+ onFuture["object_type_plural"] = data.OnAllOrFuture.ObjectNamePlural.String()
+ switch data.OnAllOrFuture.Kind {
+ case InDatabaseBulkOperationGrantKind:
+ onFuture["in_database"] = data.OnAllOrFuture.Database.FullyQualifiedName()
+ case InSchemaBulkOperationGrantKind:
+ onFuture["in_schema"] = data.OnAllOrFuture.Schema.FullyQualifiedName()
+ }
+
+ onSchemaObject["future"] = []any{onFuture}
+ }
+
+ if err := d.Set("on_schema_object", []any{onSchemaObject}); err != nil {
+ return nil, err
+ }
+ }
+
+ return []*schema.ResourceData{d}, nil
+ }
+}
+
+func CreateGrantPrivilegesToAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
+ logging.DebugLogger.Printf("[DEBUG] Entering create grant privileges to account role")
+ db := meta.(*sql.DB)
+
+ logging.DebugLogger.Printf("[DEBUG] Creating new client from db")
+ client := sdk.NewClientFromDB(db)
+
+ id := createGrantPrivilegesToAccountRoleIdFromSchema(d)
+ logging.DebugLogger.Printf("[DEBUG] created identifier from schema: %s", id.String())
+
+ err := client.Grants.GrantPrivilegesToAccountRole(
+ ctx,
+ getAccountRolePrivilegesFromSchema(d),
+ getAccountRoleGrantOn(d),
+ sdk.NewAccountObjectIdentifierFromFullyQualifiedName(d.Get("account_role_name").(string)),
+ &sdk.GrantPrivilegesToAccountRoleOptions{
+ WithGrantOption: sdk.Bool(d.Get("with_grant_option").(bool)),
+ },
+ )
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "An error occurred when granting privileges to account role",
+ Detail: fmt.Sprintf("Id: %s\nDatabase role name: %s\nError: %s", id.String(), id.RoleName, err.Error()),
+ },
+ }
+ }
+
+ logging.DebugLogger.Printf("[DEBUG] Setting identifier to %s", id.String())
+ d.SetId(id.String())
+
+ return ReadGrantPrivilegesToAccountRole(ctx, d, meta)
+}
+
+func UpdateGrantPrivilegesToAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
+ logging.DebugLogger.Printf("[DEBUG] Entering update grant privileges to account role")
+ db := meta.(*sql.DB)
+
+ logging.DebugLogger.Printf("[DEBUG] Creating new client from db")
+ client := sdk.NewClientFromDB(db)
+
+ id, err := ParseGrantPrivilegesToAccountRoleId(d.Id())
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to parse internal identifier",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+ logging.DebugLogger.Printf("[DEBUG] Parsed identifier to %s", id.String())
+
+ // handle all_privileges -> privileges change (revoke all privileges)
+ if d.HasChange("all_privileges") {
+ _, allPrivileges := d.GetChange("all_privileges")
+
+ if !allPrivileges.(bool) {
+ logging.DebugLogger.Printf("[DEBUG] Revoking all privileges")
+ err = client.Grants.RevokePrivilegesFromAccountRole(ctx, &sdk.AccountRoleGrantPrivileges{
+ AllPrivileges: sdk.Bool(true),
+ },
+ getAccountRoleGrantOn(d),
+ id.RoleName,
+ new(sdk.RevokePrivilegesFromAccountRoleOptions),
+ )
+
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to revoke all privileges",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+ }
+
+ id.AllPrivileges = allPrivileges.(bool)
+ }
+
+ if d.HasChange("privileges") {
+ shouldHandlePrivilegesChange := true
+
+ // Skip if all_privileges was set to true
+ if d.HasChange("all_privileges") {
+ if _, allPrivileges := d.GetChange("all_privileges"); allPrivileges.(bool) {
+ shouldHandlePrivilegesChange = false
+ id.Privileges = []string{}
+ }
+ }
+
+ if shouldHandlePrivilegesChange {
+ before, after := d.GetChange("privileges")
+ privilegesBeforeChange := expandStringList(before.(*schema.Set).List())
+ privilegesAfterChange := expandStringList(after.(*schema.Set).List())
+
+ logging.DebugLogger.Printf("[DEBUG] Changes in privileges. Before: %v, after: %v", privilegesBeforeChange, privilegesAfterChange)
+
+ var privilegesToAdd, privilegesToRemove []string
+
+ for _, privilegeBeforeChange := range privilegesBeforeChange {
+ if !slices.Contains(privilegesAfterChange, privilegeBeforeChange) {
+ privilegesToRemove = append(privilegesToRemove, privilegeBeforeChange)
+ }
+ }
+
+ for _, privilegeAfterChange := range privilegesAfterChange {
+ if !slices.Contains(privilegesBeforeChange, privilegeAfterChange) {
+ privilegesToAdd = append(privilegesToAdd, privilegeAfterChange)
+ }
+ }
+
+ grantOn := getAccountRoleGrantOn(d)
+
+ if len(privilegesToAdd) > 0 {
+ logging.DebugLogger.Printf("[DEBUG] Granting privileges: %v", privilegesToAdd)
+ err = client.Grants.GrantPrivilegesToAccountRole(
+ ctx,
+ getAccountRolePrivileges(
+ false,
+ privilegesToAdd,
+ id.Kind == OnAccountAccountRoleGrantKind,
+ id.Kind == OnAccountObjectAccountRoleGrantKind,
+ id.Kind == OnSchemaAccountRoleGrantKind,
+ id.Kind == OnSchemaObjectAccountRoleGrantKind,
+ ),
+ grantOn,
+ id.RoleName,
+ new(sdk.GrantPrivilegesToAccountRoleOptions),
+ )
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to grant added privileges",
+ Detail: fmt.Sprintf("Id: %s\nPrivileges to add: %v\nError: %s", d.Id(), privilegesToAdd, err.Error()),
+ },
+ }
+ }
+ }
+
+ if len(privilegesToRemove) > 0 {
+ logging.DebugLogger.Printf("[DEBUG] Revoking privileges: %v", privilegesToRemove)
+ err = client.Grants.RevokePrivilegesFromAccountRole(
+ ctx,
+ getAccountRolePrivileges(
+ false,
+ privilegesToRemove,
+ id.Kind == OnAccountAccountRoleGrantKind,
+ id.Kind == OnAccountObjectAccountRoleGrantKind,
+ id.Kind == OnSchemaAccountRoleGrantKind,
+ id.Kind == OnSchemaObjectAccountRoleGrantKind,
+ ),
+ grantOn,
+ id.RoleName,
+ new(sdk.RevokePrivilegesFromAccountRoleOptions),
+ )
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to revoke removed privileges",
+ Detail: fmt.Sprintf("Id: %s\nPrivileges to remove: %v\nError: %s", d.Id(), privilegesToRemove, err.Error()),
+ },
+ }
+ }
+ }
+
+ id.Privileges = privilegesAfterChange
+ }
+ }
+
+ // handle privileges -> all_privileges change (grant all privileges)
+ if d.HasChange("all_privileges") {
+ _, allPrivileges := d.GetChange("all_privileges")
+
+ if allPrivileges.(bool) {
+ logging.DebugLogger.Printf("[DEBUG] Granting all privileges")
+ err = client.Grants.GrantPrivilegesToAccountRole(ctx, &sdk.AccountRoleGrantPrivileges{
+ AllPrivileges: sdk.Bool(true),
+ },
+ getAccountRoleGrantOn(d),
+ id.RoleName,
+ new(sdk.GrantPrivilegesToAccountRoleOptions),
+ )
+
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to grant all privileges",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+ }
+
+ id.AllPrivileges = allPrivileges.(bool)
+ }
+
+ if d.HasChange("always_apply") {
+ id.AlwaysApply = d.Get("always_apply").(bool)
+ }
+
+ if id.AlwaysApply {
+ logging.DebugLogger.Printf("[DEBUG] Performing always_apply re-grant")
+ err := client.Grants.GrantPrivilegesToAccountRole(
+ ctx,
+ getAccountRolePrivilegesFromSchema(d),
+ getAccountRoleGrantOn(d),
+ id.RoleName,
+ &sdk.GrantPrivilegesToAccountRoleOptions{
+ WithGrantOption: &id.WithGrantOption,
+ },
+ )
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Always apply. An error occurred when granting privileges to account role",
+ Detail: fmt.Sprintf("Id: %s\nAccount role name: %s\nError: %s", d.Id(), id.RoleName, err.Error()),
+ },
+ }
+ }
+ }
+
+ logging.DebugLogger.Printf("[DEBUG] Setting identifier to %s", id.String())
+ d.SetId(id.String())
+
+ return ReadGrantPrivilegesToAccountRole(ctx, d, meta)
+}
+
+func DeleteGrantPrivilegesToAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
+ logging.DebugLogger.Printf("[DEBUG] Entering delete grant privileges to account role")
+ db := meta.(*sql.DB)
+
+ logging.DebugLogger.Printf("[DEBUG] Creating new client from db")
+ client := sdk.NewClientFromDB(db)
+
+ id, err := ParseGrantPrivilegesToAccountRoleId(d.Id())
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to parse internal identifier",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+ logging.DebugLogger.Printf("[DEBUG] Parsed identifier: %s", id.String())
+
+ err = client.Grants.RevokePrivilegesFromAccountRole(
+ ctx,
+ getAccountRolePrivilegesFromSchema(d),
+ getAccountRoleGrantOn(d),
+ id.RoleName,
+ &sdk.RevokePrivilegesFromAccountRoleOptions{},
+ )
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "An error occurred when revoking privileges from account role",
+ Detail: fmt.Sprintf("Id: %s\nAccount role name: %s\nError: %s", d.Id(), id.RoleName, err.Error()),
+ },
+ }
+ }
+
+ d.SetId("")
+
+ return nil
+}
+
+func ReadGrantPrivilegesToAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
+ logging.DebugLogger.Printf("[DEBUG] Entering read grant privileges to role")
+ id, err := ParseGrantPrivilegesToAccountRoleId(d.Id())
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to parse internal identifier",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+ logging.DebugLogger.Printf("[DEBUG] Parsed identifier: %s", id.String())
+
+ if id.AlwaysApply {
+ // The Trigger is a string rather than boolean that would be flipped on every terraform apply
+ // because it's easier to think about and not to worry about edge cases that may occur with 1bit values.
+ // The only place to have the "flip" is Read operation, because there we can set value and produce a plan
+ // that later on will be executed in the Update operation.
+ //
+ // The following example shows that we can end up with the same value as before, which may lead to empty plans:
+ // 1. Create configuration with always_apply = false (let's say trigger will be false by default)
+ // 2. terraform apply: Create (Read will update it to false)
+ // 3. Update config so that always_apply = true
+ // 4. terraform apply: Read (updated trigger to false) -> change is not detected (no plan; no Update)
+ triggerId, err := uuid.GenerateUUID()
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to generate UUID",
+ Detail: fmt.Sprintf("Original error: %s", err.Error()),
+ },
+ }
+ }
+
+ // Change the value of always_apply_trigger to produce a plan
+ if err := d.Set("always_apply_trigger", triggerId); err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Error setting always_apply_trigger for database role",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+ }
+
+ if id.AllPrivileges {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Warning,
+ Summary: "Show with all_privileges option is skipped.",
+ // TODO: link to the design decisions doc (SNOW-990811)
+ Detail: "See our document on design decisions for grants: ",
+ },
+ }
+ }
+
+ opts, grantedOn, diags := prepareShowGrantsRequestForAccountRole(id)
+ if len(diags) != 0 {
+ return diags
+ }
+
+ db := meta.(*sql.DB)
+ logging.DebugLogger.Printf("[DEBUG] Creating new client from db")
+ client := sdk.NewClientFromDB(db)
+
+ logging.DebugLogger.Printf("[DEBUG] About to show grants")
+ grants, err := client.Grants.Show(ctx, opts)
+ if err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to retrieve grants",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
+ }
+
+ var privileges []string
+
+ logging.DebugLogger.Printf("[DEBUG] Filtering grants to be set on account: count = %d", len(grants))
+ for _, grant := range grants {
+ // Accept only (account) ROLEs
+ if grant.GrantTo != sdk.ObjectTypeRole && grant.GrantedTo != sdk.ObjectTypeRole {
+ continue
+ }
+ // Only consider privileges that are already present in the ID, so we
+ // don't delete privileges managed by other resources.
+ if !slices.Contains(id.Privileges, grant.Privilege) {
+ continue
+ }
+ if grant.GrantOption == id.WithGrantOption && grant.GranteeName.Name() == id.RoleName.Name() {
+ // Future grants do not have grantedBy, only current grants do.
+ // If grantedby is an empty string, it means terraform could not have created the grant
+ if (opts.Future == nil || !*opts.Future) && grant.GrantedBy.Name() == "" {
+ continue
+ }
+ // grant_on is for future grants, granted_on is for current grants.
+ // They function the same way though in a test for matching the object type
+ if grantedOn == grant.GrantedOn || grantedOn == grant.GrantOn {
+ privileges = append(privileges, grant.Privilege)
+ }
+ }
+ }
+
+ logging.DebugLogger.Printf("[DEBUG] Setting privileges: %v", privileges)
+ if err := d.Set("privileges", privileges); err != nil {
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Error setting privileges for account role",
+ Detail: fmt.Sprintf("Id: %s\nPrivileges: %v\nError: %s", d.Id(), privileges, err.Error()),
+ },
+ }
+ }
+
+ return nil
+}
+
+func prepareShowGrantsRequestForAccountRole(id GrantPrivilegesToAccountRoleId) (*sdk.ShowGrantOptions, sdk.ObjectType, diag.Diagnostics) {
+ opts := new(sdk.ShowGrantOptions)
+ var grantedOn sdk.ObjectType
+
+ switch id.Kind {
+ case OnAccountAccountRoleGrantKind:
+ grantedOn = sdk.ObjectTypeAccount
+ opts.On = &sdk.ShowGrantsOn{
+ Account: sdk.Bool(true),
+ }
+ case OnAccountObjectAccountRoleGrantKind:
+ data := id.Data.(*OnAccountObjectGrantData)
+ grantedOn = data.ObjectType
+ opts.On = &sdk.ShowGrantsOn{
+ Object: &sdk.Object{
+ ObjectType: data.ObjectType,
+ Name: data.ObjectName,
+ },
+ }
+ case OnSchemaAccountRoleGrantKind:
+ grantedOn = sdk.ObjectTypeSchema
+ data := id.Data.(*OnSchemaGrantData)
+
+ switch data.Kind {
+ case OnSchemaSchemaGrantKind:
+ opts.On = &sdk.ShowGrantsOn{
+ Object: &sdk.Object{
+ ObjectType: sdk.ObjectTypeSchema,
+ Name: data.SchemaName,
+ },
+ }
+ case OnAllSchemasInDatabaseSchemaGrantKind:
+ return nil, "", diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Warning,
+ Summary: "Show with OnAllSchemasInDatabase option is skipped.",
+ // TODO: link to the design decisions doc (SNOW-990811)
+ Detail: "See our document on design decisions for grants: ",
+ },
+ }
+ case OnFutureSchemasInDatabaseSchemaGrantKind:
+ opts.Future = sdk.Bool(true)
+ opts.In = &sdk.ShowGrantsIn{
+ Database: data.DatabaseName,
+ }
+ }
+ case OnSchemaObjectAccountRoleGrantKind:
+ data := id.Data.(*OnSchemaObjectGrantData)
+
+ switch data.Kind {
+ case OnObjectSchemaObjectGrantKind:
+ grantedOn = data.Object.ObjectType
+ opts.On = &sdk.ShowGrantsOn{
+ Object: data.Object,
+ }
+ case OnAllSchemaObjectGrantKind:
+ return nil, "", diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Warning,
+ Summary: "Show with OnAll option is skipped.",
+ // TODO: link to the design decisions doc (SNOW-990811)
+ Detail: "See our document on design decisions for grants: ",
+ },
+ }
+ case OnFutureSchemaObjectGrantKind:
+ grantedOn = data.OnAllOrFuture.ObjectNamePlural.Singular()
+ opts.Future = sdk.Bool(true)
+
+ switch data.OnAllOrFuture.Kind {
+ case InDatabaseBulkOperationGrantKind:
+ opts.In = &sdk.ShowGrantsIn{
+ Database: data.OnAllOrFuture.Database,
+ }
+ case InSchemaBulkOperationGrantKind:
+ opts.In = &sdk.ShowGrantsIn{
+ Schema: data.OnAllOrFuture.Schema,
+ }
+ }
+ }
+ }
+
+ return opts, grantedOn, nil
+}
+
+func getAccountRolePrivilegesFromSchema(d *schema.ResourceData) *sdk.AccountRoleGrantPrivileges {
+ _, onAccountOk := d.GetOk("on_account")
+ _, onAccountObjectOk := d.GetOk("on_account_object")
+ _, onSchemaOk := d.GetOk("on_schema")
+ _, onSchemaObjectOk := d.GetOk("on_schema_object")
+
+ return getAccountRolePrivileges(
+ d.Get("all_privileges").(bool),
+ expandStringList(d.Get("privileges").(*schema.Set).List()),
+ onAccountOk,
+ onAccountObjectOk,
+ onSchemaOk,
+ onSchemaObjectOk,
+ )
+}
+
+func getAccountRolePrivileges(allPrivileges bool, privileges []string, onAccount bool, onAccountObject bool, onSchema bool, onSchemaObject bool) *sdk.AccountRoleGrantPrivileges {
+ accountRoleGrantPrivileges := new(sdk.AccountRoleGrantPrivileges)
+
+ if allPrivileges {
+ accountRoleGrantPrivileges.AllPrivileges = sdk.Bool(true)
+ return accountRoleGrantPrivileges
+ }
+
+ switch {
+ case onAccount:
+ globalPrivileges := make([]sdk.GlobalPrivilege, len(privileges))
+ for i, privilege := range privileges {
+ globalPrivileges[i] = sdk.GlobalPrivilege(privilege)
+ }
+ accountRoleGrantPrivileges.GlobalPrivileges = globalPrivileges
+ case onAccountObject:
+ accountObjectPrivileges := make([]sdk.AccountObjectPrivilege, len(privileges))
+ for i, privilege := range privileges {
+ accountObjectPrivileges[i] = sdk.AccountObjectPrivilege(privilege)
+ }
+ accountRoleGrantPrivileges.AccountObjectPrivileges = accountObjectPrivileges
+ case onSchema:
+ schemaPrivileges := make([]sdk.SchemaPrivilege, len(privileges))
+ for i, privilege := range privileges {
+ schemaPrivileges[i] = sdk.SchemaPrivilege(privilege)
+ }
+ accountRoleGrantPrivileges.SchemaPrivileges = schemaPrivileges
+ case onSchemaObject:
+ schemaObjectPrivileges := make([]sdk.SchemaObjectPrivilege, len(privileges))
+ for i, privilege := range privileges {
+ schemaObjectPrivileges[i] = sdk.SchemaObjectPrivilege(privilege)
+ }
+ accountRoleGrantPrivileges.SchemaObjectPrivileges = schemaObjectPrivileges
+ }
+
+ return accountRoleGrantPrivileges
+}
+
+func getAccountRoleGrantOn(d *schema.ResourceData) *sdk.AccountRoleGrantOn {
+ _, onAccountOk := d.GetOk("on_account")
+ onAccountObjectBlock, onAccountObjectOk := d.GetOk("on_account_object")
+ onSchemaBlock, onSchemaOk := d.GetOk("on_schema")
+ onSchemaObjectBlock, onSchemaObjectOk := d.GetOk("on_schema_object")
+ on := new(sdk.AccountRoleGrantOn)
+
+ switch {
+ case onAccountOk:
+ on.Account = sdk.Bool(true)
+ case onAccountObjectOk:
+ onAccountObject := onAccountObjectBlock.([]any)[0].(map[string]any)
+
+ grantOnAccountObject := new(sdk.GrantOnAccountObject)
+
+ objectType := onAccountObject["object_type"].(string)
+ objectName := onAccountObject["object_name"].(string)
+ objectIdentifier := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(objectName)
+
+ switch sdk.ObjectType(objectType) {
+ case sdk.ObjectTypeDatabase:
+ grantOnAccountObject.Database = &objectIdentifier
+ case sdk.ObjectTypeFailoverGroup:
+ grantOnAccountObject.FailoverGroup = &objectIdentifier
+ case sdk.ObjectTypeIntegration:
+ grantOnAccountObject.Integration = &objectIdentifier
+ case sdk.ObjectTypeReplicationGroup:
+ grantOnAccountObject.ReplicationGroup = &objectIdentifier
+ case sdk.ObjectTypeResourceMonitor:
+ grantOnAccountObject.ResourceMonitor = &objectIdentifier
+ case sdk.ObjectTypeUser:
+ grantOnAccountObject.User = &objectIdentifier
+ case sdk.ObjectTypeWarehouse:
+ grantOnAccountObject.Warehouse = &objectIdentifier
+ case sdk.ObjectTypeComputePool:
+ grantOnAccountObject.ComputePool = &objectIdentifier
+ case sdk.ObjectTypeExternalVolume:
+ grantOnAccountObject.ExternalVolume = &objectIdentifier
+ }
+
+ on.AccountObject = grantOnAccountObject
+ case onSchemaOk:
+ onSchema := onSchemaBlock.([]any)[0].(map[string]any)
+
+ grantOnSchema := new(sdk.GrantOnSchema)
+
+ schemaName := onSchema["schema_name"].(string)
+ schemaNameOk := len(schemaName) > 0
+
+ allSchemasInDatabase := onSchema["all_schemas_in_database"].(string)
+ allSchemasInDatabaseOk := len(allSchemasInDatabase) > 0
+
+ futureSchemasInDatabase := onSchema["future_schemas_in_database"].(string)
+ futureSchemasInDatabaseOk := len(futureSchemasInDatabase) > 0
+
+ switch {
+ case schemaNameOk:
+ grantOnSchema.Schema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(schemaName))
+ case allSchemasInDatabaseOk:
+ grantOnSchema.AllSchemasInDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(allSchemasInDatabase))
+ case futureSchemasInDatabaseOk:
+ grantOnSchema.FutureSchemasInDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(futureSchemasInDatabase))
+ }
+
+ on.Schema = grantOnSchema
+ case onSchemaObjectOk:
+ onSchemaObject := onSchemaObjectBlock.([]any)[0].(map[string]any)
+
+ grantOnSchemaObject := new(sdk.GrantOnSchemaObject)
+
+ objectType := onSchemaObject["object_type"].(string)
+ objectTypeOk := len(objectType) > 0
+
+ objectName := onSchemaObject["object_name"].(string)
+ objectNameOk := len(objectName) > 0
+
+ all := onSchemaObject["all"].([]any)
+ allOk := len(all) > 0
+
+ future := onSchemaObject["future"].([]any)
+ futureOk := len(future) > 0
+
+ switch {
+ case objectTypeOk && objectNameOk:
+ grantOnSchemaObject.SchemaObject = &sdk.Object{
+ ObjectType: sdk.ObjectType(objectType),
+ Name: sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(objectName),
+ }
+ case allOk:
+ grantOnSchemaObject.All = getGrantOnSchemaObjectIn(all[0].(map[string]any))
+ case futureOk:
+ grantOnSchemaObject.Future = getGrantOnSchemaObjectIn(future[0].(map[string]any))
+ }
+
+ on.SchemaObject = grantOnSchemaObject
+ }
+
+ return on
+}
+
+func createGrantPrivilegesToAccountRoleIdFromSchema(d *schema.ResourceData) *GrantPrivilegesToAccountRoleId {
+ id := new(GrantPrivilegesToAccountRoleId)
+ id.RoleName = sdk.NewAccountObjectIdentifierFromFullyQualifiedName(d.Get("account_role_name").(string))
+ id.AllPrivileges = d.Get("all_privileges").(bool)
+ if p, ok := d.GetOk("privileges"); ok {
+ id.Privileges = expandStringList(p.(*schema.Set).List())
+ }
+ id.WithGrantOption = d.Get("with_grant_option").(bool)
+
+ on := getAccountRoleGrantOn(d)
+ switch {
+ case on.Account != nil:
+ id.Kind = OnAccountAccountRoleGrantKind
+ id.Data = new(OnAccountGrantData)
+ case on.AccountObject != nil:
+ onAccountObjectGrantData := new(OnAccountObjectGrantData)
+
+ switch {
+ case on.AccountObject.User != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeUser
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.User
+ case on.AccountObject.ResourceMonitor != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeResourceMonitor
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.ResourceMonitor
+ case on.AccountObject.Warehouse != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeWarehouse
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.Warehouse
+ case on.AccountObject.Database != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeDatabase
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.Database
+ case on.AccountObject.Integration != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeIntegration
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.Integration
+ case on.AccountObject.FailoverGroup != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeFailoverGroup
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.FailoverGroup
+ case on.AccountObject.ReplicationGroup != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeReplicationGroup
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.ReplicationGroup
+ case on.AccountObject.ExternalVolume != nil:
+ onAccountObjectGrantData.ObjectType = sdk.ObjectTypeExternalVolume
+ onAccountObjectGrantData.ObjectName = *on.AccountObject.ExternalVolume
+ }
+
+ id.Kind = OnAccountObjectAccountRoleGrantKind
+ id.Data = onAccountObjectGrantData
+ case on.Schema != nil:
+ onSchemaGrantData := new(OnSchemaGrantData)
+
+ switch {
+ case on.Schema.Schema != nil:
+ onSchemaGrantData.Kind = OnSchemaSchemaGrantKind
+ onSchemaGrantData.SchemaName = on.Schema.Schema
+ case on.Schema.AllSchemasInDatabase != nil:
+ onSchemaGrantData.Kind = OnAllSchemasInDatabaseSchemaGrantKind
+ onSchemaGrantData.DatabaseName = on.Schema.AllSchemasInDatabase
+ case on.Schema.FutureSchemasInDatabase != nil:
+ onSchemaGrantData.Kind = OnFutureSchemasInDatabaseSchemaGrantKind
+ onSchemaGrantData.DatabaseName = on.Schema.FutureSchemasInDatabase
+ }
+
+ id.Kind = OnSchemaAccountRoleGrantKind
+ id.Data = onSchemaGrantData
+ case on.SchemaObject != nil:
+ onSchemaObjectGrantData := new(OnSchemaObjectGrantData)
+
+ switch {
+ case on.SchemaObject.SchemaObject != nil:
+ onSchemaObjectGrantData.Kind = OnObjectSchemaObjectGrantKind
+ onSchemaObjectGrantData.Object = on.SchemaObject.SchemaObject
+ case on.SchemaObject.All != nil:
+ onSchemaObjectGrantData.Kind = OnAllSchemaObjectGrantKind
+ onSchemaObjectGrantData.OnAllOrFuture = getBulkOperationGrantData(on.SchemaObject.All)
+ case on.SchemaObject.Future != nil:
+ onSchemaObjectGrantData.Kind = OnFutureSchemaObjectGrantKind
+ onSchemaObjectGrantData.OnAllOrFuture = getBulkOperationGrantData(on.SchemaObject.Future)
+ }
+
+ id.Kind = OnSchemaObjectAccountRoleGrantKind
+ id.Data = onSchemaObjectGrantData
+ }
+
+ return id
+}
diff --git a/pkg/resources/grant_privileges_to_account_role_acceptance_test.go b/pkg/resources/grant_privileges_to_account_role_acceptance_test.go
new file mode 100644
index 0000000000..c2a89f1cf8
--- /dev/null
+++ b/pkg/resources/grant_privileges_to_account_role_acceptance_test.go
@@ -0,0 +1,894 @@
+package resources_test
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "log"
+ "regexp"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+
+ acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+ "github.com/hashicorp/terraform-plugin-testing/config"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/plancheck"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+ "github.com/hashicorp/terraform-plugin-testing/tfversion"
+)
+
+func TestAcc_GrantPrivilegesToAccountRole_OnAccount(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.GlobalPrivilegeCreateDatabase)),
+ config.StringVariable(string(sdk.GlobalPrivilegeCreateRole)),
+ ),
+ "with_grant_option": config.BoolVariable(true),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccount"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.GlobalPrivilegeCreateDatabase)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.GlobalPrivilegeCreateRole)),
+ resource.TestCheckResourceAttr(resourceName, "on_account", "true"),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "true"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE DATABASE,CREATE ROLE|OnAccount", roleName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccount"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnAccount_PrivilegesReversed(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.GlobalPrivilegeCreateRole)),
+ config.StringVariable(string(sdk.GlobalPrivilegeCreateDatabase)),
+ ),
+ "with_grant_option": config.BoolVariable(true),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccount"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.GlobalPrivilegeCreateDatabase)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.GlobalPrivilegeCreateRole)),
+ resource.TestCheckResourceAttr(resourceName, "on_account", "true"),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "true"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE DATABASE,CREATE ROLE|OnAccount", roleName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccount"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnAccountObject(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "database": config.StringVariable(databaseName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.AccountObjectPrivilegeCreateDatabaseRole)),
+ config.StringVariable(string(sdk.AccountObjectPrivilegeCreateSchema)),
+ ),
+ "with_grant_option": config.BoolVariable(true),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccountObject"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeCreateDatabaseRole)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeCreateSchema)),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "true"),
+ resource.TestCheckResourceAttr(resourceName, "on_account_object.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_account_object.0.object_type", "DATABASE"),
+ resource.TestCheckResourceAttr(resourceName, "on_account_object.0.object_name", databaseName),
+ // TODO (SNOW-999049): Even if the identifier is passed as a non-escaped value it will be escaped in the identifier and later on in the CRUD operations (right now, it's "only" read, which can cause behavior similar to always_apply)
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE DATABASE ROLE,CREATE SCHEMA|OnAccountObject|DATABASE|\"%s\"", roleName, acc.TestDatabaseName)),
+ ),
+ },
+ {
+ // TODO (SNOW-999049): this fails, because after import object_name identifier is escaped (was unescaped)
+ // Make grant_privileges_to_account_role and grant_privileges_to_account_role identifiers accept
+ // quoted and unquoted identifiers.
+ // ConfigPlanChecks: resource.ConfigPlanChecks{
+ // PostApplyPostRefresh: []plancheck.PlanCheck{
+ // plancheck.ExpectEmptyPlan(),
+ // },
+ // },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccountObject"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+// This proves that infinite plan is not produced as in snowflake_grant_privileges_to_role.
+// More details can be found in the fix pr https://github.com/Snowflake-Labs/terraform-provider-snowflake/pull/2364.
+func TestAcc_GrantPrivilegesToApplicationRole_OnAccountObject_InfinitePlan(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan"),
+ ConfigVariables: config.Variables{
+ "name": config.StringVariable(name),
+ "database": config.StringVariable(acc.TestDatabaseName),
+ },
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PostApplyPostRefresh: []plancheck.PlanCheck{
+ plancheck.ExpectEmptyPlan(),
+ },
+ },
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnSchema(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaPrivilegeCreateTable)),
+ config.StringVariable(string(sdk.SchemaPrivilegeModify)),
+ ),
+ "database": config.StringVariable(acc.TestDatabaseName),
+ "schema": config.StringVariable(acc.TestSchemaName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ schemaName := sdk.NewDatabaseObjectIdentifier(acc.TestDatabaseName, acc.TestSchemaName).FullyQualifiedName()
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchema"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaPrivilegeCreateTable)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.SchemaPrivilegeModify)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema.0.schema_name", schemaName),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE TABLE,MODIFY|OnSchema|OnSchema|%s", roleName, schemaName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchema"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnSchema_ExactlyOneOf(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchema_ExactlyOneOf"),
+ PlanOnly: true,
+ ExpectError: regexp.MustCompile("Error: Invalid combination of arguments"),
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnAllSchemasInDatabase(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaPrivilegeCreateTable)),
+ config.StringVariable(string(sdk.SchemaPrivilegeModify)),
+ ),
+ "database": config.StringVariable(databaseName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaPrivilegeCreateTable)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.SchemaPrivilegeModify)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema.0.all_schemas_in_database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE TABLE,MODIFY|OnSchema|OnAllSchemasInDatabase|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnFutureSchemasInDatabase(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaPrivilegeCreateTable)),
+ config.StringVariable(string(sdk.SchemaPrivilegeModify)),
+ ),
+ "database": config.StringVariable(databaseName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaPrivilegeCreateTable)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.SchemaPrivilegeModify)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema.0.future_schemas_in_database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE TABLE,MODIFY|OnSchema|OnFutureSchemasInDatabase|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnSchemaObject_OnObject(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ tblName := "test_database_role_table_name"
+ tableName := sdk.NewSchemaObjectIdentifier(acc.TestDatabaseName, acc.TestSchemaName, tblName).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "table_name": config.StringVariable(tblName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaObjectPrivilegeInsert)),
+ config.StringVariable(string(sdk.SchemaObjectPrivilegeUpdate)),
+ ),
+ "database": config.StringVariable(acc.TestDatabaseName),
+ "schema": config.StringVariable(acc.TestSchemaName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaObjectPrivilegeInsert)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.SchemaObjectPrivilegeUpdate)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.object_type", string(sdk.ObjectTypeTable)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.object_name", tableName),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|INSERT,UPDATE|OnSchemaObject|OnObject|TABLE|%s", roleName, tableName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnSchemaObject_OnObject_OwnershipPrivilege(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ tableName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ configVariables := config.Variables{
+ "name": config.StringVariable(name),
+ "table_name": config.StringVariable(tableName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaObjectOwnership)),
+ ),
+ "database": config.StringVariable(acc.TestDatabaseName),
+ "schema": config.StringVariable(acc.TestSchemaName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createDatabaseRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject"),
+ ConfigVariables: configVariables,
+ ExpectError: regexp.MustCompile("Unsupported privilege 'OWNERSHIP'"),
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnSchemaObject_OnAll_InDatabase(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaObjectPrivilegeInsert)),
+ config.StringVariable(string(sdk.SchemaObjectPrivilegeUpdate)),
+ ),
+ "database": config.StringVariable(databaseName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaObjectPrivilegeInsert)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.SchemaObjectPrivilegeUpdate)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.all.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.all.0.object_type_plural", string(sdk.PluralObjectTypeTables)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.all.0.in_database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|INSERT,UPDATE|OnSchemaObject|OnAll|TABLES|InDatabase|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_OnSchemaObject_OnFuture_InDatabase(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "privileges": config.ListVariable(
+ config.StringVariable(string(sdk.SchemaObjectPrivilegeInsert)),
+ config.StringVariable(string(sdk.SchemaObjectPrivilegeUpdate)),
+ ),
+ "database": config.StringVariable(databaseName),
+ "with_grant_option": config.BoolVariable(false),
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase"),
+ ConfigVariables: configVariables,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "account_role_name", roleName),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaObjectPrivilegeInsert)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.SchemaObjectPrivilegeUpdate)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.future.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.future.0.object_type_plural", string(sdk.PluralObjectTypeTables)),
+ resource.TestCheckResourceAttr(resourceName, "on_schema_object.0.future.0.in_database", databaseName),
+ resource.TestCheckResourceAttr(resourceName, "with_grant_option", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|INSERT,UPDATE|OnSchemaObject|OnFuture|TABLES|InDatabase|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase"),
+ ConfigVariables: configVariables,
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_UpdatePrivileges(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := func(allPrivileges bool, privileges []sdk.AccountObjectPrivilege) config.Variables {
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName),
+ "database": config.StringVariable(databaseName),
+ }
+ if allPrivileges {
+ configVariables["all_privileges"] = config.BoolVariable(allPrivileges)
+ }
+ if len(privileges) > 0 {
+ configPrivileges := make([]config.Variable, len(privileges))
+ for i, privilege := range privileges {
+ configPrivileges[i] = config.StringVariable(string(privilege))
+ }
+ configVariables["privileges"] = config.ListVariable(configPrivileges...)
+ }
+ return configVariables
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges"),
+ ConfigVariables: configVariables(false, []sdk.AccountObjectPrivilege{
+ sdk.AccountObjectPrivilegeCreateSchema,
+ sdk.AccountObjectPrivilegeModify,
+ }),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "all_privileges", "false"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeCreateSchema)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeModify)),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE SCHEMA,MODIFY|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges"),
+ ConfigVariables: configVariables(false, []sdk.AccountObjectPrivilege{
+ sdk.AccountObjectPrivilegeCreateSchema,
+ sdk.AccountObjectPrivilegeMonitor,
+ sdk.AccountObjectPrivilegeUsage,
+ }),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "all_privileges", "false"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "3"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeCreateSchema)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeMonitor)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.2", string(sdk.AccountObjectPrivilegeUsage)),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE SCHEMA,USAGE,MONITOR|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges"),
+ ConfigVariables: configVariables(true, []sdk.AccountObjectPrivilege{}),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "all_privileges", "true"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "0"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges"),
+ ConfigVariables: configVariables(false, []sdk.AccountObjectPrivilege{
+ sdk.AccountObjectPrivilegeModify,
+ sdk.AccountObjectPrivilegeMonitor,
+ }),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "all_privileges", "false"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"),
+ resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeModify)),
+ resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeMonitor)),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|MODIFY,MONITOR|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_UpdatePrivileges_SnowflakeChecked(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name)
+ schemaName := "test_database_role_schema_name"
+ configVariables := func(allPrivileges bool, privileges []string, schemaName string) config.Variables {
+ configVariables := config.Variables{
+ "name": config.StringVariable(roleName.FullyQualifiedName()),
+ "database": config.StringVariable(acc.TestDatabaseName),
+ }
+ if allPrivileges {
+ configVariables["all_privileges"] = config.BoolVariable(allPrivileges)
+ }
+ if len(privileges) > 0 {
+ configPrivileges := make([]config.Variable, len(privileges))
+ for i, privilege := range privileges {
+ configPrivileges[i] = config.StringVariable(privilege)
+ }
+ configVariables["privileges"] = config.ListVariable(configPrivileges...)
+ }
+ if len(schemaName) > 0 {
+ configVariables["schema_name"] = config.StringVariable(schemaName)
+ }
+ return configVariables
+ }
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges"),
+ ConfigVariables: configVariables(false, []string{
+ sdk.AccountObjectPrivilegeCreateSchema.String(),
+ sdk.AccountObjectPrivilegeModify.String(),
+ }, ""),
+ Check: queriedAccountRolePrivilegesEqualTo(
+ roleName,
+ sdk.AccountObjectPrivilegeCreateSchema.String(),
+ sdk.AccountObjectPrivilegeModify.String(),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges"),
+ ConfigVariables: configVariables(true, []string{}, ""),
+ Check: queriedAccountRolePrivilegesContainAtLeast(
+ roleName,
+ sdk.AccountObjectPrivilegeCreateDatabaseRole.String(),
+ sdk.AccountObjectPrivilegeCreateSchema.String(),
+ sdk.AccountObjectPrivilegeModify.String(),
+ sdk.AccountObjectPrivilegeMonitor.String(),
+ sdk.AccountObjectPrivilegeUsage.String(),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges"),
+ ConfigVariables: configVariables(false, []string{
+ sdk.AccountObjectPrivilegeModify.String(),
+ sdk.AccountObjectPrivilegeMonitor.String(),
+ }, ""),
+ Check: queriedAccountRolePrivilegesEqualTo(
+ roleName,
+ sdk.AccountObjectPrivilegeModify.String(),
+ sdk.AccountObjectPrivilegeMonitor.String(),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema"),
+ ConfigVariables: configVariables(false, []string{
+ sdk.SchemaPrivilegeCreateTask.String(),
+ sdk.SchemaPrivilegeCreateExternalTable.String(),
+ }, schemaName),
+ Check: queriedAccountRolePrivilegesEqualTo(
+ roleName,
+ sdk.SchemaPrivilegeCreateTask.String(),
+ sdk.SchemaPrivilegeCreateExternalTable.String(),
+ ),
+ },
+ },
+ })
+}
+
+func TestAcc_GrantPrivilegesToAccountRole_AlwaysApply(t *testing.T) {
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
+ roleName := sdk.NewAccountObjectIdentifier(name).FullyQualifiedName()
+ databaseName := sdk.NewAccountObjectIdentifier(acc.TestDatabaseName).FullyQualifiedName()
+ configVariables := func(alwaysApply bool) config.Variables {
+ return config.Variables{
+ "name": config.StringVariable(roleName),
+ "all_privileges": config.BoolVariable(true),
+ "database": config.StringVariable(databaseName),
+ "always_apply": config.BoolVariable(alwaysApply),
+ }
+ }
+ resourceName := "snowflake_grant_privileges_to_account_role.test"
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+ tfversion.RequireAbove(tfversion.Version1_5_0),
+ },
+ CheckDestroy: testAccCheckAccountRolePrivilegesRevoked(name),
+ Steps: []resource.TestStep{
+ {
+ PreConfig: func() { createAccountRoleOutsideTerraform(t, name) },
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/AlwaysApply"),
+ ConfigVariables: configVariables(false),
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PostApplyPostRefresh: []plancheck.PlanCheck{
+ plancheck.ExpectEmptyPlan(),
+ },
+ },
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "always_apply", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/AlwaysApply"),
+ ConfigVariables: configVariables(true),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "always_apply", "true"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ ExpectNonEmptyPlan: true,
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/AlwaysApply"),
+ ConfigVariables: configVariables(true),
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PreApply: []plancheck.PlanCheck{
+ plancheck.ExpectNonEmptyPlan(),
+ },
+ },
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "always_apply", "true"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ ExpectNonEmptyPlan: true,
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/AlwaysApply"),
+ ConfigVariables: configVariables(true),
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PreApply: []plancheck.PlanCheck{
+ plancheck.ExpectNonEmptyPlan(),
+ },
+ },
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "always_apply", "true"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ ExpectNonEmptyPlan: true,
+ },
+ {
+ ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToAccountRole/AlwaysApply"),
+ ConfigVariables: configVariables(false),
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PostApplyPostRefresh: []plancheck.PlanCheck{
+ plancheck.ExpectEmptyPlan(),
+ },
+ },
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "always_apply", "false"),
+ resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnAccountObject|DATABASE|%s", roleName, databaseName)),
+ ),
+ },
+ },
+ })
+}
+
+func createAccountRoleOutsideTerraform(t *testing.T, name string) {
+ t.Helper()
+ client, err := sdk.NewDefaultClient()
+ if err != nil {
+ t.Fatal(err)
+ }
+ ctx := context.Background()
+ roleId := sdk.NewAccountObjectIdentifier(name)
+ if err := client.Roles.Create(ctx, sdk.NewCreateRoleRequest(roleId).WithOrReplace(true)); err != nil {
+ t.Fatal(fmt.Errorf("error account role (%s): %w", roleId.FullyQualifiedName(), err))
+ }
+}
+
+func testAccCheckAccountRolePrivilegesRevoked(name string) func(*terraform.State) error {
+ return func(state *terraform.State) error {
+ db := acc.TestAccProvider.Meta().(*sql.DB)
+ client := sdk.NewClientFromDB(db)
+
+ defer func() {
+ err := client.Roles.Drop(context.Background(), sdk.NewDropRoleRequest(sdk.NewAccountObjectIdentifier(name)))
+ if err != nil {
+ log.Printf("failed to drop account role (%s), err = %s\n", name, err.Error())
+ }
+ }()
+
+ for _, rs := range state.RootModule().Resources {
+ if rs.Type != "snowflake_grant_privileges_to_account_role" {
+ continue
+ }
+ ctx := context.Background()
+
+ id := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(rs.Primary.Attributes["account_role_name"])
+ grants, err := client.Grants.Show(ctx, &sdk.ShowGrantOptions{
+ To: &sdk.ShowGrantsTo{
+ Role: id,
+ },
+ })
+ if err != nil {
+ return err
+ }
+ var grantedPrivileges []string
+ for _, grant := range grants {
+ grantedPrivileges = append(grantedPrivileges, grant.Privilege)
+ }
+ if len(grantedPrivileges) > 0 {
+ return fmt.Errorf("account role (%s) is still granted, granted privileges %v", id.FullyQualifiedName(), grantedPrivileges)
+ }
+ }
+ return nil
+ }
+}
+
+func queriedAccountRolePrivilegesEqualTo(roleName sdk.AccountObjectIdentifier, privileges ...string) func(s *terraform.State) error {
+ return queriedPrivilegesEqualTo(func(client *sdk.Client, ctx context.Context) ([]sdk.Grant, error) {
+ return client.Grants.Show(ctx, &sdk.ShowGrantOptions{
+ To: &sdk.ShowGrantsTo{
+ Role: roleName,
+ },
+ })
+ }, privileges...)
+}
+
+func queriedAccountRolePrivilegesContainAtLeast(roleName sdk.AccountObjectIdentifier, privileges ...string) func(s *terraform.State) error {
+ return queriedPrivilegesContainAtLeast(func(client *sdk.Client, ctx context.Context) ([]sdk.Grant, error) {
+ return client.Grants.Show(ctx, &sdk.ShowGrantOptions{
+ To: &sdk.ShowGrantsTo{
+ Role: roleName,
+ },
+ })
+ }, roleName, privileges...)
+}
diff --git a/pkg/resources/grant_privileges_to_account_role_identifier.go b/pkg/resources/grant_privileges_to_account_role_identifier.go
new file mode 100644
index 0000000000..03f91dee4d
--- /dev/null
+++ b/pkg/resources/grant_privileges_to_account_role_identifier.go
@@ -0,0 +1,175 @@
+package resources
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+)
+
+type AccountRoleGrantKind string
+
+const (
+ OnAccountAccountRoleGrantKind AccountRoleGrantKind = "OnAccount"
+ OnAccountObjectAccountRoleGrantKind AccountRoleGrantKind = "OnAccountObject"
+ OnSchemaAccountRoleGrantKind AccountRoleGrantKind = "OnSchema"
+ OnSchemaObjectAccountRoleGrantKind AccountRoleGrantKind = "OnSchemaObject"
+)
+
+type OnAccountGrantData struct{}
+
+func (d *OnAccountGrantData) String() string {
+ return ""
+}
+
+type OnAccountObjectGrantData struct {
+ ObjectType sdk.ObjectType
+ ObjectName sdk.AccountObjectIdentifier
+}
+
+func (d *OnAccountObjectGrantData) String() string {
+ return strings.Join([]string{
+ d.ObjectType.String(),
+ d.ObjectName.FullyQualifiedName(),
+ }, helpers.IDDelimiter)
+}
+
+type GrantPrivilegesToAccountRoleId struct {
+ RoleName sdk.AccountObjectIdentifier
+ WithGrantOption bool
+ AlwaysApply bool
+ AllPrivileges bool
+ Privileges []string
+ Kind AccountRoleGrantKind
+ Data fmt.Stringer
+}
+
+func (g *GrantPrivilegesToAccountRoleId) String() string {
+ var parts []string
+ parts = append(parts, g.RoleName.FullyQualifiedName())
+ parts = append(parts, strconv.FormatBool(g.WithGrantOption))
+ parts = append(parts, strconv.FormatBool(g.AlwaysApply))
+ if g.AllPrivileges {
+ parts = append(parts, "ALL")
+ } else {
+ parts = append(parts, strings.Join(g.Privileges, ","))
+ }
+ parts = append(parts, string(g.Kind))
+ data := g.Data.String()
+ if len(data) > 0 {
+ parts = append(parts, data)
+ }
+ return strings.Join(parts, helpers.IDDelimiter)
+}
+
+func ParseGrantPrivilegesToAccountRoleId(id string) (GrantPrivilegesToAccountRoleId, error) {
+ var accountRoleId GrantPrivilegesToAccountRoleId
+
+ parts := strings.Split(id, helpers.IDDelimiter)
+ if len(parts) < 5 {
+ return accountRoleId, sdk.NewError(`account role identifier should hold at least 5 parts "||||"`)
+ }
+
+ // TODO: Identifier parsing should be replaced with better version introduced in SNOW-999049.
+ // Right now, it's same as sdk.NewAccountObjectIdentifierFromFullyQualifiedName, but with error handling.
+ name := strings.Trim(parts[0], `"`)
+ if len(name) == 0 {
+ return accountRoleId, sdk.NewError(fmt.Sprintf(`invalid (empty) AccountRoleName value: %s, should be a fully qualified name of account object `, parts[0]))
+ }
+ accountRoleId.RoleName = sdk.NewAccountObjectIdentifier(name)
+
+ if parts[1] != "false" && parts[1] != "true" {
+ return accountRoleId, sdk.NewError(fmt.Sprintf(`invalid WithGrantOption value: %s, should be either "true" or "false"`, parts[1]))
+ }
+ accountRoleId.WithGrantOption = parts[1] == "true"
+
+ if parts[2] != "false" && parts[2] != "true" {
+ return accountRoleId, sdk.NewError(fmt.Sprintf(`invalid AlwaysApply value: %s, should be either "true" or "false"`, parts[2]))
+ }
+ accountRoleId.AlwaysApply = parts[2] == "true"
+
+ privileges := strings.Split(parts[3], ",")
+ if len(privileges) == 0 || (len(privileges) == 1 && privileges[0] == "") {
+ return accountRoleId, sdk.NewError(fmt.Sprintf(`invalid Privileges value: %s, should be either a comma separated list of privileges or "ALL" / "ALL PRIVILEGES" for all privileges`, parts[3]))
+ }
+ if len(privileges) == 1 && (privileges[0] == "ALL" || privileges[0] == "ALL PRIVILEGES") {
+ accountRoleId.AllPrivileges = true
+ } else {
+ accountRoleId.Privileges = privileges
+ }
+
+ accountRoleId.Kind = AccountRoleGrantKind(parts[4])
+ switch accountRoleId.Kind {
+ case OnAccountAccountRoleGrantKind:
+ accountRoleId.Data = new(OnAccountGrantData)
+ case OnAccountObjectAccountRoleGrantKind:
+ if len(parts) != 7 {
+ return accountRoleId, sdk.NewError(`account role identifier should hold at least 7 parts "||||OnAccountObject||"`)
+ }
+ accountRoleId.Data = &OnAccountObjectGrantData{
+ ObjectType: sdk.ObjectType(parts[5]),
+ ObjectName: sdk.NewAccountObjectIdentifierFromFullyQualifiedName(parts[6]),
+ }
+ case OnSchemaAccountRoleGrantKind:
+ if len(parts) < 7 {
+ return accountRoleId, sdk.NewError(`account role identifier should hold at least 7 parts "||||OnSchema||..."`)
+ }
+ onSchemaGrantData := OnSchemaGrantData{
+ Kind: OnSchemaGrantKind(parts[5]),
+ }
+ switch onSchemaGrantData.Kind {
+ case OnSchemaSchemaGrantKind:
+ onSchemaGrantData.SchemaName = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(parts[6]))
+ case OnAllSchemasInDatabaseSchemaGrantKind, OnFutureSchemasInDatabaseSchemaGrantKind:
+ onSchemaGrantData.DatabaseName = sdk.Pointer(sdk.NewAccountObjectIdentifier(parts[6]))
+ default:
+ return accountRoleId, sdk.NewError(fmt.Sprintf("invalid OnSchemaGrantKind: %s", onSchemaGrantData.Kind))
+ }
+ accountRoleId.Data = &onSchemaGrantData
+ case OnSchemaObjectAccountRoleGrantKind:
+ if len(parts) < 7 {
+ return accountRoleId, sdk.NewError(`account role identifier should hold at least 7 parts "||||OnSchemaObject||..."`)
+ }
+ onSchemaObjectGrantData := OnSchemaObjectGrantData{
+ Kind: OnSchemaObjectGrantKind(parts[5]),
+ }
+ switch onSchemaObjectGrantData.Kind {
+ case OnObjectSchemaObjectGrantKind:
+ if len(parts) != 8 {
+ return accountRoleId, sdk.NewError(`account role identifier should hold 8 parts "||||OnSchemaObject|OnObject||"`)
+ }
+ onSchemaObjectGrantData.Object = &sdk.Object{
+ ObjectType: sdk.ObjectType(parts[6]),
+ Name: sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(parts[7]),
+ }
+ case OnAllSchemaObjectGrantKind, OnFutureSchemaObjectGrantKind:
+ bulkOperationGrantData := &BulkOperationGrantData{
+ ObjectNamePlural: sdk.PluralObjectType(parts[6]),
+ }
+ if len(parts) > 7 {
+ if len(parts) != 9 {
+ return accountRoleId, sdk.NewError(`account role identifier should hold 9 parts "||||OnSchemaObject|On[All or Future]||In[Database or Schema]|"`)
+ }
+ bulkOperationGrantData.Kind = BulkOperationGrantKind(parts[7])
+ switch bulkOperationGrantData.Kind {
+ case InDatabaseBulkOperationGrantKind:
+ bulkOperationGrantData.Database = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(parts[8]))
+ case InSchemaBulkOperationGrantKind:
+ bulkOperationGrantData.Schema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(parts[8]))
+ default:
+ return accountRoleId, sdk.NewError(fmt.Sprintf("invalid BulkOperationGrantKind: %s", bulkOperationGrantData.Kind))
+ }
+ }
+ onSchemaObjectGrantData.OnAllOrFuture = bulkOperationGrantData
+ default:
+ return accountRoleId, sdk.NewError(fmt.Sprintf("invalid OnSchemaObjectGrantKind: %s", onSchemaObjectGrantData.Kind))
+ }
+ accountRoleId.Data = &onSchemaObjectGrantData
+ default:
+ return accountRoleId, sdk.NewError(fmt.Sprintf("invalid AccountRoleGrantKind: %s", accountRoleId.Kind))
+ }
+
+ return accountRoleId, nil
+}
diff --git a/pkg/resources/grant_privileges_to_account_role_identifier_test.go b/pkg/resources/grant_privileges_to_account_role_identifier_test.go
new file mode 100644
index 0000000000..41905d4705
--- /dev/null
+++ b/pkg/resources/grant_privileges_to_account_role_identifier_test.go
@@ -0,0 +1,452 @@
+package resources
+
+import (
+ "testing"
+
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParseGrantPrivilegesToAccountRoleId(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Identifier string
+ Expected GrantPrivilegesToAccountRoleId
+ Error string
+ }{
+ {
+ Name: "grant account role on account",
+ Identifier: `"account-role"|false|false|CREATE DATABASE,CREATE USER|OnAccount`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE DATABASE", "CREATE USER"},
+ Kind: OnAccountAccountRoleGrantKind,
+ Data: new(OnAccountGrantData),
+ },
+ },
+ {
+ Name: "grant account role on account - always apply with grant option",
+ Identifier: `"account-role"|true|true|CREATE DATABASE,CREATE USER|OnAccount`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: true,
+ AlwaysApply: true,
+ Privileges: []string{"CREATE DATABASE", "CREATE USER"},
+ Kind: OnAccountAccountRoleGrantKind,
+ Data: new(OnAccountGrantData),
+ },
+ },
+ {
+ Name: "grant account role on account - all privileges",
+ Identifier: `"account-role"|false|false|ALL|OnAccount`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ AllPrivileges: true,
+ Privileges: nil,
+ Kind: OnAccountAccountRoleGrantKind,
+ Data: new(OnAccountGrantData),
+ },
+ },
+ {
+ Name: "grant account role on account object",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnAccountObject|DATABASE|"database-name"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnAccountObjectAccountRoleGrantKind,
+ Data: &OnAccountObjectGrantData{
+ ObjectType: sdk.ObjectTypeDatabase,
+ ObjectName: sdk.NewAccountObjectIdentifier("database-name"),
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema with schema name",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnSchema|"database-name"."schema-name"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaAccountRoleGrantKind,
+ Data: &OnSchemaGrantData{
+ Kind: OnSchemaSchemaGrantKind,
+ SchemaName: sdk.Pointer(sdk.NewDatabaseObjectIdentifier("database-name", "schema-name")),
+ },
+ },
+ },
+ {
+ Name: "grant account role on all schemas in database",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnAllSchemasInDatabase|"database-name-123"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaAccountRoleGrantKind,
+ Data: &OnSchemaGrantData{
+ Kind: OnAllSchemasInDatabaseSchemaGrantKind,
+ DatabaseName: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name-123")),
+ },
+ },
+ },
+ {
+ Name: "grant account role on future schemas in database",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnFutureSchemasInDatabase|"database-name-123"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaAccountRoleGrantKind,
+ Data: &OnSchemaGrantData{
+ Kind: OnFutureSchemasInDatabaseSchemaGrantKind,
+ DatabaseName: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name-123")),
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on object option",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnObject|TABLE|"database-name"."schema-name"."table-name"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnObjectSchemaObjectGrantKind,
+ Object: &sdk.Object{
+ ObjectType: sdk.ObjectTypeTable,
+ Name: sdk.NewSchemaObjectIdentifier("database-name", "schema-name", "table-name"),
+ },
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on all option",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnAll|TABLES`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnAllSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: "TABLES",
+ },
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on all option in database",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnAll|TABLES|InDatabase|"database-name-123"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnAllSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: "TABLES",
+ Kind: InDatabaseBulkOperationGrantKind,
+ Database: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name-123")),
+ },
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on all option in schema",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnAll|TABLES|InSchema|"database-name"."schema-name"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnAllSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: "TABLES",
+ Kind: InSchemaBulkOperationGrantKind,
+ Schema: sdk.Pointer(sdk.NewDatabaseObjectIdentifier("database-name", "schema-name")),
+ },
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on future option",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnFuture|TABLES`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnFutureSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: "TABLES",
+ },
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on all option in database",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnFuture|TABLES|InDatabase|"database-name-123"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnFutureSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: "TABLES",
+ Kind: InDatabaseBulkOperationGrantKind,
+ Database: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name-123")),
+ },
+ },
+ },
+ },
+ {
+ Name: "grant account role on schema object with on all option in schema",
+ Identifier: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnFuture|TABLES|InSchema|"database-name"."schema-name"`,
+ Expected: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnFutureSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: "TABLES",
+ Kind: InSchemaBulkOperationGrantKind,
+ Schema: sdk.Pointer(sdk.NewDatabaseObjectIdentifier("database-name", "schema-name")),
+ },
+ },
+ },
+ },
+ {
+ Name: "validation: grant account role not enough parts",
+ Identifier: `"database-name"."role-name"|false|false`,
+ Error: "account role identifier should hold at least 5 parts",
+ },
+ {
+ Name: "validation: grant account role not enough parts for OnAccountObject kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnAccountObject`,
+ Error: `account role identifier should hold at least 7 parts "||||OnAccountObject||"`,
+ },
+ {
+ Name: "validation: grant account role not enough parts for OnSchema kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnAllSchemasInDatabase`,
+ Error: "account role identifier should hold at least 7 parts",
+ },
+ {
+ Name: "validation: grant account role not enough parts for OnSchemaObject kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnObject`,
+ Error: "account role identifier should hold at least 7 parts",
+ },
+ {
+ Name: "validation: grant account role not enough parts for OnSchemaObject kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnObject|TABLE`,
+ Error: "account role identifier should hold 8 parts",
+ },
+ {
+ Name: "validation: grant account role not enough parts for OnSchemaObject.InDatabase kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnAll|TABLES|InDatabase`,
+ Error: "account role identifier should hold 9 parts",
+ },
+ {
+ Name: "validation: grant account role invalid AccountRoleGrantKind kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|some-kind|some-data`,
+ Error: "invalid AccountRoleGrantKind: some-kind",
+ },
+ {
+ Name: "validation: grant account role invalid OnSchemaGrantKind kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|some-kind|some-data`,
+ Error: "invalid OnSchemaGrantKind: some-kind",
+ },
+ {
+ Name: "validation: grant account role invalid OnSchemaObjectGrantKind kind",
+ Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|some-kind|some-data`,
+ Error: "invalid OnSchemaObjectGrantKind: some-kind",
+ },
+ {
+ Name: "validation: grant account role empty privileges",
+ Identifier: `"account-role"|false|false||OnAccount`,
+ Error: `invalid Privileges value: , should be either a comma separated list of privileges or "ALL" / "ALL PRIVILEGES" for all privileges`,
+ },
+ {
+ Name: "validation: grant account role empty with grant option",
+ Identifier: `"account-role"||false|ALL PRIVILEGES|OnAccount`,
+ Error: `invalid WithGrantOption value: , should be either "true" or "false"`,
+ },
+ {
+ Name: "validation: grant account role empty always apply",
+ Identifier: `"account-role"|false||ALL PRIVILEGES|OnAccount`,
+ Error: `invalid AlwaysApply value: , should be either "true" or "false"`,
+ },
+ {
+ Name: "validation: grant account role empty role name",
+ Identifier: `|false|false|ALL PRIVILEGES|OnAccount`,
+ Error: "invalid (empty) AccountRoleName value: , should be a fully qualified name of account object ",
+ },
+ {
+ Name: "validation: account role empty type",
+ Identifier: `"account-role"|false|false|ALL PRIVILEGES||"on-database-name"`,
+ Error: "invalid AccountRoleGrantKind: ",
+ },
+ }
+
+ for _, tt := range testCases {
+ tt := tt
+ t.Run(tt.Name, func(t *testing.T) {
+ id, err := ParseGrantPrivilegesToAccountRoleId(tt.Identifier)
+ if tt.Error == "" {
+ assert.NoError(t, err)
+ assert.Equal(t, tt.Expected, id)
+ } else {
+ assert.ErrorContains(t, err, tt.Error)
+ }
+ })
+ }
+}
+
+func TestGrantPrivilegesToAccountRoleIdString(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Identifier GrantPrivilegesToAccountRoleId
+ Expected string
+ Error string
+ }{
+ {
+ Name: "grant account role on account",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: true,
+ AllPrivileges: true,
+ Kind: OnAccountAccountRoleGrantKind,
+ AlwaysApply: true,
+ Data: new(OnAccountGrantData),
+ },
+ Expected: `"account-role"|true|true|ALL|OnAccount`,
+ },
+ {
+ Name: "grant account role on account object",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: true,
+ AllPrivileges: true,
+ Kind: OnAccountObjectAccountRoleGrantKind,
+ AlwaysApply: true,
+ Data: &OnAccountObjectGrantData{
+ ObjectType: sdk.ObjectTypeDatabase,
+ ObjectName: sdk.NewAccountObjectIdentifier("database-name"),
+ },
+ },
+ Expected: `"account-role"|true|true|ALL|OnAccountObject|DATABASE|"database-name"`,
+ },
+ {
+ Name: "grant account role on schema on schema",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaAccountRoleGrantKind,
+ Data: &OnSchemaGrantData{
+ Kind: OnSchemaSchemaGrantKind,
+ SchemaName: sdk.Pointer(sdk.NewDatabaseObjectIdentifier("database-name", "schema-name")),
+ },
+ },
+ Expected: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnSchema|"database-name"."schema-name"`,
+ },
+ {
+ Name: "grant account role on all schemas in database",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaAccountRoleGrantKind,
+ Data: &OnSchemaGrantData{
+ Kind: OnAllSchemasInDatabaseSchemaGrantKind,
+ DatabaseName: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name")),
+ },
+ },
+ Expected: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnAllSchemasInDatabase|"database-name"`,
+ },
+ {
+ Name: "grant account role on future schemas in database",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaAccountRoleGrantKind,
+ Data: &OnSchemaGrantData{
+ Kind: OnFutureSchemasInDatabaseSchemaGrantKind,
+ DatabaseName: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name")),
+ },
+ },
+ Expected: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchema|OnFutureSchemasInDatabase|"database-name"`,
+ },
+ {
+ Name: "grant account role on schema object on object",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnObjectSchemaObjectGrantKind,
+ Object: &sdk.Object{
+ ObjectType: sdk.ObjectTypeTable,
+ Name: sdk.NewSchemaObjectIdentifier("database-name", "schema-name", "table-name"),
+ },
+ },
+ },
+ Expected: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnObject|TABLE|"database-name"."schema-name"."table-name"`,
+ },
+ {
+ Name: "grant account role on schema object on all tables in database",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnAllSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: sdk.PluralObjectTypeTables,
+ Kind: InDatabaseBulkOperationGrantKind,
+ Database: sdk.Pointer(sdk.NewAccountObjectIdentifier("database-name")),
+ },
+ },
+ },
+ Expected: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnAll|TABLES|InDatabase|"database-name"`,
+ },
+ {
+ Name: "grant account role on schema object on all tables in schema",
+ Identifier: GrantPrivilegesToAccountRoleId{
+ RoleName: sdk.NewAccountObjectIdentifier("account-role"),
+ WithGrantOption: false,
+ Privileges: []string{"CREATE SCHEMA", "USAGE", "MONITOR"},
+ Kind: OnSchemaObjectAccountRoleGrantKind,
+ Data: &OnSchemaObjectGrantData{
+ Kind: OnAllSchemaObjectGrantKind,
+ OnAllOrFuture: &BulkOperationGrantData{
+ ObjectNamePlural: sdk.PluralObjectTypeTables,
+ Kind: InSchemaBulkOperationGrantKind,
+ Schema: sdk.Pointer(sdk.NewDatabaseObjectIdentifier("database-name", "schema-name")),
+ },
+ },
+ },
+ Expected: `"account-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnSchemaObject|OnAll|TABLES|InSchema|"database-name"."schema-name"`,
+ },
+ }
+
+ for _, tt := range testCases {
+ tt := tt
+ t.Run(tt.Name, func(t *testing.T) {
+ assert.Equal(t, tt.Expected, tt.Identifier.String())
+ })
+ }
+}
diff --git a/pkg/resources/grant_privileges_to_database_role.go b/pkg/resources/grant_privileges_to_database_role.go
index 8f4b9f0cb3..9aa096130b 100644
--- a/pkg/resources/grant_privileges_to_database_role.go
+++ b/pkg/resources/grant_privileges_to_database_role.go
@@ -5,10 +5,8 @@ import (
"database/sql"
"fmt"
"slices"
- "strings"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
- "github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -64,7 +62,7 @@ var grantPrivilegesToDatabaseRoleSchema = map[string]*schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
- Description: "This field should not be set and its main purpose is to achieve the functionality described by always_apply field. This is value will be flipped to the opposite value on every terraform apply, thus creating a new plan that will re-apply grants.",
+ Description: "This is a helper field and should not be set. Its main purpose is to help to achieve the functionality described by the always_apply field.",
},
"on_database": {
Type: schema.TypeString,
@@ -155,7 +153,7 @@ var grantPrivilegesToDatabaseRoleSchema = map[string]*schema.Schema{
"on_schema_object.0.all",
"on_schema_object.0.future",
},
- ValidateDiagFunc: ValidObjectType(),
+ ValidateDiagFunc: ValidGrantedObjectType(),
},
"object_name": {
Type: schema.TypeString,
@@ -219,7 +217,7 @@ var grantPrivilegesOnDatabaseRoleBulkOperationSchema = map[string]*schema.Schema
Required: true,
ForceNew: true,
Description: "The plural object type of the schema object on which privileges will be granted. Valid values are: ALERTS | DYNAMIC TABLES | EVENT TABLES | FILE FORMATS | FUNCTIONS | PROCEDURES | SECRETS | SEQUENCES | PIPES | MASKING POLICIES | PASSWORD POLICIES | ROW ACCESS POLICIES | SESSION POLICIES | TAGS | STAGES | STREAMS | TABLES | EXTERNAL TABLES | TASKS | VIEWS | MATERIALIZED VIEWS | NETWORK RULES | PACKAGES POLICIES | ICEBERG TABLES",
- ValidateDiagFunc: ValidPluralObjectType(),
+ ValidateDiagFunc: ValidGrantedPluralObjectType(),
},
"in_database": {
Type: schema.TypeString,
@@ -235,28 +233,12 @@ var grantPrivilegesOnDatabaseRoleBulkOperationSchema = map[string]*schema.Schema
},
}
-func isNotOwnershipGrant() func(value any, path cty.Path) diag.Diagnostics {
- return func(value any, path cty.Path) diag.Diagnostics {
- var diags diag.Diagnostics
- if privilege, ok := value.(string); ok && strings.ToUpper(privilege) == "OWNERSHIP" {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Unsupported privilege 'OWNERSHIP'",
- // TODO: Change when a new resource for granting ownership will be available (SNOW-991423)
- Detail: "Granting ownership is only allowed in dedicated resources (snowflake_user_ownership_grant, snowflake_role_ownership_grant)",
- AttributePath: nil,
- })
- }
- return diags
- }
-}
-
func GrantPrivilegesToDatabaseRole() *schema.Resource {
return &schema.Resource{
CreateContext: CreateGrantPrivilegesToDatabaseRole,
- ReadContext: ReadGrantPrivilegesToDatabaseRole,
- DeleteContext: DeleteGrantPrivilegesToDatabaseRole,
UpdateContext: UpdateGrantPrivilegesToDatabaseRole,
+ DeleteContext: DeleteGrantPrivilegesToDatabaseRole,
+ ReadContext: ReadGrantPrivilegesToDatabaseRole,
Schema: grantPrivilegesToDatabaseRoleSchema,
Importer: &schema.ResourceImporter{
@@ -392,6 +374,7 @@ func UpdateGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.Resource
}
}
+ // handle all_privileges -> privileges change (revoke all privileges)
if d.HasChange("all_privileges") {
_, allPrivileges := d.GetChange("all_privileges")
@@ -419,17 +402,17 @@ func UpdateGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.Resource
}
if d.HasChange("privileges") {
- shouldGrantAndRevoke := true
+ shouldHandlePrivilegesChange := true
// Skip if all_privileges was set to true
if d.HasChange("all_privileges") {
if _, allPrivileges := d.GetChange("all_privileges"); allPrivileges.(bool) {
- shouldGrantAndRevoke = false
+ shouldHandlePrivilegesChange = false
id.Privileges = []string{}
}
}
- if shouldGrantAndRevoke {
+ if shouldHandlePrivilegesChange {
before, after := d.GetChange("privileges")
privilegesBeforeChange := expandStringList(before.(*schema.Set).List())
privilegesAfterChange := expandStringList(after.(*schema.Set).List())
@@ -504,6 +487,7 @@ func UpdateGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.Resource
}
}
+ // handle privileges -> all_privileges change (grant all privileges)
if d.HasChange("all_privileges") {
_, allPrivileges := d.GetChange("all_privileges")
@@ -609,6 +593,16 @@ func ReadGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.ResourceDa
}
if id.AlwaysApply {
+ // The Trigger is a string rather than boolean that would be flipped on every terraform apply
+ // because it's easier to think about and not to worry about edge cases that may occur with 1bit values.
+ // The only place to have the "flip" is Read operation, because there we can set value and produce a plan
+ // that later on will be executed in the Update operation.
+ //
+ // The following example shows that we can end up with the same value as before, which may lead to empty plans:
+ // 1. Create configuration with always_apply = false (let's say trigger will be false by default)
+ // 2. terraform apply: Create (Read will update it to false)
+ // 3. Update config so that always_apply = true
+ // 4. terraform apply: Read (updated trigger to false) -> change is not detected (no plan; no Update)
triggerId, err := uuid.GenerateUUID()
if err != nil {
return diag.Diagnostics{
@@ -652,11 +646,13 @@ func ReadGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.ResourceDa
client := sdk.NewClientFromDB(db)
grants, err := client.Grants.Show(ctx, opts)
if err != nil {
- return append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Failed to retrieve grants",
- Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
- })
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Failed to retrieve grants",
+ Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()),
+ },
+ }
}
var privileges []string
@@ -686,14 +682,16 @@ func ReadGrantPrivilegesToDatabaseRole(ctx context.Context, d *schema.ResourceDa
}
if err := d.Set("privileges", privileges); err != nil {
- return append(diags, diag.Diagnostic{
- Severity: diag.Error,
- Summary: "Error setting privileges for database role",
- Detail: fmt.Sprintf("Id: %s\nPrivileges: %v\nError: %s", d.Id(), privileges, err.Error()),
- })
+ return diag.Diagnostics{
+ diag.Diagnostic{
+ Severity: diag.Error,
+ Summary: "Error setting privileges for database role",
+ Detail: fmt.Sprintf("Id: %s\nPrivileges: %v\nError: %s", d.Id(), privileges, err.Error()),
+ },
+ }
}
- return diags
+ return nil
}
func prepareShowGrantsRequest(id GrantPrivilegesToDatabaseRoleId) (*sdk.ShowGrantOptions, sdk.ObjectType, diag.Diagnostics) {
@@ -889,23 +887,6 @@ func getDatabaseRoleGrantOn(d *schema.ResourceData) *sdk.DatabaseRoleGrantOn {
return on
}
-func getGrantOnSchemaObjectIn(allOrFuture map[string]any) *sdk.GrantOnSchemaObjectIn {
- pluralObjectType := sdk.PluralObjectType(allOrFuture["object_type_plural"].(string))
- grantOnSchemaObjectIn := &sdk.GrantOnSchemaObjectIn{
- PluralObjectType: pluralObjectType,
- }
-
- if inDatabase, ok := allOrFuture["in_database"].(string); ok && len(inDatabase) > 0 {
- grantOnSchemaObjectIn.InDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(inDatabase))
- }
-
- if inSchema, ok := allOrFuture["in_schema"].(string); ok && len(inSchema) > 0 {
- grantOnSchemaObjectIn.InSchema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(inSchema))
- }
-
- return grantOnSchemaObjectIn
-}
-
func createGrantPrivilegesToDatabaseRoleIdFromSchema(d *schema.ResourceData) *GrantPrivilegesToDatabaseRoleId {
id := new(GrantPrivilegesToDatabaseRoleId)
id.DatabaseRoleName = sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(d.Get("database_role_name").(string))
@@ -960,21 +941,3 @@ func createGrantPrivilegesToDatabaseRoleIdFromSchema(d *schema.ResourceData) *Gr
return id
}
-
-func getBulkOperationGrantData(in *sdk.GrantOnSchemaObjectIn) *BulkOperationGrantData {
- bulkOperationGrantData := &BulkOperationGrantData{
- ObjectNamePlural: in.PluralObjectType,
- }
-
- if in.InDatabase != nil {
- bulkOperationGrantData.Kind = InDatabaseBulkOperationGrantKind
- bulkOperationGrantData.Database = in.InDatabase
- }
-
- if in.InSchema != nil {
- bulkOperationGrantData.Kind = InSchemaBulkOperationGrantKind
- bulkOperationGrantData.Schema = in.InSchema
- }
-
- return bulkOperationGrantData
-}
diff --git a/pkg/resources/grant_privileges_to_database_role_acceptance_test.go b/pkg/resources/grant_privileges_to_database_role_acceptance_test.go
index 451c66f048..2a704dd7c3 100644
--- a/pkg/resources/grant_privileges_to_database_role_acceptance_test.go
+++ b/pkg/resources/grant_privileges_to_database_role_acceptance_test.go
@@ -4,11 +4,12 @@ import (
"context"
"database/sql"
"fmt"
- "log"
"regexp"
- "slices"
+ "strings"
"testing"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+
acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
"github.com/hashicorp/terraform-plugin-testing/config"
@@ -19,7 +20,7 @@ import (
)
func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -70,7 +71,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase(t *testing.T) {
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase_PrivilegesReversed(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -121,7 +122,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase_PrivilegesReversed(t *test
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnSchema(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -190,7 +191,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnSchema_ExactlyOneOf(t *testing.T) {
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnAllSchemasInDatabase(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -240,7 +241,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnAllSchemasInDatabase(t *testing.T)
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnFutureSchemasInDatabase(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -290,7 +291,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnFutureSchemasInDatabase(t *testing.
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnObject(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
tblName := "test_database_role_table_name"
configVariables := config.Variables{
"name": config.StringVariable(name),
@@ -344,7 +345,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnObject(t *testing.T)
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnObject_OwnershipPrivilege(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
tableName := "test_database_role_table_name"
configVariables := config.Variables{
"name": config.StringVariable(name),
@@ -376,7 +377,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnObject_OwnershipPriv
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnAll_InDatabase(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -428,7 +429,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnAll_InDatabase(t *te
}
func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnFuture_InDatabase(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := config.Variables{
"name": config.StringVariable(name),
"privileges": config.ListVariable(
@@ -480,7 +481,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnSchemaObject_OnFuture_InDatabase(t
}
func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := func(allPrivileges bool, privileges []sdk.AccountObjectPrivilege) config.Variables {
configVariables := config.Variables{
"name": config.StringVariable(name),
@@ -570,7 +571,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges(t *testing.T) {
}
func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges_SnowflakeChecked(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
schemaName := "test_database_role_schema_name"
configVariables := func(allPrivileges bool, privileges []string, schemaName string) config.Variables {
configVariables := config.Variables{
@@ -610,7 +611,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges_SnowflakeChecked(t *
sdk.AccountObjectPrivilegeCreateSchema.String(),
sdk.AccountObjectPrivilegeModify.String(),
}, ""),
- Check: queriedPrivilegesEqualTo(
+ Check: queriedPrivilegesToDatabaseRoleEqualTo(
databaseRoleName,
sdk.AccountObjectPrivilegeCreateSchema.String(),
sdk.AccountObjectPrivilegeModify.String(),
@@ -619,7 +620,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges_SnowflakeChecked(t *
{
ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/UpdatePrivileges_SnowflakeChecked/all_privileges"),
ConfigVariables: configVariables(true, []string{}, ""),
- Check: queriedPrivilegesContainAtLeast(
+ Check: queriedPrivilegesToDatabaseRoleContainAtLeast(
databaseRoleName,
sdk.AccountObjectPrivilegeCreateDatabaseRole.String(),
sdk.AccountObjectPrivilegeCreateSchema.String(),
@@ -634,7 +635,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges_SnowflakeChecked(t *
sdk.AccountObjectPrivilegeModify.String(),
sdk.AccountObjectPrivilegeMonitor.String(),
}, ""),
- Check: queriedPrivilegesEqualTo(
+ Check: queriedPrivilegesToDatabaseRoleEqualTo(
databaseRoleName,
sdk.AccountObjectPrivilegeModify.String(),
sdk.AccountObjectPrivilegeMonitor.String(),
@@ -646,7 +647,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges_SnowflakeChecked(t *
sdk.SchemaPrivilegeCreateTask.String(),
sdk.SchemaPrivilegeCreateExternalTable.String(),
}, schemaName),
- Check: queriedPrivilegesEqualTo(
+ Check: queriedPrivilegesToDatabaseRoleEqualTo(
databaseRoleName,
sdk.SchemaPrivilegeCreateTask.String(),
sdk.SchemaPrivilegeCreateExternalTable.String(),
@@ -657,7 +658,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges_SnowflakeChecked(t *
}
func TestAcc_GrantPrivilegesToDatabaseRole_AlwaysApply(t *testing.T) {
- name := "test_database_role_name"
+ name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
configVariables := func(alwaysApply bool) config.Variables {
return config.Variables{
"name": config.StringVariable(name),
@@ -760,63 +761,24 @@ func createDatabaseRoleOutsideTerraform(t *testing.T, name string) {
}
}
-// queriedPrivilegesEqualTo will check if all the privileges specified in the argument are granted in Snowflake.
-// Any additional grants (other than usage and ownership) will be treated as an error.
-func queriedPrivilegesEqualTo(databaseRoleName sdk.DatabaseObjectIdentifier, privileges ...string) func(s *terraform.State) error {
- return func(s *terraform.State) error {
- db := acc.TestAccProvider.Meta().(*sql.DB)
- ctx := context.Background()
- client := sdk.NewClientFromDB(db)
- grants, err := client.Grants.Show(ctx, &sdk.ShowGrantOptions{
+func queriedPrivilegesToDatabaseRoleEqualTo(databaseRoleName sdk.DatabaseObjectIdentifier, privileges ...string) func(s *terraform.State) error {
+ return queriedPrivilegesEqualTo(func(client *sdk.Client, ctx context.Context) ([]sdk.Grant, error) {
+ return client.Grants.Show(ctx, &sdk.ShowGrantOptions{
To: &sdk.ShowGrantsTo{
DatabaseRole: databaseRoleName,
},
})
- if err != nil {
- return err
- }
- for _, grant := range grants {
- if grant.Privilege == "USAGE" || grant.Privilege == "OWNERSHIP" {
- log.Printf("Skipping check for %s privilege as its one of the privileges that are implicitly granted by Snowflake", grant.Privilege)
- continue
- }
- if !slices.Contains(privileges, grant.Privilege) {
- return fmt.Errorf("grant not expected, grant: %v, not in %v", grants, privileges)
- }
- }
-
- return nil
- }
+ }, privileges...)
}
-// queriedPrivilegesContainAtLeast will check if all the privileges specified in the argument are granted in Snowflake.
-// Any additional grants will be ignored.
-func queriedPrivilegesContainAtLeast(databaseRoleName sdk.DatabaseObjectIdentifier, privileges ...string) func(s *terraform.State) error {
- return func(s *terraform.State) error {
- db := acc.TestAccProvider.Meta().(*sql.DB)
- ctx := context.Background()
- client := sdk.NewClientFromDB(db)
- grants, err := client.Grants.Show(ctx, &sdk.ShowGrantOptions{
+func queriedPrivilegesToDatabaseRoleContainAtLeast(databaseRoleName sdk.DatabaseObjectIdentifier, privileges ...string) func(s *terraform.State) error {
+ return queriedPrivilegesContainAtLeast(func(client *sdk.Client, ctx context.Context) ([]sdk.Grant, error) {
+ return client.Grants.Show(ctx, &sdk.ShowGrantOptions{
To: &sdk.ShowGrantsTo{
DatabaseRole: databaseRoleName,
},
})
- if err != nil {
- return err
- }
- var grantedPrivileges []string
- for _, grant := range grants {
- grantedPrivileges = append(grantedPrivileges, grant.Privilege)
- }
- notAllPrivilegesInGrantedPrivileges := slices.ContainsFunc(privileges, func(privilege string) bool {
- return !slices.Contains(grantedPrivileges, privilege)
- })
- if notAllPrivilegesInGrantedPrivileges {
- return fmt.Errorf("not every privilege from the list: %v was found in grant privileges: %v, for database role name: %s", privileges, grantedPrivileges, databaseRoleName.FullyQualifiedName())
- }
-
- return nil
- }
+ }, databaseRoleName, privileges...)
}
func testAccCheckDatabaseRolePrivilegesRevoked(s *terraform.State) error {
@@ -845,7 +807,7 @@ func testAccCheckDatabaseRolePrivilegesRevoked(s *terraform.State) error {
}
}
if len(grantedPrivileges) > 0 {
- return fmt.Errorf("database role (%s) still grants , granted privileges %v", id.FullyQualifiedName(), grantedPrivileges)
+ return fmt.Errorf("database role (%s) is still granted, granted privileges %v", id.FullyQualifiedName(), grantedPrivileges)
}
}
return nil
diff --git a/pkg/resources/grant_privileges_to_database_role_identifier.go b/pkg/resources/grant_privileges_to_database_role_identifier.go
index f297e968d8..56e4ec2044 100644
--- a/pkg/resources/grant_privileges_to_database_role_identifier.go
+++ b/pkg/resources/grant_privileges_to_database_role_identifier.go
@@ -17,22 +17,6 @@ const (
OnSchemaObjectDatabaseRoleGrantKind DatabaseRoleGrantKind = "OnSchemaObject"
)
-type OnSchemaGrantKind string
-
-const (
- OnSchemaSchemaGrantKind OnSchemaGrantKind = "OnSchema"
- OnAllSchemasInDatabaseSchemaGrantKind OnSchemaGrantKind = "OnAllSchemasInDatabase"
- OnFutureSchemasInDatabaseSchemaGrantKind OnSchemaGrantKind = "OnFutureSchemasInDatabase"
-)
-
-type OnSchemaObjectGrantKind string
-
-const (
- OnObjectSchemaObjectGrantKind OnSchemaObjectGrantKind = "OnObject"
- OnAllSchemaObjectGrantKind OnSchemaObjectGrantKind = "OnAll"
- OnFutureSchemaObjectGrantKind OnSchemaObjectGrantKind = "OnFuture"
-)
-
type GrantPrivilegesToDatabaseRoleId struct {
DatabaseRoleName sdk.DatabaseObjectIdentifier
WithGrantOption bool
@@ -66,77 +50,20 @@ func (d *OnDatabaseGrantData) String() string {
return d.DatabaseName.FullyQualifiedName()
}
-type OnSchemaGrantData struct {
- Kind OnSchemaGrantKind
- SchemaName *sdk.DatabaseObjectIdentifier
- DatabaseName *sdk.AccountObjectIdentifier
-}
-
-func (d *OnSchemaGrantData) String() string {
- var parts []string
- parts = append(parts, string(d.Kind))
- switch d.Kind {
- case OnSchemaSchemaGrantKind:
- parts = append(parts, d.SchemaName.FullyQualifiedName())
- case OnAllSchemasInDatabaseSchemaGrantKind, OnFutureSchemasInDatabaseSchemaGrantKind:
- parts = append(parts, d.DatabaseName.FullyQualifiedName())
- }
- return strings.Join(parts, helpers.IDDelimiter)
-}
-
-type OnSchemaObjectGrantData struct {
- Kind OnSchemaObjectGrantKind
- Object *sdk.Object
- OnAllOrFuture *BulkOperationGrantData
-}
-
-func (d *OnSchemaObjectGrantData) String() string {
- var parts []string
- parts = append(parts, string(d.Kind))
- switch d.Kind {
- case OnObjectSchemaObjectGrantKind:
- parts = append(parts, fmt.Sprintf("%s|%s", d.Object.ObjectType, d.Object.Name.FullyQualifiedName()))
- case OnAllSchemaObjectGrantKind, OnFutureSchemaObjectGrantKind:
- parts = append(parts, d.OnAllOrFuture.ObjectNamePlural.String())
- parts = append(parts, string(d.OnAllOrFuture.Kind))
- switch d.OnAllOrFuture.Kind {
- case InDatabaseBulkOperationGrantKind:
- parts = append(parts, d.OnAllOrFuture.Database.FullyQualifiedName())
- case InSchemaBulkOperationGrantKind:
- parts = append(parts, d.OnAllOrFuture.Schema.FullyQualifiedName())
- }
- }
- return strings.Join(parts, helpers.IDDelimiter)
-}
-
-type BulkOperationGrantKind string
-
-const (
- InDatabaseBulkOperationGrantKind BulkOperationGrantKind = "InDatabase"
- InSchemaBulkOperationGrantKind BulkOperationGrantKind = "InSchema"
-)
-
-type BulkOperationGrantData struct {
- ObjectNamePlural sdk.PluralObjectType
- Kind BulkOperationGrantKind
- Database *sdk.AccountObjectIdentifier
- Schema *sdk.DatabaseObjectIdentifier
-}
-
func ParseGrantPrivilegesToDatabaseRoleId(id string) (GrantPrivilegesToDatabaseRoleId, error) {
var databaseRoleId GrantPrivilegesToDatabaseRoleId
parts := strings.Split(id, helpers.IDDelimiter)
if len(parts) < 6 {
- return databaseRoleId, sdk.NewError(`database role identifier should hold at least 5 parts "|||||"`)
+ return databaseRoleId, sdk.NewError(`database role identifier should hold at least 6 parts "|||||"`)
}
// TODO: Identifier parsing should be replaced with better version introduced in SNOW-999049.
// Right now, it's same as sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName, but with error handling.
databaseRoleNameParts := strings.Split(parts[0], ".")
if len(databaseRoleNameParts) == 0 ||
- (len(databaseRoleNameParts) == 1 && databaseRoleNameParts[0] == "") ||
- (len(databaseRoleNameParts) == 2 && databaseRoleNameParts[1] == "") ||
+ (len(databaseRoleNameParts) == 1 && strings.Trim(databaseRoleNameParts[0], `"`) == "") ||
+ (len(databaseRoleNameParts) == 2 && strings.Trim(databaseRoleNameParts[1], `"`) == "") ||
len(databaseRoleNameParts) > 2 {
return databaseRoleId, sdk.NewError(fmt.Sprintf(`invalid DatabaseRoleName value: %s, should be a fully qualified name of database object .`, parts[0]))
}
@@ -164,6 +91,7 @@ func ParseGrantPrivilegesToDatabaseRoleId(id string) (GrantPrivilegesToDatabaseR
} else {
databaseRoleId.Privileges = privileges
}
+
databaseRoleId.Kind = DatabaseRoleGrantKind(parts[4])
switch databaseRoleId.Kind {
diff --git a/pkg/resources/grant_privileges_to_database_role_identifier_test.go b/pkg/resources/grant_privileges_to_database_role_identifier_test.go
index 6d6668816b..ea8cd4404b 100644
--- a/pkg/resources/grant_privileges_to_database_role_identifier_test.go
+++ b/pkg/resources/grant_privileges_to_database_role_identifier_test.go
@@ -221,12 +221,12 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) {
{
Name: "validation: grant database role not enough parts",
Identifier: `"database-name"."role-name"|false|false`,
- Error: "database role identifier should hold at least 5 parts",
+ Error: "database role identifier should hold at least 6 parts",
},
{
Name: "validation: grant database role not enough parts for OnDatabase kind",
Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabase`,
- Error: "database role identifier should hold at least 5 parts",
+ Error: "database role identifier should hold at least 6 parts",
},
{
Name: "validation: grant database role not enough parts for OnSchema kind",
@@ -291,6 +291,7 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) {
}
for _, tt := range testCases {
+ tt := tt
t.Run(tt.Name, func(t *testing.T) {
id, err := ParseGrantPrivilegesToDatabaseRoleId(tt.Identifier)
if tt.Error == "" {
@@ -422,6 +423,7 @@ func TestGrantPrivilegesToDatabaseRoleIdString(t *testing.T) {
}
for _, tt := range testCases {
+ tt := tt
t.Run(tt.Name, func(t *testing.T) {
assert.Equal(t, tt.Expected, tt.Identifier.String())
})
diff --git a/pkg/resources/grant_privileges_to_role.go b/pkg/resources/grant_privileges_to_role.go
index 6edc8b9ee8..0d5a768519 100644
--- a/pkg/resources/grant_privileges_to_role.go
+++ b/pkg/resources/grant_privileges_to_role.go
@@ -129,7 +129,7 @@ var grantPrivilegesToRoleSchema = map[string]*schema.Schema{
RequiredWith: []string{"on_schema_object.0.object_name"},
ConflictsWith: []string{"on_schema_object.0.all", "on_schema_object.0.future"},
ForceNew: true,
- ValidateDiagFunc: ValidObjectType(),
+ ValidateDiagFunc: ValidGrantedObjectType(),
},
"object_name": {
Type: schema.TypeString,
@@ -153,7 +153,7 @@ var grantPrivilegesToRoleSchema = map[string]*schema.Schema{
Required: true,
Description: "The plural object type of the schema object on which privileges will be granted. Valid values are: ALERTS | DYNAMIC TABLES | EVENT TABLES | FILE FORMATS | FUNCTIONS | ICEBERG TABLES | PROCEDURES | SECRETS | SEQUENCES | PIPES | MASKING POLICIES | PASSWORD POLICIES | ROW ACCESS POLICIES | SESSION POLICIES | TAGS | STAGES | STREAMS | TABLES | EXTERNAL TABLES | TASKS | VIEWS | MATERIALIZED VIEWS",
ForceNew: true,
- ValidateDiagFunc: ValidPluralObjectType(),
+ ValidateDiagFunc: ValidGrantedPluralObjectType(),
},
"in_database": {
Type: schema.TypeString,
@@ -187,7 +187,7 @@ var grantPrivilegesToRoleSchema = map[string]*schema.Schema{
Required: true,
Description: "The plural object type of the schema object on which privileges will be granted. Valid values are: ALERTS | DYNAMIC TABLES | EVENT TABLES | FILE FORMATS | FUNCTIONS | ICEBERG TABLES | PROCEDURES | SECRETS | SEQUENCES | PIPES | MASKING POLICIES | PASSWORD POLICIES | ROW ACCESS POLICIES | SESSION POLICIES | TAGS | STAGES | STREAMS | TABLES | EXTERNAL TABLES | TASKS | VIEWS | MATERIALIZED VIEWS",
ForceNew: true,
- ValidateDiagFunc: ValidPluralObjectType(),
+ ValidateDiagFunc: ValidGrantedPluralObjectType(),
},
"in_database": {
Type: schema.TypeString,
@@ -229,15 +229,16 @@ var grantPrivilegesToRoleSchema = map[string]*schema.Schema{
func GrantPrivilegesToRole() *schema.Resource {
return &schema.Resource{
- Create: CreateGrantPrivilegesToRole,
- Read: ReadGrantPrivilegesToRole,
- Delete: DeleteGrantPrivilegesToRole,
- Update: UpdateGrantPrivilegesToRole,
+ Create: CreateGrantPrivilegesToRole,
+ Read: ReadGrantPrivilegesToRole,
+ Delete: DeleteGrantPrivilegesToRole,
+ Update: UpdateGrantPrivilegesToRole,
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: grantPrivilegesToRoleSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
- resourceID := NewGrantPrivilegesToAccountRoleID(d.Id())
+ resourceID := NewGrantPrivilegesToRoleID(d.Id())
if err := d.Set("role_name", resourceID.RoleName); err != nil {
return nil, err
}
@@ -336,7 +337,7 @@ func GrantPrivilegesToRole() *schema.Resource {
}
// we need to keep track of literally everything to construct a unique identifier that can be imported
-type GrantPrivilegesToAccountRoleID struct {
+type GrantPrivilegesToRoleID struct {
RoleName string
Privileges []string
AllPrivileges bool
@@ -356,13 +357,13 @@ type GrantPrivilegesToAccountRoleID struct {
DatabaseName string
}
-func NewGrantPrivilegesToAccountRoleID(id string) GrantPrivilegesToAccountRoleID {
+func NewGrantPrivilegesToRoleID(id string) GrantPrivilegesToRoleID {
parts := strings.Split(id, "|")
privileges := strings.Split(parts[1], ",")
if len(privileges) == 1 && privileges[0] == "" {
privileges = []string{}
}
- return GrantPrivilegesToAccountRoleID{
+ return GrantPrivilegesToRoleID{
RoleName: parts[0],
Privileges: privileges,
AllPrivileges: parts[2] == "true",
@@ -383,7 +384,7 @@ func NewGrantPrivilegesToAccountRoleID(id string) GrantPrivilegesToAccountRoleID
}
}
-func (v GrantPrivilegesToAccountRoleID) String() string {
+func (v GrantPrivilegesToRoleID) String() string {
return helpers.EncodeSnowflakeID(v.RoleName, v.Privileges, v.AllPrivileges, v.WithGrantOption, v.OnAccount, v.OnAccountObject, v.OnSchema, v.OnSchemaObject, v.All, v.Future, v.ObjectType, v.ObjectName, v.ObjectTypePlural, v.InSchema, v.SchemaName, v.InDatabase, v.DatabaseName)
}
@@ -393,7 +394,7 @@ func CreateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
logging.DebugLogger.Printf("[DEBUG] Creating new client from db")
client := sdk.NewClientFromDB(db)
ctx := context.Background()
- resourceID := &GrantPrivilegesToAccountRoleID{}
+ resourceID := &GrantPrivilegesToRoleID{}
var privileges []string
if p, ok := d.GetOk("privileges"); ok {
logging.DebugLogger.Printf("[DEBUG] Building privileges list based on config")
@@ -402,7 +403,7 @@ func CreateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
}
allPrivileges := d.Get("all_privileges").(bool)
resourceID.AllPrivileges = allPrivileges
- privilegesToGrant, on, err := configureAccountRoleGrantPrivilegeOptions(d, privileges, allPrivileges, resourceID)
+ privilegesToGrant, on, err := configureRoleGrantPrivilegeOptions(d, privileges, allPrivileges, resourceID)
if err != nil {
return fmt.Errorf("error configuring account role grant privilege options: %w", err)
}
@@ -432,7 +433,7 @@ func ReadGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error {
logging.DebugLogger.Printf("[DEBUG] Creating new client from db")
client := sdk.NewClientFromDB(db)
ctx := context.Background()
- resourceID := NewGrantPrivilegesToAccountRoleID(d.Id())
+ resourceID := NewGrantPrivilegesToRoleID(d.Id())
roleName := resourceID.RoleName
allPrivileges := resourceID.AllPrivileges
if allPrivileges {
@@ -532,7 +533,7 @@ func ReadGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error {
}
}
- err := readAccountRoleGrantPrivileges(ctx, client, grantOn, resourceID, &opts, d)
+ err := readRoleGrantPrivileges(ctx, client, grantOn, resourceID, &opts, d)
if err != nil {
return err
}
@@ -574,7 +575,7 @@ func UpdateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
// first add new privileges
if len(addPrivileges) > 0 {
logging.DebugLogger.Printf("[DEBUG] Adding new privileges")
- privilegesToGrant, on, err := configureAccountRoleGrantPrivilegeOptions(d, addPrivileges, false, &GrantPrivilegesToAccountRoleID{})
+ privilegesToGrant, on, err := configureRoleGrantPrivilegeOptions(d, addPrivileges, false, &GrantPrivilegesToRoleID{})
if err != nil {
return fmt.Errorf("error configuring account role grant privilege options: %w", err)
}
@@ -589,7 +590,7 @@ func UpdateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
// then remove old privileges
if len(removePrivileges) > 0 {
logging.DebugLogger.Printf("[DEBUG] Removing old privileges")
- privilegesToRevoke, on, err := configureAccountRoleGrantPrivilegeOptions(d, removePrivileges, false, &GrantPrivilegesToAccountRoleID{})
+ privilegesToRevoke, on, err := configureRoleGrantPrivilegeOptions(d, removePrivileges, false, &GrantPrivilegesToRoleID{})
if err != nil {
return fmt.Errorf("error configuring account role grant privilege options: %w", err)
}
@@ -601,7 +602,7 @@ func UpdateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
}
}
logging.DebugLogger.Printf("[DEBUG] Setting new values")
- resourceID := NewGrantPrivilegesToAccountRoleID(d.Id())
+ resourceID := NewGrantPrivilegesToRoleID(d.Id())
resourceID.Privileges = newPrivileges
d.SetId(resourceID.String())
}
@@ -623,7 +624,7 @@ func DeleteGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
privileges = expandStringList(p.(*schema.Set).List())
}
allPrivileges := d.Get("all_privileges").(bool)
- privilegesToRevoke, on, err := configureAccountRoleGrantPrivilegeOptions(d, privileges, allPrivileges, &GrantPrivilegesToAccountRoleID{})
+ privilegesToRevoke, on, err := configureRoleGrantPrivilegeOptions(d, privileges, allPrivileges, &GrantPrivilegesToRoleID{})
if err != nil {
return fmt.Errorf("error configuring account role grant privilege options: %w", err)
}
@@ -638,7 +639,7 @@ func DeleteGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error
return nil
}
-func configureAccountRoleGrantPrivilegeOptions(d *schema.ResourceData, privileges []string, allPrivileges bool, resourceID *GrantPrivilegesToAccountRoleID) (*sdk.AccountRoleGrantPrivileges, *sdk.AccountRoleGrantOn, error) {
+func configureRoleGrantPrivilegeOptions(d *schema.ResourceData, privileges []string, allPrivileges bool, resourceID *GrantPrivilegesToRoleID) (*sdk.AccountRoleGrantPrivileges, *sdk.AccountRoleGrantOn, error) {
logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options")
var privilegesToGrant *sdk.AccountRoleGrantPrivileges
on := sdk.AccountRoleGrantOn{}
@@ -646,7 +647,7 @@ func configureAccountRoleGrantPrivilegeOptions(d *schema.ResourceData, privilege
logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: on account")
on.Account = sdk.Bool(true)
resourceID.OnAccount = true
- privilegesToGrant = setAccountRolePrivilegeOptions(privileges, allPrivileges, true, false, false, false)
+ privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, true, false, false, false)
return privilegesToGrant, &on, nil
}
@@ -680,7 +681,7 @@ func configureAccountRoleGrantPrivilegeOptions(d *schema.ResourceData, privilege
default:
return nil, nil, fmt.Errorf("invalid object type %s", objectType)
}
- privilegesToGrant = setAccountRolePrivilegeOptions(privileges, allPrivileges, false, true, false, false)
+ privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, false, true, false, false)
return privilegesToGrant, &on, nil
}
@@ -709,7 +710,7 @@ func configureAccountRoleGrantPrivilegeOptions(d *schema.ResourceData, privilege
resourceID.DatabaseName = v.(string)
on.Schema.FutureSchemasInDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(v.(string)))
}
- privilegesToGrant = setAccountRolePrivilegeOptions(privileges, allPrivileges, false, false, true, false)
+ privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, false, false, true, false)
return privilegesToGrant, &on, nil
}
@@ -774,14 +775,14 @@ func configureAccountRoleGrantPrivilegeOptions(d *schema.ResourceData, privilege
}
}
- privilegesToGrant = setAccountRolePrivilegeOptions(privileges, allPrivileges, false, false, false, true)
+ privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, false, false, false, true)
return privilegesToGrant, &on, nil
}
logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: invalid")
return nil, nil, fmt.Errorf("invalid grant options")
}
-func setAccountRolePrivilegeOptions(privileges []string, allPrivileges bool, onAccount bool, onAccountObject bool, onSchema bool, onSchemaObject bool) *sdk.AccountRoleGrantPrivileges {
+func setRolePrivilegeOptions(privileges []string, allPrivileges bool, onAccount bool, onAccountObject bool, onSchema bool, onSchemaObject bool) *sdk.AccountRoleGrantPrivileges {
privilegesToGrant := &sdk.AccountRoleGrantPrivileges{}
if allPrivileges {
logging.DebugLogger.Printf("[DEBUG] Setting all privileges on privileges to grant")
@@ -824,7 +825,7 @@ func setAccountRolePrivilegeOptions(privileges []string, allPrivileges bool, onA
return nil
}
-func readAccountRoleGrantPrivileges(ctx context.Context, client *sdk.Client, grantedOn sdk.ObjectType, id GrantPrivilegesToAccountRoleID, opts *sdk.ShowGrantOptions, d *schema.ResourceData) error {
+func readRoleGrantPrivileges(ctx context.Context, client *sdk.Client, grantedOn sdk.ObjectType, id GrantPrivilegesToRoleID, opts *sdk.ShowGrantOptions, d *schema.ResourceData) error {
logging.DebugLogger.Printf("[DEBUG] About to show grants")
grants, err := client.Grants.Show(ctx, opts)
logging.DebugLogger.Printf("[DEBUG] After showing grants: err = %v", err)
@@ -834,7 +835,7 @@ func readAccountRoleGrantPrivileges(ctx context.Context, client *sdk.Client, gra
withGrantOption := d.Get("with_grant_option").(bool)
privileges := []string{}
- roleName := sdk.NewAccountObjectIdentifier(d.Get("role_name").(string)).Name()
+ roleName := d.Get("role_name").(string)
logging.DebugLogger.Printf("[DEBUG] Filtering grants to be set on account: count = %d", len(grants))
for _, grant := range grants {
@@ -855,6 +856,7 @@ func readAccountRoleGrantPrivileges(ctx context.Context, client *sdk.Client, gra
}
}
}
+
logging.DebugLogger.Printf("[DEBUG] Setting privileges on account")
if err := d.Set("privileges", privileges); err != nil {
logging.DebugLogger.Printf("[DEBUG] Error setting privileges for account role: err = %v", err)
diff --git a/pkg/resources/helpers_test.go b/pkg/resources/helpers_test.go
index cf65bfff25..941a71be92 100644
--- a/pkg/resources/helpers_test.go
+++ b/pkg/resources/helpers_test.go
@@ -1,9 +1,17 @@
package resources_test
import (
+ "context"
+ "database/sql"
+ "fmt"
"os"
+ "slices"
"testing"
+ acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
+ "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+
"github.com/stretchr/testify/assert"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -491,3 +499,52 @@ func tagGrant(t *testing.T, id string, params map[string]interface{}) *schema.Re
d.SetId(id)
return d
}
+
+// queriedAccountRolePrivilegesEqualTo will check if all the privileges specified in the argument are granted in Snowflake.
+func queriedPrivilegesEqualTo(query func(client *sdk.Client, ctx context.Context) ([]sdk.Grant, error), privileges ...string) func(s *terraform.State) error {
+ return func(s *terraform.State) error {
+ db := acc.TestAccProvider.Meta().(*sql.DB)
+ ctx := context.Background()
+ client := sdk.NewClientFromDB(db)
+ grants, err := query(client, ctx)
+ if err != nil {
+ return err
+ }
+ for _, grant := range grants {
+ if (grant.GrantTo == sdk.ObjectTypeDatabaseRole || grant.GrantedTo == sdk.ObjectTypeDatabaseRole) && grant.Privilege == "USAGE" {
+ continue
+ }
+ if !slices.Contains(privileges, grant.Privilege) {
+ return fmt.Errorf("grant not expected, grant: %v, not in %v", grants, privileges)
+ }
+ }
+
+ return nil
+ }
+}
+
+// queriedAccountRolePrivilegesContainAtLeast will check if all the privileges specified in the argument are granted in Snowflake.
+// Any additional grants will be ignored.
+func queriedPrivilegesContainAtLeast(query func(client *sdk.Client, ctx context.Context) ([]sdk.Grant, error), roleName sdk.ObjectIdentifier, privileges ...string) func(s *terraform.State) error {
+ return func(s *terraform.State) error {
+ db := acc.TestAccProvider.Meta().(*sql.DB)
+ ctx := context.Background()
+ client := sdk.NewClientFromDB(db)
+ grants, err := query(client, ctx)
+ if err != nil {
+ return err
+ }
+ var grantedPrivileges []string
+ for _, grant := range grants {
+ grantedPrivileges = append(grantedPrivileges, grant.Privilege)
+ }
+ notAllPrivilegesInGrantedPrivileges := slices.ContainsFunc(privileges, func(privilege string) bool {
+ return !slices.Contains(grantedPrivileges, privilege)
+ })
+ if notAllPrivilegesInGrantedPrivileges {
+ return fmt.Errorf("not every privilege from the list: %v was found in grant privileges: %v, for role name: %s", privileges, grantedPrivileges, roleName.FullyQualifiedName())
+ }
+
+ return nil
+ }
+}
diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go
index 1daac92b0f..ec79f0b16e 100644
--- a/pkg/resources/integration_grant.go
+++ b/pkg/resources/integration_grant.go
@@ -74,7 +74,7 @@ func IntegrationGrant() *TerraformGrantResource {
Read: ReadIntegrationGrant,
Delete: DeleteIntegrationGrant,
Update: UpdateIntegrationGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: integrationGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go
index 0cf4a99817..826a531c31 100644
--- a/pkg/resources/masking_policy_grant.go
+++ b/pkg/resources/masking_policy_grant.go
@@ -86,7 +86,7 @@ func MaskingPolicyGrant() *TerraformGrantResource {
Read: ReadMaskingPolicyGrant,
Delete: DeleteMaskingPolicyGrant,
Update: UpdateMaskingPolicyGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: maskingPolicyGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go
index 09860819fa..d410095adc 100644
--- a/pkg/resources/materialized_view_grant.go
+++ b/pkg/resources/materialized_view_grant.go
@@ -113,7 +113,7 @@ func MaterializedViewGrant() *TerraformGrantResource {
Read: ReadMaterializedViewGrant,
Delete: DeleteMaterializedViewGrant,
Update: UpdateMaterializedViewGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: materializedViewGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go
index 21c864f2ce..4538c35f82 100644
--- a/pkg/resources/pipe_grant.go
+++ b/pkg/resources/pipe_grant.go
@@ -94,7 +94,7 @@ func PipeGrant() *TerraformGrantResource {
Read: ReadPipeGrant,
Delete: DeletePipeGrant,
Update: UpdatePipeGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: pipeGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go
index 1e4a9e7b85..924c735073 100644
--- a/pkg/resources/procedure_grant.go
+++ b/pkg/resources/procedure_grant.go
@@ -115,7 +115,7 @@ func ProcedureGrant() *TerraformGrantResource {
Read: ReadProcedureGrant,
Delete: DeleteProcedureGrant,
Update: UpdateProcedureGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: procedureGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go
index 93c6b176d8..eb9a312506 100644
--- a/pkg/resources/resource_monitor_grant.go
+++ b/pkg/resources/resource_monitor_grant.go
@@ -62,7 +62,7 @@ func ResourceMonitorGrant() *TerraformGrantResource {
Read: ReadResourceMonitorGrant,
Delete: DeleteResourceMonitorGrant,
Update: UpdateResourceMonitorGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), helpers.IDDelimiter)
diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go
index ebb2a1b25b..957bd0f372 100644
--- a/pkg/resources/row_access_policy_grant.go
+++ b/pkg/resources/row_access_policy_grant.go
@@ -86,7 +86,7 @@ func RowAccessPolicyGrant() *TerraformGrantResource {
Read: ReadRowAccessPolicyGrant,
Delete: DeleteRowAccessPolicyGrant,
Update: UpdateRowAccessPolicyGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: rowAccessPolicyGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go
index 4929d4d2f8..b2751f1e24 100644
--- a/pkg/resources/schema_grant.go
+++ b/pkg/resources/schema_grant.go
@@ -124,7 +124,7 @@ func SchemaGrant() *TerraformGrantResource {
Read: ReadSchemaGrant,
Delete: DeleteSchemaGrant,
Update: UpdateSchemaGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: schemaGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go
index 4854ab764d..a4d2588f56 100644
--- a/pkg/resources/sequence_grant.go
+++ b/pkg/resources/sequence_grant.go
@@ -103,7 +103,7 @@ func SequenceGrant() *TerraformGrantResource {
Read: ReadSequenceGrant,
Delete: DeleteSequenceGrant,
Update: UpdateSequenceGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: sequenceGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go
index df6d01f4e0..ef1ab6e58c 100644
--- a/pkg/resources/stage_grant.go
+++ b/pkg/resources/stage_grant.go
@@ -106,7 +106,7 @@ func StageGrant() *TerraformGrantResource {
Read: ReadStageGrant,
Delete: DeleteStageGrant,
Update: UpdateStageGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: stageGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go
index 1100356ba2..e55cdc31f5 100644
--- a/pkg/resources/stream_grant.go
+++ b/pkg/resources/stream_grant.go
@@ -103,7 +103,7 @@ func StreamGrant() *TerraformGrantResource {
Read: ReadStreamGrant,
Delete: DeleteStreamGrant,
Update: UpdateStreamGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: streamGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go
index 378c1bff4b..19df12a6fe 100644
--- a/pkg/resources/table_grant.go
+++ b/pkg/resources/table_grant.go
@@ -113,7 +113,7 @@ func TableGrant() *TerraformGrantResource {
Read: ReadTableGrant,
Delete: DeleteTableGrant,
Update: UpdateTableGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: tableGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go
index 8a2d98f5e0..2ccd733aa0 100644
--- a/pkg/resources/tag_grant.go
+++ b/pkg/resources/tag_grant.go
@@ -86,7 +86,7 @@ func TagGrant() *TerraformGrantResource {
Read: ReadTagGrant,
Update: UpdateTagGrant,
Delete: DeleteTagGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: tagGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go
index cc26b32c39..41c0d54783 100644
--- a/pkg/resources/task_grant.go
+++ b/pkg/resources/task_grant.go
@@ -104,7 +104,7 @@ func TaskGrant() *TerraformGrantResource {
Read: ReadTaskGrant,
Delete: DeleteTaskGrant,
Update: UpdateTaskGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: taskGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/AlwaysApply/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/AlwaysApply/test.tf
new file mode 100644
index 0000000000..8fc91be4e1
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/AlwaysApply/test.tf
@@ -0,0 +1,9 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ all_privileges = var.all_privileges
+ always_apply = var.always_apply
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/AlwaysApply/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/AlwaysApply/variables.tf
new file mode 100644
index 0000000000..563945ecc7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/AlwaysApply/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "all_privileges" {
+ type = bool
+}
+
+variable "database" {
+ type = string
+}
+
+variable "always_apply" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccount/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccount/test.tf
new file mode 100644
index 0000000000..7be94738ba
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccount/test.tf
@@ -0,0 +1,6 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ on_account = true
+ with_grant_option = var.with_grant_option
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccount/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccount/variables.tf
new file mode 100644
index 0000000000..82bfdf9934
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccount/variables.tf
@@ -0,0 +1,11 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject/test.tf
new file mode 100644
index 0000000000..8fc5c7e82a
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject/test.tf
@@ -0,0 +1,9 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject/variables.tf
new file mode 100644
index 0000000000..c60ae630f7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "database" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan/test.tf
new file mode 100644
index 0000000000..700e91c6de
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan/test.tf
@@ -0,0 +1,8 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ privileges = ["CREATE SCHEMA"]
+ account_role_name = "\"${var.name}\""
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
\ No newline at end of file
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan/variables.tf
new file mode 100644
index 0000000000..2cf13b7d6e
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAccountObject_InfinitePlan/variables.tf
@@ -0,0 +1,7 @@
+variable "name" {
+ type = string
+}
+
+variable "database" {
+ type = string
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase/test.tf
new file mode 100644
index 0000000000..2be39c206c
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase/test.tf
@@ -0,0 +1,9 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+
+ on_schema {
+ all_schemas_in_database = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase/variables.tf
new file mode 100644
index 0000000000..0e22e903d7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnAllSchemasInDatabase/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase/test.tf
new file mode 100644
index 0000000000..3ffada833e
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase/test.tf
@@ -0,0 +1,9 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+
+ on_schema {
+ future_schemas_in_database = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase/variables.tf
new file mode 100644
index 0000000000..0e22e903d7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnFutureSchemasInDatabase/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema/test.tf
new file mode 100644
index 0000000000..d22337fe38
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema/test.tf
@@ -0,0 +1,9 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+
+ on_schema {
+ schema_name = "\"${var.database}\".\"${var.schema}\""
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema/variables.tf
new file mode 100644
index 0000000000..44c69f32ee
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema/variables.tf
@@ -0,0 +1,19 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "schema" {
+ type = string
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase/test.tf
new file mode 100644
index 0000000000..7fa86e21f7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase/test.tf
@@ -0,0 +1,12 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+
+ on_schema_object {
+ all {
+ object_type_plural = "TABLES"
+ in_database = var.database
+ }
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase/variables.tf
new file mode 100644
index 0000000000..0e22e903d7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnAll_InDatabase/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase/test.tf
new file mode 100644
index 0000000000..ed7804ce4b
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase/test.tf
@@ -0,0 +1,12 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+
+ on_schema_object {
+ future {
+ object_type_plural = "TABLES"
+ in_database = var.database
+ }
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase/variables.tf
new file mode 100644
index 0000000000..0e22e903d7
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnFuture_InDatabase/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject/test.tf
new file mode 100644
index 0000000000..5f4cc61b8b
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject/test.tf
@@ -0,0 +1,22 @@
+resource "snowflake_table" "test" {
+ database = var.database
+ schema = var.schema
+ name = var.table_name
+
+ column {
+ name = "id"
+ type = "NUMBER(38,0)"
+ }
+}
+
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ depends_on = [snowflake_table.test]
+ account_role_name = var.name
+ privileges = var.privileges
+ with_grant_option = var.with_grant_option
+
+ on_schema_object {
+ object_type = "TABLE"
+ object_name = "\"${var.database}\".\"${var.schema}\".\"${var.table_name}\""
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject/variables.tf
new file mode 100644
index 0000000000..e779508540
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchemaObject_OnObject/variables.tf
@@ -0,0 +1,23 @@
+variable "name" {
+ type = string
+}
+
+variable "table_name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "schema" {
+ type = string
+}
+
+variable "with_grant_option" {
+ type = bool
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema_ExactlyOneOf/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema_ExactlyOneOf/test.tf
new file mode 100644
index 0000000000..fab4091039
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/OnSchema_ExactlyOneOf/test.tf
@@ -0,0 +1,9 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = "role_name"
+ privileges = ["USAGE"]
+
+ on_schema {
+ schema_name = "some_database.schema_name"
+ all_schemas_in_database = "some_database"
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges/test.tf
new file mode 100644
index 0000000000..ae5a851309
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges/test.tf
@@ -0,0 +1,8 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ all_privileges = var.all_privileges
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges/variables.tf
new file mode 100644
index 0000000000..cb4441bfce
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/all_privileges/variables.tf
@@ -0,0 +1,11 @@
+variable "name" {
+ type = string
+}
+
+variable "all_privileges" {
+ type = bool
+}
+
+variable "database" {
+ type = string
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges/test.tf
new file mode 100644
index 0000000000..b64219e171
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges/test.tf
@@ -0,0 +1,8 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges/variables.tf
new file mode 100644
index 0000000000..27eccc7883
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges/privileges/variables.tf
@@ -0,0 +1,11 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges/test.tf
new file mode 100644
index 0000000000..ae5a851309
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges/test.tf
@@ -0,0 +1,8 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ all_privileges = var.all_privileges
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges/variables.tf
new file mode 100644
index 0000000000..cb4441bfce
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/all_privileges/variables.tf
@@ -0,0 +1,11 @@
+variable "name" {
+ type = string
+}
+
+variable "all_privileges" {
+ type = bool
+}
+
+variable "database" {
+ type = string
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema/test.tf
new file mode 100644
index 0000000000..f414ad817c
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema/test.tf
@@ -0,0 +1,13 @@
+resource "snowflake_schema" "test" {
+ database = var.database
+ name = var.schema_name
+}
+
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ depends_on = [snowflake_schema.test]
+ account_role_name = var.name
+ privileges = var.privileges
+ on_schema {
+ schema_name = "${var.database}.${var.schema_name}"
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema/variables.tf
new file mode 100644
index 0000000000..90d9c04448
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/on_schema/variables.tf
@@ -0,0 +1,15 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
+
+variable "schema_name" {
+ type = string
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges/test.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges/test.tf
new file mode 100644
index 0000000000..b64219e171
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges/test.tf
@@ -0,0 +1,8 @@
+resource "snowflake_grant_privileges_to_account_role" "test" {
+ account_role_name = var.name
+ privileges = var.privileges
+ on_account_object {
+ object_type = "DATABASE"
+ object_name = var.database
+ }
+}
diff --git a/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges/variables.tf b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges/variables.tf
new file mode 100644
index 0000000000..27eccc7883
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_GrantPrivilegesToAccountRole/UpdatePrivileges_SnowflakeChecked/privileges/variables.tf
@@ -0,0 +1,11 @@
+variable "name" {
+ type = string
+}
+
+variable "privileges" {
+ type = list(string)
+}
+
+variable "database" {
+ type = string
+}
diff --git a/pkg/resources/user_grant.go b/pkg/resources/user_grant.go
index e944c4e38d..a8af8e24a7 100644
--- a/pkg/resources/user_grant.go
+++ b/pkg/resources/user_grant.go
@@ -59,7 +59,7 @@ func UserGrant() *TerraformGrantResource {
Read: ReadUserGrant,
Delete: DeleteUserGrant,
Update: UpdateUserGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: userGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/validators.go b/pkg/resources/validators.go
index b14e122d7f..99d0be8c3a 100644
--- a/pkg/resources/validators.go
+++ b/pkg/resources/validators.go
@@ -110,65 +110,6 @@ func getExpectedIdentifierForm(id any) string {
return ""
}
-func ValidObjectType() schema.SchemaValidateDiagFunc {
- return StringInSlice([]string{
- sdk.ObjectTypeAlert.String(),
- sdk.ObjectTypeDynamicTable.String(),
- sdk.ObjectTypeEventTable.String(),
- sdk.ObjectTypeFileFormat.String(),
- sdk.ObjectTypeFunction.String(),
- sdk.ObjectTypeProcedure.String(),
- sdk.ObjectTypeSecret.String(),
- sdk.ObjectTypeSequence.String(),
- sdk.ObjectTypePipe.String(),
- sdk.ObjectTypeMaskingPolicy.String(),
- sdk.ObjectTypePasswordPolicy.String(),
- sdk.ObjectTypeRowAccessPolicy.String(),
- sdk.ObjectTypeSessionPolicy.String(),
- sdk.ObjectTypeTag.String(),
- sdk.ObjectTypeStage.String(),
- sdk.ObjectTypeStream.String(),
- sdk.ObjectTypeTable.String(),
- sdk.ObjectTypeExternalTable.String(),
- sdk.ObjectTypeTask.String(),
- sdk.ObjectTypeView.String(),
- sdk.ObjectTypeMaterializedView.String(),
- sdk.ObjectTypeNetworkRule.String(),
- sdk.ObjectTypePackagesPolicy.String(),
- sdk.ObjectTypeIcebergTable.String(),
- }, true)
-}
-
-func ValidPluralObjectType() schema.SchemaValidateDiagFunc {
- return StringInSlice(
- []string{
- sdk.PluralObjectTypeAlerts.String(),
- sdk.PluralObjectTypeDynamicTables.String(),
- sdk.PluralObjectTypeEventTables.String(),
- sdk.PluralObjectTypeFileFormats.String(),
- sdk.PluralObjectTypeFunctions.String(),
- sdk.PluralObjectTypeProcedures.String(),
- sdk.PluralObjectTypeSecrets.String(),
- sdk.PluralObjectTypeSequences.String(),
- sdk.PluralObjectTypePipes.String(),
- sdk.PluralObjectTypeMaskingPolicies.String(),
- sdk.PluralObjectTypePasswordPolicies.String(),
- sdk.PluralObjectTypeRowAccessPolicies.String(),
- sdk.PluralObjectTypeSessionPolicies.String(),
- sdk.PluralObjectTypeTags.String(),
- sdk.PluralObjectTypeStages.String(),
- sdk.PluralObjectTypeStreams.String(),
- sdk.PluralObjectTypeTables.String(),
- sdk.PluralObjectTypeExternalTables.String(),
- sdk.PluralObjectTypeTasks.String(),
- sdk.PluralObjectTypeViews.String(),
- sdk.PluralObjectTypeMaterializedViews.String(),
- sdk.PluralObjectTypeNetworkRules.String(),
- sdk.PluralObjectTypePackagesPolicies.String(),
- sdk.PluralObjectTypeIcebergTables.String(),
- }, true)
-}
-
// StringInSlice has the same implementation as validation.StringInSlice, but adapted to schema.SchemaValidateDiagFunc
func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateDiagFunc {
return func(i interface{}, path cty.Path) diag.Diagnostics {
diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go
index eb11f333af..7ac1efeea2 100644
--- a/pkg/resources/view_grant.go
+++ b/pkg/resources/view_grant.go
@@ -108,7 +108,7 @@ func ViewGrant() *TerraformGrantResource {
Read: ReadViewGrant,
Delete: DeleteViewGrant,
Update: UpdateViewGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: viewGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go
index 5351eb579a..d850c0452e 100644
--- a/pkg/resources/warehouse_grant.go
+++ b/pkg/resources/warehouse_grant.go
@@ -76,7 +76,7 @@ func WarehouseGrant() *TerraformGrantResource {
Read: ReadWarehouseGrant,
Delete: DeleteWarehouseGrant,
Update: UpdateWarehouseGrant,
- DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_role instead.",
+ DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_privileges_to_account_role instead.",
Schema: warehouseGrantSchema,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
diff --git a/pkg/sdk/grants.go b/pkg/sdk/grants.go
index 191d7388ce..2eb79f7372 100644
--- a/pkg/sdk/grants.go
+++ b/pkg/sdk/grants.go
@@ -48,6 +48,7 @@ type GrantOnAccountObject struct {
User *AccountObjectIdentifier `ddl:"identifier" sql:"USER"`
ResourceMonitor *AccountObjectIdentifier `ddl:"identifier" sql:"RESOURCE MONITOR"`
Warehouse *AccountObjectIdentifier `ddl:"identifier" sql:"WAREHOUSE"`
+ ComputePool *AccountObjectIdentifier `ddl:"identifier" sql:"COMPUTE POOL"`
Database *AccountObjectIdentifier `ddl:"identifier" sql:"DATABASE"`
Integration *AccountObjectIdentifier `ddl:"identifier" sql:"INTEGRATION"`
FailoverGroup *AccountObjectIdentifier `ddl:"identifier" sql:"FAILOVER GROUP"`
diff --git a/pkg/sdk/grants_test.go b/pkg/sdk/grants_test.go
index 8aecb1cb7a..19289554fe 100644
--- a/pkg/sdk/grants_test.go
+++ b/pkg/sdk/grants_test.go
@@ -51,6 +51,50 @@ func TestGrantPrivilegesToAccountRole(t *testing.T) {
assertOptsValidAndSQLEquals(t, opts, `GRANT ALL PRIVILEGES ON EXTERNAL VOLUME "ex volume" TO ROLE "role1"`)
})
+ t.Run("on account object - compute pool", func(t *testing.T) {
+ opts := &GrantPrivilegesToAccountRoleOptions{
+ privileges: &AccountRoleGrantPrivileges{
+ AllPrivileges: Bool(true),
+ },
+ on: &AccountRoleGrantOn{
+ AccountObject: &GrantOnAccountObject{
+ ComputePool: Pointer(NewAccountObjectIdentifier("compute pool")),
+ },
+ },
+ accountRole: NewAccountObjectIdentifier("role1"),
+ }
+ assertOptsValidAndSQLEquals(t, opts, `GRANT ALL PRIVILEGES ON COMPUTE POOL "compute pool" TO ROLE "role1"`)
+ })
+
+ t.Run("on account object - exactly one of validation", func(t *testing.T) {
+ opts := &GrantPrivilegesToAccountRoleOptions{
+ privileges: &AccountRoleGrantPrivileges{
+ AllPrivileges: Bool(true),
+ },
+ on: &AccountRoleGrantOn{
+ AccountObject: &GrantOnAccountObject{
+ Database: Pointer(NewAccountObjectIdentifier("database")),
+ ComputePool: Pointer(NewAccountObjectIdentifier("pool")),
+ },
+ },
+ accountRole: NewAccountObjectIdentifier("role1"),
+ }
+ assertOptsInvalid(t, opts, errExactlyOneOf("GrantOnAccountObject", "User", "ResourceMonitor", "Warehouse", "ComputePool", "Database", "Integration", "Connection", "FailoverGroup", "ReplicationGroup", "ExternalVolume"))
+ })
+
+ t.Run("on account object - exactly one of validation - empty options", func(t *testing.T) {
+ opts := &GrantPrivilegesToAccountRoleOptions{
+ privileges: &AccountRoleGrantPrivileges{
+ AllPrivileges: Bool(true),
+ },
+ on: &AccountRoleGrantOn{
+ AccountObject: &GrantOnAccountObject{},
+ },
+ accountRole: NewAccountObjectIdentifier("role1"),
+ }
+ assertOptsInvalid(t, opts, errExactlyOneOf("GrantOnAccountObject", "User", "ResourceMonitor", "Warehouse", "ComputePool", "Database", "Integration", "Connection", "FailoverGroup", "ReplicationGroup", "ExternalVolume"))
+ })
+
t.Run("on schema", func(t *testing.T) {
opts := &GrantPrivilegesToAccountRoleOptions{
privileges: &AccountRoleGrantPrivileges{
@@ -194,6 +238,7 @@ func TestRevokePrivilegesFromAccountRole(t *testing.T) {
}
assertOptsValidAndSQLEquals(t, opts, `REVOKE CREATE DATABASE ROLE, MODIFY ON DATABASE "db1" FROM ROLE "role1"`)
})
+
t.Run("on schema", func(t *testing.T) {
opts := &RevokePrivilegesFromAccountRoleOptions{
privileges: &AccountRoleGrantPrivileges{
diff --git a/pkg/sdk/grants_validations.go b/pkg/sdk/grants_validations.go
index 339a78a5e8..3f7317afbf 100644
--- a/pkg/sdk/grants_validations.go
+++ b/pkg/sdk/grants_validations.go
@@ -70,8 +70,8 @@ func (v *AccountRoleGrantOn) validate() error {
}
func (v *GrantOnAccountObject) validate() error {
- if !exactlyOneValueSet(v.User, v.ResourceMonitor, v.Warehouse, v.Database, v.Integration, v.FailoverGroup, v.ReplicationGroup, v.ExternalVolume) {
- return errExactlyOneOf("GrantOnAccountObject", "User", "ResourceMonitor", "Warehouse", "Database", "Integration", "FailoverGroup", "ReplicationGroup", "ExternalVolume")
+ if !exactlyOneValueSet(v.User, v.ResourceMonitor, v.Warehouse, v.ComputePool, v.Database, v.Integration, v.FailoverGroup, v.ReplicationGroup, v.ExternalVolume) {
+ return errExactlyOneOf("GrantOnAccountObject", "User", "ResourceMonitor", "Warehouse", "ComputePool", "Database", "Integration", "FailoverGroup", "ReplicationGroup", "ExternalVolume")
}
return nil
}
diff --git a/pkg/sdk/object_types.go b/pkg/sdk/object_types.go
index ea858b9441..c829419eb3 100644
--- a/pkg/sdk/object_types.go
+++ b/pkg/sdk/object_types.go
@@ -62,6 +62,7 @@ const (
ObjectTypeExternalVolume ObjectType = "EXTERNAL VOLUME"
ObjectTypeNetworkRule ObjectType = "NETWORK RULE"
ObjectTypePackagesPolicy ObjectType = "PACKAGES POLICY"
+ ObjectTypeComputePool ObjectType = "COMPUTE POOL"
)
func (o ObjectType) String() string {
@@ -116,6 +117,7 @@ func objectTypeSingularToPluralMap() map[ObjectType]PluralObjectType {
ObjectTypeExternalVolume: PluralObjectTypeExternalVolumes,
ObjectTypeNetworkRule: PluralObjectTypeNetworkRules,
ObjectTypePackagesPolicy: PluralObjectTypePackagesPolicies,
+ ObjectTypeComputePool: PluralObjectTypeComputePool,
}
}
@@ -210,6 +212,7 @@ const (
PluralObjectTypeExternalVolumes PluralObjectType = "EXTERNAL VOLUMES"
PluralObjectTypeNetworkRules PluralObjectType = "NETWORK RULES"
PluralObjectTypePackagesPolicies PluralObjectType = "PACKAGES POLICIES"
+ PluralObjectTypeComputePool PluralObjectType = "COMPUTE POOLS"
)
func (p PluralObjectType) String() string {
diff --git a/templates/resources/grant_privileges_to_account_role.md.tmpl b/templates/resources/grant_privileges_to_account_role.md.tmpl
new file mode 100644
index 0000000000..f7ec5422b1
--- /dev/null
+++ b/templates/resources/grant_privileges_to_account_role.md.tmpl
@@ -0,0 +1,104 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+~> **Note** This is a preview resource. It's ready for general use. In case of any errors, please file an issue in our GitHub repository.
+
+{{/* SNOW-990811 */}}
+!> **Warning** Be careful when using `always_apply` field. It will always produce a plan (even when no changes were made) and can be harmful in some setups. For more details why we decided to introduce it to go our document explaining those design decisions (coming soon).
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | trimspace }}
+
+{{ if .HasExample -}}
+## Example Usage
+
+{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}}
+{{- end }}
+
+{{ .SchemaMarkdown | trimspace }}
+
+## Import
+
+~> **Note** All the ..._name parts should be fully qualified names, e.g. for schema object it is `""."".""`
+~> **Note** To import all_privileges write ALL or ALL PRIVILEGES in place of ``
+
+Import is supported using the following syntax:
+
+`terraform import "|||||"`
+
+where:
+- account_role_name - fully qualified identifier
+- with_grant_option - boolean
+- always_apply - boolean
+- privileges - list of privileges, comma separated; to import all_privileges write "ALL" or "ALL PRIVILEGES"
+- grant_type - enum
+- grant_data - enum data
+
+It has varying number of parts, depending on grant_type. All the possible types are:
+
+### OnAccount
+`terraform import "||||OnAccount`
+
+### OnAccountObject
+`terraform import "||||OnAccountObject||`
+
+### OnSchema
+
+On schema contains inner types for all options.
+
+#### OnSchema
+`terraform import "||||OnSchema|OnSchema|"`
+
+#### OnAllSchemasInDatabase
+`terraform import "||||OnSchema|OnAllSchemasInDatabase|"`
+
+#### OnFutureSchemasInDatabase
+`terraform import "||||OnSchema|OnFutureSchemasInDatabase|"`
+
+### OnSchemaObject
+
+On schema object contains inner types for all options.
+
+#### OnObject
+`terraform import "||||OnSchemaObject|OnObject||"`
+
+#### OnAll
+
+On all contains inner types for all options.
+
+##### InDatabase
+`terraform import "||||OnSchemaObject|OnAll||InDatabase|"`
+
+##### InSchema
+`terraform import "||||OnSchemaObject|OnAll||InSchema|"`
+
+#### OnFuture
+
+On future contains inner types for all options.
+
+##### InDatabase
+`terraform import "||||OnSchemaObject|OnFuture||InDatabase|"`
+
+##### InSchema
+`terraform import "||||OnSchemaObject|OnFuture||InSchema|"`
+
+### Import examples
+
+#### Grant all privileges OnAccountObject (Database)
+`terraform import "\"test_db_role\"|false|false|ALL|OnAccountObject|DATABASE|\"test_db\""`
+
+#### Grant list of privileges OnAllSchemasInDatabase
+`terraform import "\"test_db_role\"|false|false|CREATE TAG,CREATE TABLE|OnSchema|OnAllSchemasInDatabase|\"test_db\""`
+
+#### Grant list of privileges on table
+`terraform import "\"test_db_role\"|false|false|SELECT,DELETE,INSERT|OnSchemaObject|OnObject|TABLE|\"test_db\".\"test_schema\".\"test_table\""`
+
+#### Grant list of privileges OnAll tables in schema
+`terraform import "\"test_db_role\"|false|false|SELECT,DELETE,INSERT|OnSchemaObject|OnAll|TABLES|InSchema|\"test_db\".\"test_schema\""`
+
diff --git a/templates/resources/grant_privileges_to_database_role.md.tmpl b/templates/resources/grant_privileges_to_database_role.md.tmpl
index 6423a74cab..7c27860ff8 100644
--- a/templates/resources/grant_privileges_to_database_role.md.tmpl
+++ b/templates/resources/grant_privileges_to_database_role.md.tmpl
@@ -6,6 +6,8 @@ description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---
+~> **Note** This is a preview resource. It's ready for general use. In case of any errors, please file an issue in our GitHub repository.
+
{{/* SNOW-990811 */}}
!> **Warning** Be careful when using `always_apply` field. It will always produce a plan (even when no changes were made) and can be harmful in some setups. For more details why we decided to introduce it to go our document explaining those design decisions (coming soon).