From 4420f7bce350accf492badbcce8a18494ee1baf5 Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 11:15:26 +0200 Subject: [PATCH 01/10] Remove password validation --- pkg/resources/managed_account.go | 16 ++++------ pkg/validation/validation.go | 53 ------------------------------- pkg/validation/validation_test.go | 27 ---------------- 3 files changed, 6 insertions(+), 90 deletions(-) diff --git a/pkg/resources/managed_account.go b/pkg/resources/managed_account.go index 3ecdc7cb8e..196d14beca 100644 --- a/pkg/resources/managed_account.go +++ b/pkg/resources/managed_account.go @@ -5,11 +5,8 @@ import ( "fmt" "time" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - - snowflakeValidation "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/validation" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -33,12 +30,11 @@ var managedAccountSchema = map[string]*schema.Schema{ ForceNew: true, }, "admin_password": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - Description: "Password for the initial user in the managed account.", - ValidateFunc: snowflakeValidation.ValidatePassword, - ForceNew: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "Password for the initial user in the managed account. Check [Snowflake-provided password policy](https://docs.snowflake.com/en/user-guide/admin-user-management#snowflake-provided-password-policy).", + ForceNew: true, }, "type": { Type: schema.TypeString, diff --git a/pkg/validation/validation.go b/pkg/validation/validation.go index c8f47f34bb..19f523f06e 100644 --- a/pkg/validation/validation.go +++ b/pkg/validation/validation.go @@ -7,59 +7,6 @@ import ( "unicode" ) -const ( - ascii0 = 48 - ascii9 = 57 - asciiA = 65 - asciiZ = 90 - asciia = 97 - asciiz = 122 -) - -// ValidatePassword checks that your password meets the Snowflake Password Policy -// -// Must be at least 8 characters long. -// Must contain at least 1 digit. -// Must contain at least 1 uppercase letter and 1 lowercase letter. -// lintignore:V011 -func ValidatePassword(i interface{}, k string) (s []string, errs []error) { - pass, ok := i.(string) - if !ok { - return nil, []error{fmt.Errorf("expected type of %s to be string", k)} - } - - if len(pass) < 8 { - errs = append(errs, fmt.Errorf("password must be at least 8 characters long")) - } - - var digit, uppercase, lowercase bool - for _, c := range pass { - if c >= asciiA && c <= asciiZ { - uppercase = true - } - if c >= asciia && c <= asciiz { - lowercase = true - } - if c >= ascii0 && c <= ascii9 { - digit = true - } - } - - if !uppercase { - errs = append(errs, fmt.Errorf("password must contain an uppercase character")) - } - - if !lowercase { - errs = append(errs, fmt.Errorf("password must contain a lowercase character")) - } - - if !digit { - errs = append(errs, fmt.Errorf("password must contain a digit")) - } - - return -} - // ValidateIsNotAccountLocator validates that the account value is not an account locator. Account locators have the // following format: 8 characters where the first 3 characters are letters and the last 5 are digits. ex: ABC12345 // The desired format should be 'organization_name.account_name' ex: testOrgName.testAccName. diff --git a/pkg/validation/validation_test.go b/pkg/validation/validation_test.go index 16f434046b..e9f8815a51 100644 --- a/pkg/validation/validation_test.go +++ b/pkg/validation/validation_test.go @@ -6,33 +6,6 @@ import ( "github.com/stretchr/testify/require" ) -var validPasswords = []string{ - "bob123BOB", - "actually-quite-a-strong-pASSword-90210", -} - -var invalidPasswords = []interface{}{ - "password", - "password123", - "birthday", - "1982", - "alM0st!", - 123, -} - -func TestValidatePassword(t *testing.T) { - r := require.New(t) - for _, p := range validPasswords { - _, errs := ValidatePassword(p, "test_password") - r.Len(errs, 0, "%v failed to validate: %v", p, errs) - } - - for _, p := range invalidPasswords { - _, errs := ValidatePassword(p, "test_password") - r.NotZero(len(errs), "%v should have failed to validate: %v", p, errs) - } -} - var validAccounts = []string{ "testOrg.testAcc", "testingOrg2.testingAcc2", From 39b8c3d5c2763e58ff2c9b150ec6afc09718e7f1 Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 11:37:18 +0200 Subject: [PATCH 02/10] Remove a few remaining validations --- pkg/resources/account.go | 24 +++++------ pkg/resources/database_grant.go | 6 --- pkg/resources/external_table_grant.go | 6 --- pkg/resources/failover_group_grant.go | 6 --- pkg/resources/file_format_grant.go | 6 --- pkg/resources/function_grant.go | 6 --- pkg/resources/integration_grant.go | 6 --- pkg/resources/masking_policy_grant.go | 6 --- pkg/resources/materialized_view_grant.go | 6 --- pkg/resources/pipe_grant.go | 6 --- pkg/resources/procedure_grant.go | 6 --- pkg/resources/role_grants.go | 4 -- pkg/resources/role_ownership_grant.go | 14 ------- pkg/resources/row_access_policy_grant.go | 6 --- pkg/resources/schema_grant.go | 6 --- pkg/resources/sequence_grant.go | 6 --- pkg/resources/stage_grant.go | 6 --- pkg/resources/stream_grant.go | 6 --- pkg/resources/table_grant.go | 6 --- pkg/resources/tag_grant.go | 6 --- pkg/resources/task_grant.go | 6 --- pkg/resources/user_ownership_grant.go | 10 ----- pkg/resources/view_grant.go | 6 --- pkg/resources/warehouse_grant.go | 6 --- pkg/sdk/validation.go | 53 ------------------------ pkg/sdk/validation_test.go | 43 ------------------- pkg/validation/validation.go | 44 -------------------- v1-preparations/REMAINING_GA_OBJECTS.MD | 2 +- 28 files changed, 11 insertions(+), 303 deletions(-) delete mode 100644 pkg/sdk/validation_test.go diff --git a/pkg/resources/account.go b/pkg/resources/account.go index d17a220b35..643d983709 100644 --- a/pkg/resources/account.go +++ b/pkg/resources/account.go @@ -10,7 +10,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - snowflakeValidation "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -20,20 +19,18 @@ import ( var accountSchema = map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - Description: "Specifies the identifier (i.e. name) for the account; must be unique within an organization, regardless of which Snowflake Region the account is in. In addition, the identifier must start with an alphabetic character and cannot contain spaces or special characters except for underscores (_). Note that if the account name includes underscores, features that do not accept account names with underscores (e.g. Okta SSO or SCIM) can reference a version of the account name that substitutes hyphens (-) for the underscores.", - ValidateFunc: snowflakeValidation.ValidateAccountIdentifier, + Type: schema.TypeString, + Required: true, + Description: "Specifies the identifier (i.e. name) for the account; must be unique within an organization, regardless of which Snowflake Region the account is in. In addition, the identifier must start with an alphabetic character and cannot contain spaces or special characters except for underscores (_). Note that if the account name includes underscores, features that do not accept account names with underscores (e.g. Okta SSO or SCIM) can reference a version of the account name that substitutes hyphens (-) for the underscores.", // Name is automatically uppercase by Snowflake StateFunc: func(val interface{}) string { return strings.ToUpper(val.(string)) }, }, "admin_name": { - Type: schema.TypeString, - Required: true, - Description: "Login name of the initial administrative user of the account. A new user is created in the new account with this name and password and granted the ACCOUNTADMIN role in the account. A login name can be any string consisting of letters, numbers, and underscores. Login names are always case-insensitive.", - ValidateFunc: snowflakeValidation.ValidateAdminName, + Type: schema.TypeString, + Required: true, + Description: "Login name of the initial administrative user of the account. A new user is created in the new account with this name and password and granted the ACCOUNTADMIN role in the account. A login name can be any string consisting of letters, numbers, and underscores. Login names are always case-insensitive.", // We have no way of assuming a role into this account to change the admin user name so this has to be ForceNew even though it's not ideal ForceNew: true, DiffSuppressOnRefresh: true, @@ -83,11 +80,10 @@ var accountSchema = map[string]*schema.Schema{ }, }, "email": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - Description: "Email address of the initial administrative user of the account. This email address is used to send any notifications about the account.", - ValidateFunc: snowflakeValidation.ValidateEmail, + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "Email address of the initial administrative user of the account. This email address is used to send any notifications about the account.", // We have no way of assuming a role into this account to change the admin email so this has to be ForceNew even though it's not ideal ForceNew: true, DiffSuppressOnRefresh: true, diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index cf80147dc3..cb851f3ce5 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -70,10 +68,6 @@ var databaseGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go index e83061ca36..601e7b0535 100644 --- a/pkg/resources/external_table_grant.go +++ b/pkg/resources/external_table_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -92,10 +90,6 @@ var externalTableGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/failover_group_grant.go b/pkg/resources/failover_group_grant.go index bfdd6c8938..df32bc419b 100644 --- a/pkg/resources/failover_group_grant.go +++ b/pkg/resources/failover_group_grant.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -61,10 +59,6 @@ var failoverGroupGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index 390dfcf59f..afc098115f 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -6,8 +6,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -88,10 +86,6 @@ var fileFormatGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index 12fd864cbb..03ca88f404 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -100,10 +98,6 @@ var functionGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go index ec79f0b16e..959f104bfb 100644 --- a/pkg/resources/integration_grant.go +++ b/pkg/resources/integration_grant.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -59,10 +57,6 @@ var integrationGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go index 826a531c31..00943bb050 100644 --- a/pkg/resources/masking_policy_grant.go +++ b/pkg/resources/masking_policy_grant.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -71,10 +69,6 @@ var maskingPolicyGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go index d410095adc..6836d4d736 100644 --- a/pkg/resources/materialized_view_grant.go +++ b/pkg/resources/materialized_view_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -98,10 +96,6 @@ var materializedViewGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index 4538c35f82..f7a79ac84d 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -6,8 +6,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -79,10 +77,6 @@ var pipeGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index 924c735073..d646fe7a95 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -100,10 +98,6 @@ var procedureGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go index d3554294c6..e8b151510c 100644 --- a/pkg/resources/role_grants.go +++ b/pkg/resources/role_grants.go @@ -33,10 +33,6 @@ func RoleGrants() *schema.Resource { Required: true, Description: "The name of the role we are granting.", ForceNew: true, - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, "roles": { Type: schema.TypeSet, diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go index 24c0973b89..861e393bb8 100644 --- a/pkg/resources/role_ownership_grant.go +++ b/pkg/resources/role_ownership_grant.go @@ -9,8 +9,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -21,19 +19,11 @@ var roleOwnershipGrantSchema = map[string]*schema.Schema{ Type: schema.TypeString, Required: true, Description: "The name of the role ownership is granted on.", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, "to_role_name": { Type: schema.TypeString, Required: true, Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, "current_grants": { Type: schema.TypeString, @@ -50,10 +40,6 @@ var roleOwnershipGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy.", Default: "ACCOUNTADMIN", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index 957bd0f372..c412631131 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -71,10 +69,6 @@ var rowAccessPolicyGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go index b2751f1e24..ebabaf7cae 100644 --- a/pkg/resources/schema_grant.go +++ b/pkg/resources/schema_grant.go @@ -6,8 +6,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -109,10 +107,6 @@ var schemaGrantSchema = map[string]*schema.Schema{ Type: schema.TypeString, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go index a4d2588f56..f8efc06562 100644 --- a/pkg/resources/sequence_grant.go +++ b/pkg/resources/sequence_grant.go @@ -6,8 +6,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -88,10 +86,6 @@ var sequenceGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go index ef1ab6e58c..c6206e46db 100644 --- a/pkg/resources/stage_grant.go +++ b/pkg/resources/stage_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -91,10 +89,6 @@ var stageGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go index e55cdc31f5..736cce0293 100644 --- a/pkg/resources/stream_grant.go +++ b/pkg/resources/stream_grant.go @@ -6,8 +6,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -88,10 +86,6 @@ var streamGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go index 19df12a6fe..d0a1fb3c8e 100644 --- a/pkg/resources/table_grant.go +++ b/pkg/resources/table_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -98,10 +96,6 @@ var tableGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go index 2ccd733aa0..3d023277a6 100644 --- a/pkg/resources/tag_grant.go +++ b/pkg/resources/tag_grant.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -71,10 +69,6 @@ var tagGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go index 41c0d54783..7db2a0b578 100644 --- a/pkg/resources/task_grant.go +++ b/pkg/resources/task_grant.go @@ -6,8 +6,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -89,10 +87,6 @@ var taskGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/user_ownership_grant.go b/pkg/resources/user_ownership_grant.go index c6708dccbc..1da2460463 100644 --- a/pkg/resources/user_ownership_grant.go +++ b/pkg/resources/user_ownership_grant.go @@ -9,8 +9,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -26,10 +24,6 @@ var userOwnershipGrantSchema = map[string]*schema.Schema{ Type: schema.TypeString, Required: true, Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, "current_grants": { Type: schema.TypeString, @@ -46,10 +40,6 @@ var userOwnershipGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy.", Default: "ACCOUNTADMIN", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go index 7ac1efeea2..8e53a40997 100644 --- a/pkg/resources/view_grant.go +++ b/pkg/resources/view_grant.go @@ -5,8 +5,6 @@ import ( "errors" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -93,10 +91,6 @@ var viewGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go index d850c0452e..f34394b13b 100644 --- a/pkg/resources/warehouse_grant.go +++ b/pkg/resources/warehouse_grant.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -61,10 +59,6 @@ var warehouseGrantSchema = map[string]*schema.Schema{ Optional: true, Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", Default: "", - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, }, } diff --git a/pkg/sdk/validation.go b/pkg/sdk/validation.go index c5654f19fa..1281747374 100644 --- a/pkg/sdk/validation.go +++ b/pkg/sdk/validation.go @@ -1,58 +1,5 @@ package sdk -import "fmt" - -// ValidateIdentifier implements a strict definition of valid identifiers from -// https://docs.snowflake.net/manuals/sql-reference/identifiers-syntax.html -func ValidateIdentifier(val interface{}, exclusions []string) (warns []string, errs []error) { - name, ok := val.(string) - if !ok { - errs = append(errs, fmt.Errorf("unable to assert identifier as string type")) - return - } - - if len(name) == 0 { - errs = append(errs, fmt.Errorf("Identifier must be at least 1 character")) - return - } - - if len(name) > 256 { - errs = append(errs, fmt.Errorf("Identifier must be <= 256 characters")) - return - } - - // TODO handle quoted identifiers - excludedCharacterMap := make(map[string]bool) - for _, char := range exclusions { - excludedCharacterMap[char] = true - } - for k, r := range name { - if k == 0 && !isInitialIdentifierRune(r) { - errs = append(errs, fmt.Errorf("'%s' can not start an identifier", string(r))) - continue - } - - if !isIdentifierRune(r, excludedCharacterMap) { - errs = append(errs, fmt.Errorf("'%s' is not valid identifier character", string(r))) - } - } - return -} - -func isIdentifierRune(r rune, excludedCharacters map[string]bool) bool { - return isInitialIdentifierRune(r) || excludedCharacters[string(r)] || r == '$' || (r >= '0' && r <= '9') -} - -func isInitialIdentifierRune(r rune) bool { - return (r == '_' || - r == '-' || - r == '[' || - r == ']' || - (r >= 'A' && r <= 'Z') || - (r >= 'a' && r <= 'z')) || - (r >= 48 && r <= 57) // 0-9 -} - type DateFormat string const ( diff --git a/pkg/sdk/validation_test.go b/pkg/sdk/validation_test.go deleted file mode 100644 index 63a2b82eec..0000000000 --- a/pkg/sdk/validation_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package sdk_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" -) - -// TODO write a test for a candidate that's not castable to a string. -func TestValidateIdentifier(t *testing.T) { - cases := []struct { - candidate string - valid bool - }{ - {"word", true}, - {"_1", true}, - {"Aword", true}, - {"azAZ09_$", true}, - {"-30-Ab-", true}, - {"invalidcharacter!", false}, - {"1startwithnumber", true}, - {"$startwithdollar", false}, - {"[]includingBracket", true}, - } - - for _, tc := range cases { - tc := tc - t.Run(tc.candidate, func(t *testing.T) { - _, errs := sdk.ValidateIdentifier(tc.candidate, []string{}) - actual := len(errs) == 0 - - if actual == tc.valid { - return - } - - if tc.valid { - t.Fatalf("identifier %s should pass validation", tc.candidate) - } else { - t.Fatalf("identifier %s should fail validation", tc.candidate) - } - }) - } -} diff --git a/pkg/validation/validation.go b/pkg/validation/validation.go index 19f523f06e..81b9f8a183 100644 --- a/pkg/validation/validation.go +++ b/pkg/validation/validation.go @@ -2,7 +2,6 @@ package validation import ( "fmt" - "regexp" "strings" "unicode" ) @@ -41,49 +40,6 @@ func ValidateIsNotAccountLocator(i interface{}, k string) (s []string, errors [] return } -func ValidateAccountIdentifier(i interface{}, k string) (s []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) - return - } - - match, _ := regexp.MatchString(`^[a-zA-Z][a-zA-Z0-9_]*$`, v) - if !match { - errors = append(errors, fmt.Errorf("must start with an alphabetic character and cannot contain spaces or special characters except for underscores (_)")) - } - return -} - -func ValidateEmail(i interface{}, k string) (s []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) - return - } - - match, _ := regexp.MatchString(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`, v) - if !match { - errors = append(errors, fmt.Errorf("must be a valid email address")) - } - return -} - -// ValidateAdminName: A login name can be any string consisting of letters, numbers, and underscores. Login names are always case-insensitive. -func ValidateAdminName(i interface{}, k string) (s []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) - return - } - - match, _ := regexp.MatchString(`^[a-zA-Z0-9_]+$`, v) - if !match { - errors = append(errors, fmt.Errorf("must be a valid admin name")) - } - return -} - func FormatFullyQualifiedObjectID(dbName, schemaName, objectName string) string { var n strings.Builder diff --git a/v1-preparations/REMAINING_GA_OBJECTS.MD b/v1-preparations/REMAINING_GA_OBJECTS.MD index bcb4a147ac..fe6ea6cc2d 100644 --- a/v1-preparations/REMAINING_GA_OBJECTS.MD +++ b/v1-preparations/REMAINING_GA_OBJECTS.MD @@ -30,7 +30,7 @@ Known issues lists open issues touching the given object. Note that some of thes | DYNAMIC TABLE | ❌ | - | | EVENT TABLE | ❌ | [#1888](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1888) | | EXTERNAL FUNCTION | ❌ | [#1901](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1901) | -| EXTERNAL TABLE | ❌ | [#1564](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1564), [#1537](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1537), [#1416](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1416), [#1040](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1040) | +| EXTERNAL TABLE | ❌ | [#2881](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2881), [#1564](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1564), [#1537](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1537), [#1416](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1416), [#1040](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1040) | | FILE FORMAT | ❌ | [#2154](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2154), [#1984](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1984), [#1820](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1820), [#1760](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1760), [#1614](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1614), [#1613](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1613), [#1609](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1609), [#1461](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1461) | | MATERIALIZED VIEW | ❌ | [#2397](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2397), [#1218](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/1218) | | NETWORK RULE | ❌ | [#2593](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2593), [#2482](https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2482) | From a7c10dc3101cc41d333767377afd8f8fc46ff5b4 Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 11:44:45 +0200 Subject: [PATCH 03/10] Remove unused validations --- pkg/sdk/validation.go | 144 ------------------------------------------ 1 file changed, 144 deletions(-) delete mode 100644 pkg/sdk/validation.go diff --git a/pkg/sdk/validation.go b/pkg/sdk/validation.go deleted file mode 100644 index 1281747374..0000000000 --- a/pkg/sdk/validation.go +++ /dev/null @@ -1,144 +0,0 @@ -package sdk - -type DateFormat string - -const ( - DateFormatISO DateFormat = "DateFormatISO" - DateFormatOther DateFormat = "DateFormatOther" - DateFormatAny DateFormat = "DateFormatAny" -) - -func GetValidDateFormats(f DateFormat, includeAuto bool) []string { - ISODateFormats := []string{ - "YYYY-MM-DD", - } - OtherDateFormats := []string{ - "DD-MON-YYYY", - "MM/DD/YYYY", - } - AnyDateFormats := make([]string, 0, len(ISODateFormats)+len(OtherDateFormats)) - AnyDateFormats = append(AnyDateFormats, ISODateFormats...) - AnyDateFormats = append(AnyDateFormats, OtherDateFormats...) - var formats []string - - switch f { - case DateFormatISO: - formats = ISODateFormats - case DateFormatOther: - formats = OtherDateFormats - case DateFormatAny: - formats = AnyDateFormats - } - if includeAuto { - formats = append(formats, "auto") - } - return formats -} - -type TimeFormat string - -const ( - TimeFormatISO TimeFormat = "TimeFormatISO" - TimeFormatRFC TimeFormat = "TimeFormatRFC" - TimeFormatAny TimeFormat = "TimeFormatAny" -) - -func getValidTimeFormats(f TimeFormat, includeAuto bool) []string { - ISOTimeFormats := []string{ - "HH24:MI:SS.FFTZH:TZM", - "HH24:MI:SS.FF", - "HH24:MI:SS", - "HH24:MI", - } - RFCTimeFormats := []string{ - "HH12:MI:SS.FF AM", - "HH12:MI:SS AM", - "HH12:MI AM", - } - AnyTimeFormats := make([]string, 0, len(ISOTimeFormats)+len(RFCTimeFormats)) - AnyTimeFormats = append(AnyTimeFormats, ISOTimeFormats...) - AnyTimeFormats = append(AnyTimeFormats, RFCTimeFormats...) - var formats []string - - switch f { - case TimeFormatISO: - formats = ISOTimeFormats - case TimeFormatRFC: - formats = RFCTimeFormats - case TimeFormatAny: - formats = AnyTimeFormats - } - if includeAuto { - formats = append(formats, "auto") - } - return formats -} - -type TimeStampFormat string - -const ( - TimeStampFormatISO TimeStampFormat = "TimeStampFormatISO" - TimeStampFormatRFC TimeStampFormat = "TimeStampFormatRFC" - TimeStampFormatOther TimeStampFormat = "TimeStampFormatOther" - TimeStampFormatAny TimeStampFormat = "TimeStampFormatAny" -) - -func getValidTimeStampFormats(f TimeStampFormat, includeAuto bool) []string { - ISOTimeStampFormats := []string{ - "YYYY-MM-DD\"T\"HH24:MI:SS.FFTZH:TZM", - "YYYY-MM-DD HH24:MI:SS.FFTZH:TZM", - "YYYY-MM-DD HH24:MI:SS.FFTZH", - "YYYY-MM-DD HH24:MI:SS.FF TZH:TZM", - "YYYY-MM-DD HH24:MI:SS.FF TZHTZM", - "YYYY-MM-DD HH24:MI:SS TZH:TZM", - "YYYY-MM-DD HH24:MI:SS TZHTZM", - "YYYY-MM-DD\"T\"HH24:MI:SS.FF", - "YYYY-MM-DD HH24:MI:SS.FF", - "YYYY-MM-DD\"T\"HH24:MI:SS", - "YYYY-MM-DD HH24:MI:SS", - "YYYY-MM-DD\"T\"HH24:MI", - "YYYY-MM-DD HH24:MI", - "YYYY-MM-DD\"T\"HH24", - "YYYY-MM-DD HH24", - "YYYY-MM-DD\"T\"HH24:MI:SSTZH:TZM", - "YYYY-MM-DD HH24:MI:SSTZH:TZM", - "YYYY-MM-DD HH24:MI:SSTZH", - "YYYY-MM-DD\"T\"HH24:MITZH:TZM", - "YYYY-MM-DD HH24:MITZH:TZM", - } - RFCTimeStampFormats := []string{ - "DY, DD MON YYYY HH24:MI:SS TZHTZM", - "DY, DD MON YYYY HH24:MI:SS.FF TZHTZM", - "DY, DD MON YYYY HH12:MI:SS AM TZHTZM", - "DY, DD MON YYYY HH12:MI:SS.FF AM TZHTZM", - "DY, DD MON YYYY HH24:MI:SS", - "DY, DD MON YYYY HH24:MI:SS.FF", - "DY, DD MON YYYY HH12:MI:SS AM", - "DY, DD MON YYYY HH12:MI:SS.FF AM", - } - OtherTimeStampFormats := []string{ - "MM/DD/YYYY HH24:MI:SS", - "DY MON DD HH24:MI:SS TZHTZM YYYY", - } - AnyTimeStampFormats := make([]string, 0, len(ISOTimeStampFormats)+len(RFCTimeStampFormats)+len(OtherTimeStampFormats)) - AnyTimeStampFormats = append(AnyTimeStampFormats, ISOTimeStampFormats...) - AnyTimeStampFormats = append(AnyTimeStampFormats, RFCTimeStampFormats...) - AnyTimeStampFormats = append(AnyTimeStampFormats, OtherTimeStampFormats...) - - var formats []string - switch f { - case TimeStampFormatISO: - formats = ISOTimeStampFormats - case TimeStampFormatRFC: - formats = RFCTimeStampFormats - case TimeStampFormatOther: - formats = OtherTimeStampFormats - case TimeStampFormatAny: - formats = AnyTimeStampFormats - } - - if includeAuto { - formats = append(formats, "auto") - } - return formats -} From accb3695db4efb3d399adfd37a5c0627a509571f Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 12:16:31 +0200 Subject: [PATCH 04/10] Remove old grant resources --- docs/index.md | 27 - docs/resources/account_grant.md | 43 - docs/resources/database_grant.md | 53 - docs/resources/external_table_grant.md | 61 - docs/resources/failover_group_grant.md | 31 - docs/resources/file_format_grant.md | 58 - docs/resources/function_grant.md | 60 - docs/resources/grant_ownership.md | 1 - .../grant_privileges_to_account_role.md | 2 - .../grant_privileges_to_database_role.md | 2 - docs/resources/grant_privileges_to_role.md | 256 ---- docs/resources/grant_privileges_to_share.md | 2 - docs/resources/integration_grant.md | 51 - docs/resources/managed_account.md | 2 +- docs/resources/masking_policy_grant.md | 54 - docs/resources/materialized_view_grant.md | 61 - docs/resources/pipe_grant.md | 57 - docs/resources/procedure_grant.md | 60 - docs/resources/resource_monitor_grant.md | 48 - docs/resources/role_grants.md | 72 - docs/resources/role_ownership_grant.md | 64 - docs/resources/row_access_policy_grant.md | 55 - docs/resources/schema_grant.md | 58 - docs/resources/sequence_grant.md | 58 - docs/resources/stage_grant.md | 59 - docs/resources/stream_grant.md | 58 - docs/resources/table_grant.md | 60 - docs/resources/tag_grant.md | 53 - docs/resources/task_grant.md | 58 - docs/resources/user_grant.md | 50 - docs/resources/user_ownership_grant.md | 29 - docs/resources/view_grant.md | 74 -- docs/resources/warehouse_grant.md | 51 - examples/additional/deprecated_resources.MD | 27 - .../snowflake_account_grant/import.sh | 2 - .../snowflake_account_grant/resource.tf | 5 - .../snowflake_database_grant/import.sh | 2 - .../snowflake_database_grant/resource.tf | 9 - .../snowflake_external_table_grant/import.sh | 2 - .../resource.tf | 13 - .../snowflake_file_format_grant/import.sh | 2 - .../snowflake_file_format_grant/resource.tf | 11 - .../snowflake_function_grant/import.sh | 2 - .../snowflake_function_grant/resource.tf | 11 - .../import.sh | 2 - .../resource.tf | 157 --- .../snowflake_integration_grant/import.sh | 3 - .../snowflake_integration_grant/resource.tf | 8 - .../snowflake_masking_policy_grant/import.sh | 3 - .../resource.tf | 9 - .../import.sh | 3 - .../resource.tf | 13 - .../resources/snowflake_pipe_grant/import.sh | 2 - .../snowflake_pipe_grant/resource.tf | 11 - .../snowflake_procedure_grant/import.sh | 2 - .../snowflake_procedure_grant/resource.tf | 11 - .../import.sh | 2 - .../resource.tf | 6 - .../resources/snowflake_role_grants/import.sh | 2 - .../snowflake_role_grants/resource.tf | 31 - .../import.sh | 2 - .../resource.tf | 10 - .../snowflake_schema_grant/import.sh | 2 - .../snowflake_schema_grant/resource.tf | 11 - .../snowflake_sequence_grant/import.sh | 2 - .../snowflake_sequence_grant/resource.tf | 11 - .../resources/snowflake_stage_grant/import.sh | 2 - .../snowflake_stage_grant/resource.tf | 12 - .../snowflake_stream_grant/import.sh | 2 - .../snowflake_stream_grant/resource.tf | 11 - .../resources/snowflake_table_grant/import.sh | 2 - .../snowflake_table_grant/resource.tf | 12 - .../resources/snowflake_tag_grant/import.sh | 2 - .../resources/snowflake_tag_grant/resource.tf | 8 - .../resources/snowflake_task_grant/import.sh | 2 - .../snowflake_task_grant/resource.tf | 11 - .../resources/snowflake_user_grant/import.sh | 2 - .../snowflake_user_grant/resource.tf | 8 - .../resources/snowflake_view_grant/import.sh | 2 - .../snowflake_view_grant/resource.tf | 26 - .../snowflake_warehouse_grant/import.sh | 2 - .../snowflake_warehouse_grant/resource.tf | 8 - framework/provider/provider_helpers.go | 11 - pkg/provider/provider.go | 45 +- pkg/resources/account_grant.go | 185 --- .../account_grant_acceptance_test.go | 125 -- pkg/resources/account_grant_test.go | 139 -- pkg/resources/database_grant.go | 231 ---- .../database_grant_acceptance_test.go | 124 -- pkg/resources/database_grant_test.go | 97 -- pkg/resources/deprecated_helpers_test.go | 201 +-- pkg/resources/external_table_grant.go | 301 ----- .../external_table_grant_acceptance_test.go | 105 -- pkg/resources/external_table_grant_test.go | 195 --- pkg/resources/failover_group_grant.go | 184 --- .../failover_group_grant_acceptance_test.go | 73 -- pkg/resources/file_format_grant.go | 282 ---- .../file_format_grant_acceptance_test.go | 163 --- pkg/resources/file_format_grant_test.go | 164 --- pkg/resources/function_grant.go | 321 ----- .../function_grant_acceptance_test.go | 117 -- pkg/resources/grant_helpers.go | 393 +----- pkg/resources/grant_privileges_to_role.go | 895 ------------- ...rant_privileges_to_role_acceptance_test.go | 1164 ----------------- pkg/resources/integration_grant.go | 183 --- pkg/resources/integration_grant_test.go | 80 -- pkg/resources/masking_policy_grant.go | 213 --- .../masking_policy_grant_acceptance_test.go | 87 -- pkg/resources/masking_policy_grant_test.go | 86 -- pkg/resources/materialized_view_grant.go | 316 ----- ...materialized_view_grant_acceptance_test.go | 104 -- pkg/resources/materialized_view_grant_test.go | 197 --- pkg/resources/pipe_grant.go | 266 ---- pkg/resources/pipe_grant_acceptance_test.go | 188 --- pkg/resources/pipe_grant_test.go | 164 --- pkg/resources/procedure_grant.go | 323 ----- .../procedure_grant_acceptance_test.go | 103 -- pkg/resources/resource_monitor_grant.go | 176 --- .../resource_monitor_grant_acceptance_test.go | 61 - pkg/resources/resource_monitor_grant_test.go | 80 -- pkg/resources/role_grants.go | 329 ----- pkg/resources/role_grants_acceptance_test.go | 246 ---- pkg/resources/role_grants_internal_test.go | 63 - pkg/resources/role_grants_test.go | 140 -- pkg/resources/role_ownership_grant.go | 151 --- .../role_ownership_grant_acceptance_test.go | 64 - pkg/resources/role_ownership_grant_test.go | 92 -- pkg/resources/row_access_policy_grant.go | 218 --- ...row_access_policy_grant_acceptance_test.go | 83 -- pkg/resources/row_access_policy_grant_test.go | 86 -- pkg/resources/schema_grant.go | 317 ----- pkg/resources/schema_grant_acceptance_test.go | 117 -- pkg/resources/schema_grant_test.go | 148 --- pkg/resources/sequence_grant.go | 282 ---- .../sequence_grant_acceptance_test.go | 103 -- pkg/resources/sequence_grant_test.go | 164 --- pkg/resources/stage_grant.go | 290 ---- pkg/resources/stage_grant_acceptance_test.go | 155 --- pkg/resources/stage_grant_test.go | 168 --- pkg/resources/stream_grant.go | 282 ---- pkg/resources/stream_grant_acceptance_test.go | 178 --- pkg/resources/stream_grant_test.go | 164 --- pkg/resources/table_grant.go | 326 ----- pkg/resources/table_grant_acceptance_test.go | 177 --- pkg/resources/table_grant_test.go | 216 --- pkg/resources/tag_grant.go | 216 --- pkg/resources/tag_grant_acceptance_test.go | 79 -- pkg/resources/tag_grant_test.go | 86 -- pkg/resources/task_grant.go | 281 ---- pkg/resources/task_grant_acceptance_test.go | 274 ---- pkg/resources/task_grant_test.go | 164 --- pkg/resources/user_grant.go | 180 --- pkg/resources/user_grant_acceptance_test.go | 70 - pkg/resources/user_grant_test.go | 56 - pkg/resources/user_ownership_grant.go | 158 --- .../user_ownership_grant_acceptance_test.go | 64 - pkg/resources/user_ownership_grant_test.go | 108 -- pkg/resources/view_grant.go | 303 ----- pkg/resources/view_grant_acceptance_test.go | 242 ---- pkg/resources/view_grant_test.go | 187 --- pkg/resources/warehouse_grant.go | 193 --- .../warehouse_grant_acceptance_test.go | 70 - pkg/resources/warehouse_grant_test.go | 56 - templates/resources/grant_ownership.md.tmpl | 1 - .../grant_privileges_to_account_role.md.tmpl | 2 - .../grant_privileges_to_database_role.md.tmpl | 2 - .../grant_privileges_to_share.md.tmpl | 2 - 167 files changed, 7 insertions(+), 17717 deletions(-) delete mode 100644 docs/resources/account_grant.md delete mode 100644 docs/resources/database_grant.md delete mode 100644 docs/resources/external_table_grant.md delete mode 100644 docs/resources/failover_group_grant.md delete mode 100644 docs/resources/file_format_grant.md delete mode 100644 docs/resources/function_grant.md delete mode 100644 docs/resources/grant_privileges_to_role.md delete mode 100644 docs/resources/integration_grant.md delete mode 100644 docs/resources/masking_policy_grant.md delete mode 100644 docs/resources/materialized_view_grant.md delete mode 100644 docs/resources/pipe_grant.md delete mode 100644 docs/resources/procedure_grant.md delete mode 100644 docs/resources/resource_monitor_grant.md delete mode 100644 docs/resources/role_grants.md delete mode 100644 docs/resources/role_ownership_grant.md delete mode 100644 docs/resources/row_access_policy_grant.md delete mode 100644 docs/resources/schema_grant.md delete mode 100644 docs/resources/sequence_grant.md delete mode 100644 docs/resources/stage_grant.md delete mode 100644 docs/resources/stream_grant.md delete mode 100644 docs/resources/table_grant.md delete mode 100644 docs/resources/tag_grant.md delete mode 100644 docs/resources/task_grant.md delete mode 100644 docs/resources/user_grant.md delete mode 100644 docs/resources/user_ownership_grant.md delete mode 100644 docs/resources/view_grant.md delete mode 100644 docs/resources/warehouse_grant.md delete mode 100644 examples/resources/snowflake_account_grant/import.sh delete mode 100644 examples/resources/snowflake_account_grant/resource.tf delete mode 100644 examples/resources/snowflake_database_grant/import.sh delete mode 100644 examples/resources/snowflake_database_grant/resource.tf delete mode 100644 examples/resources/snowflake_external_table_grant/import.sh delete mode 100644 examples/resources/snowflake_external_table_grant/resource.tf delete mode 100644 examples/resources/snowflake_file_format_grant/import.sh delete mode 100644 examples/resources/snowflake_file_format_grant/resource.tf delete mode 100644 examples/resources/snowflake_function_grant/import.sh delete mode 100644 examples/resources/snowflake_function_grant/resource.tf delete mode 100644 examples/resources/snowflake_grant_privileges_to_role/import.sh delete mode 100644 examples/resources/snowflake_grant_privileges_to_role/resource.tf delete mode 100644 examples/resources/snowflake_integration_grant/import.sh delete mode 100644 examples/resources/snowflake_integration_grant/resource.tf delete mode 100644 examples/resources/snowflake_masking_policy_grant/import.sh delete mode 100644 examples/resources/snowflake_masking_policy_grant/resource.tf delete mode 100644 examples/resources/snowflake_materialized_view_grant/import.sh delete mode 100644 examples/resources/snowflake_materialized_view_grant/resource.tf delete mode 100644 examples/resources/snowflake_pipe_grant/import.sh delete mode 100644 examples/resources/snowflake_pipe_grant/resource.tf delete mode 100644 examples/resources/snowflake_procedure_grant/import.sh delete mode 100644 examples/resources/snowflake_procedure_grant/resource.tf delete mode 100644 examples/resources/snowflake_resource_monitor_grant/import.sh delete mode 100644 examples/resources/snowflake_resource_monitor_grant/resource.tf delete mode 100644 examples/resources/snowflake_role_grants/import.sh delete mode 100644 examples/resources/snowflake_role_grants/resource.tf delete mode 100644 examples/resources/snowflake_row_access_policy_grant/import.sh delete mode 100644 examples/resources/snowflake_row_access_policy_grant/resource.tf delete mode 100644 examples/resources/snowflake_schema_grant/import.sh delete mode 100644 examples/resources/snowflake_schema_grant/resource.tf delete mode 100644 examples/resources/snowflake_sequence_grant/import.sh delete mode 100644 examples/resources/snowflake_sequence_grant/resource.tf delete mode 100644 examples/resources/snowflake_stage_grant/import.sh delete mode 100644 examples/resources/snowflake_stage_grant/resource.tf delete mode 100644 examples/resources/snowflake_stream_grant/import.sh delete mode 100644 examples/resources/snowflake_stream_grant/resource.tf delete mode 100644 examples/resources/snowflake_table_grant/import.sh delete mode 100644 examples/resources/snowflake_table_grant/resource.tf delete mode 100644 examples/resources/snowflake_tag_grant/import.sh delete mode 100644 examples/resources/snowflake_tag_grant/resource.tf delete mode 100644 examples/resources/snowflake_task_grant/import.sh delete mode 100644 examples/resources/snowflake_task_grant/resource.tf delete mode 100644 examples/resources/snowflake_user_grant/import.sh delete mode 100644 examples/resources/snowflake_user_grant/resource.tf delete mode 100644 examples/resources/snowflake_view_grant/import.sh delete mode 100644 examples/resources/snowflake_view_grant/resource.tf delete mode 100644 examples/resources/snowflake_warehouse_grant/import.sh delete mode 100644 examples/resources/snowflake_warehouse_grant/resource.tf delete mode 100644 pkg/resources/account_grant.go delete mode 100644 pkg/resources/account_grant_acceptance_test.go delete mode 100644 pkg/resources/account_grant_test.go delete mode 100644 pkg/resources/database_grant.go delete mode 100644 pkg/resources/database_grant_acceptance_test.go delete mode 100644 pkg/resources/database_grant_test.go delete mode 100644 pkg/resources/external_table_grant.go delete mode 100644 pkg/resources/external_table_grant_acceptance_test.go delete mode 100644 pkg/resources/external_table_grant_test.go delete mode 100644 pkg/resources/failover_group_grant.go delete mode 100644 pkg/resources/failover_group_grant_acceptance_test.go delete mode 100644 pkg/resources/file_format_grant.go delete mode 100644 pkg/resources/file_format_grant_acceptance_test.go delete mode 100644 pkg/resources/file_format_grant_test.go delete mode 100644 pkg/resources/function_grant.go delete mode 100644 pkg/resources/function_grant_acceptance_test.go delete mode 100644 pkg/resources/grant_privileges_to_role.go delete mode 100644 pkg/resources/grant_privileges_to_role_acceptance_test.go delete mode 100644 pkg/resources/integration_grant.go delete mode 100644 pkg/resources/integration_grant_test.go delete mode 100644 pkg/resources/masking_policy_grant.go delete mode 100644 pkg/resources/masking_policy_grant_acceptance_test.go delete mode 100644 pkg/resources/masking_policy_grant_test.go delete mode 100644 pkg/resources/materialized_view_grant.go delete mode 100644 pkg/resources/materialized_view_grant_acceptance_test.go delete mode 100644 pkg/resources/materialized_view_grant_test.go delete mode 100644 pkg/resources/pipe_grant.go delete mode 100644 pkg/resources/pipe_grant_acceptance_test.go delete mode 100644 pkg/resources/pipe_grant_test.go delete mode 100644 pkg/resources/procedure_grant.go delete mode 100644 pkg/resources/procedure_grant_acceptance_test.go delete mode 100644 pkg/resources/resource_monitor_grant.go delete mode 100644 pkg/resources/resource_monitor_grant_acceptance_test.go delete mode 100644 pkg/resources/resource_monitor_grant_test.go delete mode 100644 pkg/resources/role_grants.go delete mode 100644 pkg/resources/role_grants_acceptance_test.go delete mode 100644 pkg/resources/role_grants_internal_test.go delete mode 100644 pkg/resources/role_grants_test.go delete mode 100644 pkg/resources/role_ownership_grant.go delete mode 100644 pkg/resources/role_ownership_grant_acceptance_test.go delete mode 100644 pkg/resources/role_ownership_grant_test.go delete mode 100644 pkg/resources/row_access_policy_grant.go delete mode 100644 pkg/resources/row_access_policy_grant_acceptance_test.go delete mode 100644 pkg/resources/row_access_policy_grant_test.go delete mode 100644 pkg/resources/schema_grant.go delete mode 100644 pkg/resources/schema_grant_acceptance_test.go delete mode 100644 pkg/resources/schema_grant_test.go delete mode 100644 pkg/resources/sequence_grant.go delete mode 100644 pkg/resources/sequence_grant_acceptance_test.go delete mode 100644 pkg/resources/sequence_grant_test.go delete mode 100644 pkg/resources/stage_grant.go delete mode 100644 pkg/resources/stage_grant_acceptance_test.go delete mode 100644 pkg/resources/stage_grant_test.go delete mode 100644 pkg/resources/stream_grant.go delete mode 100644 pkg/resources/stream_grant_acceptance_test.go delete mode 100644 pkg/resources/stream_grant_test.go delete mode 100644 pkg/resources/table_grant.go delete mode 100644 pkg/resources/table_grant_acceptance_test.go delete mode 100644 pkg/resources/table_grant_test.go delete mode 100644 pkg/resources/tag_grant.go delete mode 100644 pkg/resources/tag_grant_acceptance_test.go delete mode 100644 pkg/resources/tag_grant_test.go delete mode 100644 pkg/resources/task_grant.go delete mode 100644 pkg/resources/task_grant_acceptance_test.go delete mode 100644 pkg/resources/task_grant_test.go delete mode 100644 pkg/resources/user_grant.go delete mode 100644 pkg/resources/user_grant_acceptance_test.go delete mode 100644 pkg/resources/user_grant_test.go delete mode 100644 pkg/resources/user_ownership_grant.go delete mode 100644 pkg/resources/user_ownership_grant_acceptance_test.go delete mode 100644 pkg/resources/user_ownership_grant_test.go delete mode 100644 pkg/resources/view_grant.go delete mode 100644 pkg/resources/view_grant_acceptance_test.go delete mode 100644 pkg/resources/view_grant_test.go delete mode 100644 pkg/resources/warehouse_grant.go delete mode 100644 pkg/resources/warehouse_grant_acceptance_test.go delete mode 100644 pkg/resources/warehouse_grant_test.go diff --git a/docs/index.md b/docs/index.md index 6ed5bb38de..a2e8c0ec88 100644 --- a/docs/index.md +++ b/docs/index.md @@ -229,35 +229,8 @@ The Snowflake provider will use the following order of precedence when determini ## Currently deprecated resources -- [snowflake_account_grant](./docs/resources/account_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_database_grant](./docs/resources/database_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead - [snowflake_database_old](./docs/resources/database_old) -- [snowflake_external_table_grant](./docs/resources/external_table_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_failover_group_grant](./docs/resources/failover_group_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_file_format_grant](./docs/resources/file_format_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_function_grant](./docs/resources/function_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_grant_privileges_to_role](./docs/resources/grant_privileges_to_role) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_integration_grant](./docs/resources/integration_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_masking_policy_grant](./docs/resources/masking_policy_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_materialized_view_grant](./docs/resources/materialized_view_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_pipe_grant](./docs/resources/pipe_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_procedure_grant](./docs/resources/procedure_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_resource_monitor_grant](./docs/resources/resource_monitor_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_role_grants](./docs/resources/role_grants) - use [snowflake_grant_account_role](./docs/resources/grant_account_role) instead -- [snowflake_role_ownership_grant](./docs/resources/role_ownership_grant) - use [snowflake_grant_ownership](./docs/resources/grant_ownership) instead -- [snowflake_row_access_policy_grant](./docs/resources/row_access_policy_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_schema_grant](./docs/resources/schema_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_sequence_grant](./docs/resources/sequence_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_stage_grant](./docs/resources/stage_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_stream_grant](./docs/resources/stream_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_table_grant](./docs/resources/table_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_tag_grant](./docs/resources/tag_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_task_grant](./docs/resources/task_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead - [snowflake_unsafe_execute](./docs/resources/unsafe_execute) -- [snowflake_user_grant](./docs/resources/user_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_user_ownership_grant](./docs/resources/user_ownership_grant) - use [snowflake_grant_ownership](./docs/resources/grant_ownership) instead -- [snowflake_view_grant](./docs/resources/view_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_warehouse_grant](./docs/resources/warehouse_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead ## Currently deprecated datasources diff --git a/docs/resources/account_grant.md b/docs/resources/account_grant.md deleted file mode 100644 index 868caef4a1..0000000000 --- a/docs/resources/account_grant.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -page_title: "snowflake_account_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_account_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_account_grant" "grant" { - roles = ["role1", "role2"] - privilege = "CREATE ROLE" - with_grant_option = false -} -``` - - -## Schema - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The account privilege to grant. Valid privileges are those in [globalPrivileges](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege.html). To grant all privileges, use the value `ALL PRIVILEGES`. -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is privilege|with_grant_option|roles -terraform import snowflake_account_grant.example "privilege|false|role1,role2" -``` diff --git a/docs/resources/database_grant.md b/docs/resources/database_grant.md deleted file mode 100644 index 870382b2b9..0000000000 --- a/docs/resources/database_grant.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -page_title: "snowflake_database_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_database_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_database_grant" "grant" { - database_name = "database" - - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the database. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `shares` (Set of String) Grants privilege to these shares. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|privilege|with_grant_option|roles|shares -terraform import snowflake_database_grant.example "MY_DATABASE|USAGE|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/external_table_grant.md b/docs/resources/external_table_grant.md deleted file mode 100644 index 336f64d47e..0000000000 --- a/docs/resources/external_table_grant.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -page_title: "snowflake_external_table_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_external_table_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_external_table_grant" "grant" { - database_name = "database" - schema_name = "schema" - external_table_name = "external_table" - - privilege = "SELECT" - roles = ["role1", "role2"] - - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future external tables on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `external_table_name` (String) The name of the external table on which to grant privileges immediately (only valid if on_future is false). -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all external tables in the given schema. When this is true and no schema_name is provided apply this grant on all external tables in the given database. The external_table_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future external tables in the given schema. When this is true and no schema_name is provided apply this grant on all future external tables in the given database. The external_table_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future external table. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future external tables on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future is false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database|schema|external_table|privilege|with_grant_option|on_future|roles|shares -terraform import snowflake_external_table_grant.example "MY_DATABASE|MY_SCHEMA|MY_TABLE_NAME|SELECT|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/failover_group_grant.md b/docs/resources/failover_group_grant.md deleted file mode 100644 index f7bd8a703e..0000000000 --- a/docs/resources/failover_group_grant.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -page_title: "snowflake_failover_group_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_failover_group_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - - - - -## Schema - -### Required - -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `failover_group_name` (String) The name of the failover group on which to grant privileges. -- `privilege` (String) The privilege to grant on the failover group. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. diff --git a/docs/resources/file_format_grant.md b/docs/resources/file_format_grant.md deleted file mode 100644 index fc4eba3ea8..0000000000 --- a/docs/resources/file_format_grant.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -page_title: "snowflake_file_format_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_file_format_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_file_format_grant" "grant" { - database_name = "database" - schema_name = "schema" - file_format_name = "file_format" - - privilege = "SELECT" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future file formats on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `file_format_name` (String) The name of the file format on which to grant privileges immediately (only valid if on_future is false). -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all file formats in the given schema. When this is true and no schema_name is provided apply this grant on all file formats in the given database. The file_format_name field must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future file formats in the given schema. When this is true and no schema_name is provided apply this grant on all future file formats in the given database. The file_format_name field must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future file format. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future file formats on which to grant privileges. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|file_format_name|privilege|with_grant_option|on_future|roles -terraform import snowflake_file_format_grant.example "MY_DATABASE|MY_SCHEMA|MY_FILE_FORMAT|USAGE|false|false|role1,role2' -``` diff --git a/docs/resources/function_grant.md b/docs/resources/function_grant.md deleted file mode 100644 index aa22a79252..0000000000 --- a/docs/resources/function_grant.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -page_title: "snowflake_function_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_function_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_function_grant" "grant" { - database_name = "database" - schema_name = "schema" - function_name = "function" - argument_data_types = ["array", "string"] - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future functions on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `argument_data_types` (List of String) List of the argument data types for the function (must be present if function has arguments and function_name is present) -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `function_name` (String) The name of the function on which to grant privileges immediately (only valid if on_future is false). -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all functions in the given schema. When this is true and no schema_name is provided apply this grant on all functions in the given database. The function_name, arguments, return_type, and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future functions in the given schema. When this is true and no schema_name is provided apply this grant on all future functions in the given database. The function_name, arguments, return_type, and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future function. Must be one of `USAGE` or `OWNERSHIP`. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future functions on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future is false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|function_name|argument_data_types|privilege|with_grant_option|on_future|roles|shares -terraform import snowflake_function_grant.example "MY_DATABASE|MY_SCHEMA|MY_FUNCTION|ARG1TYPE,ARG2TYPE|USAGE|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/grant_ownership.md b/docs/resources/grant_ownership.md index 15b27978d5..04daa50dbc 100644 --- a/docs/resources/grant_ownership.md +++ b/docs/resources/grant_ownership.md @@ -6,7 +6,6 @@ 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. ~> **Note** For more details about granting ownership, please visit [`GRANT OWNERSHIP` Snowflake documentation page](https://docs.snowflake.com/en/sql-reference/sql/grant-ownership). !> **Warning** Grant ownership resource still has some limitations. Delete operation is not implemented for on_future grants (you have to remove the config and then revoke ownership grant on future X manually). diff --git a/docs/resources/grant_privileges_to_account_role.md b/docs/resources/grant_privileges_to_account_role.md index e2e56f94c7..4d9ea595e5 100644 --- a/docs/resources/grant_privileges_to_account_role.md +++ b/docs/resources/grant_privileges_to_account_role.md @@ -6,8 +6,6 @@ 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). diff --git a/docs/resources/grant_privileges_to_database_role.md b/docs/resources/grant_privileges_to_database_role.md index 55cffdf690..0e412deff4 100644 --- a/docs/resources/grant_privileges_to_database_role.md +++ b/docs/resources/grant_privileges_to_database_role.md @@ -6,8 +6,6 @@ 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). diff --git a/docs/resources/grant_privileges_to_role.md b/docs/resources/grant_privileges_to_role.md deleted file mode 100644 index 3bb479384b..0000000000 --- a/docs/resources/grant_privileges_to_role.md +++ /dev/null @@ -1,256 +0,0 @@ ---- -page_title: "snowflake_grant_privileges_to_role Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_grant_privileges_to_role (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -################################## -### global privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g1" { - privileges = ["MODIFY", "USAGE"] - role_name = snowflake_role.r.name - on_account = true -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g2" { - role_name = snowflake_role.r.name - on_account = true - all_privileges = true - with_grant_option = true -} - -################################## -### account object privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g3" { - privileges = ["CREATE", "MONITOR"] - role_name = snowflake_role.r.name - on_account_object { - object_type = "DATABASE" - object_name = snowflake_database.d.name - } -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g4" { - role_name = snowflake_role.r.name - on_account_object { - object_type = "DATABASE" - object_name = snowflake_database.d.name - } - all_privileges = true - with_grant_option = true -} - -################################## -### schema privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g5" { - privileges = ["MODIFY", "CREATE TABLE"] - role_name = snowflake_role.r.name - on_schema { - schema_name = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g6" { - role_name = snowflake_role.r.name - on_schema { - schema_name = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } - all_privileges = true - with_grant_option = true -} - -# all schemas in database -resource "snowflake_grant_privileges_to_role" "g7" { - privileges = ["MODIFY", "CREATE TABLE"] - role_name = snowflake_role.r.name - on_schema { - all_schemas_in_database = snowflake_database.d.name - } -} - -# future schemas in database -resource "snowflake_grant_privileges_to_role" "g8" { - privileges = ["MODIFY", "CREATE TABLE"] - role_name = snowflake_role.r.name - on_schema { - future_schemas_in_database = snowflake_database.d.name - } -} - -################################## -### schema object privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g9" { - privileges = ["SELECT", "REFERENCES"] - role_name = snowflake_role.r.name - on_schema_object { - object_type = "VIEW" - object_name = "\"my_db\".\"my_schema\".\"my_view\"" # note this is a fully qualified name! - } -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g10" { - role_name = snowflake_role.r.name - on_schema_object { - object_type = "VIEW" - object_name = "\"my_db\".\"my_schema\".\"my_view\"" # note this is a fully qualified name! - } - all_privileges = true - with_grant_option = true -} - -# all in database -resource "snowflake_grant_privileges_to_role" "g11" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - all { - object_type_plural = "TABLES" - in_database = snowflake_database.d.name - } - } -} - -# all in schema -resource "snowflake_grant_privileges_to_role" "g12" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - all { - object_type_plural = "TABLES" - in_schema = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } - } -} - -# future in database -resource "snowflake_grant_privileges_to_role" "g13" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - future { - object_type_plural = "TABLES" - in_database = snowflake_database.d.name - } - } -} - -# future in schema -resource "snowflake_grant_privileges_to_role" "g14" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - future { - object_type_plural = "TABLES" - in_schema = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } - } -} -``` - - -## Schema - -### Required - -- `role_name` (String) The fully qualified name of the role to which privileges will be granted. - -### Optional - -- `all_privileges` (Boolean) Grant all privileges on the account role. -- `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 | 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 eihter 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 future objects in eihter 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: AGGREGATION POLICY | ALERT | AUTHENTICATION POLICY | DATA METRIC FUNCTION | DYNAMIC TABLE | EVENT TABLE | EXTERNAL TABLE | FILE FORMAT | FUNCTION | GIT REPOSITORY | HYBRID TABLE | IMAGE REPOSITORY | ICEBERG TABLE | MASKING POLICY | MATERIALIZED VIEW | MODEL | NETWORK RULE | PACKAGES POLICY | PASSWORD POLICY | PIPE | PROCEDURE | PROJECTION POLICY | ROW ACCESS POLICY | SECRET | SERVICE | SESSION POLICY | SEQUENCE | STAGE | STREAM | TABLE | TAG | TASK | VIEW | STREAMLIT - - -### 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: AGGREGATION POLICIES | ALERTS | AUTHENTICATION POLICIES | DATA METRIC FUNCTIONS | DYNAMIC TABLES | EVENT TABLES | EXTERNAL TABLES | FILE FORMATS | FUNCTIONS | GIT REPOSITORIES | HYBRID TABLES | IMAGE REPOSITORIES | ICEBERG TABLES | MASKING POLICIES | MATERIALIZED VIEWS | MODELS | NETWORK RULES | PACKAGES POLICIES | PASSWORD POLICIES | PIPES | PROCEDURES | PROJECTION POLICIES | ROW ACCESS POLICIES | SECRETS | SERVICES | SESSION POLICIES | SEQUENCES | STAGES | STREAMS | TABLES | TAGS | TASKS | VIEWS | STREAMLITS - -Optional: - -- `in_database` (String) The fully qualified name of the database. -- `in_schema` (String) The fully qualified name of the schema. - - - -### 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 | AUTHENTICATION POLICIES | DATA METRIC FUNCTIONS | DYNAMIC TABLES | EVENT TABLES | EXTERNAL TABLES | FILE FORMATS | FUNCTIONS | GIT REPOSITORIES | HYBRID TABLES | ICEBERG TABLES | MATERIALIZED VIEWS | MODELS | NETWORK RULES | PASSWORD POLICIES | PIPES | PROCEDURES | SECRETS | SERVICES | SEQUENCES | STAGES | STREAMS | TABLES | TASKS | VIEWS - -Optional: - -- `in_database` (String) The fully qualified name of the database. -- `in_schema` (String) The fully qualified name of the schema. - -## Import - -Import is supported using the following syntax: - -```shell -# format is role_name (string) | privileges (comma-delimited string) | all_privileges (bool) |with_grant_option (bool) | on_account (bool) | on_account_object (bool) | on_schema (bool) | on_schema_object (bool) | all (bool) | future (bool) | object_type (string) | object_name (string) | object_type_plural (string) | in_schema (bool) | schema_name (string) | in_database (bool) | database_name (string) -terraform import "test_role|MANAGE GRANTS,MONITOR USAGE|false|false|true|false|false|false|false|false||||false||false|" -``` diff --git a/docs/resources/grant_privileges_to_share.md b/docs/resources/grant_privileges_to_share.md index 6fa78c3e08..cece122b27 100644 --- a/docs/resources/grant_privileges_to_share.md +++ b/docs/resources/grant_privileges_to_share.md @@ -6,8 +6,6 @@ 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. - # snowflake_grant_privileges_to_share (Resource) diff --git a/docs/resources/integration_grant.md b/docs/resources/integration_grant.md deleted file mode 100644 index 299e16dfe2..0000000000 --- a/docs/resources/integration_grant.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -page_title: "snowflake_integration_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_integration_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_integration_grant" "grant" { - integration_name = "integration" - - privilege = "USAGE" - roles = ["role1", "role2"] - - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `integration_name` (String) Identifier for the integration; must be unique for your account. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the integration. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is integration_name|privilege|with_grant_option|roles -terraform import snowflake_integration_grant.example "MY_INTEGRATION|USAGE|false|role1,role2" -``` diff --git a/docs/resources/managed_account.md b/docs/resources/managed_account.md index f214cb56c7..00912bc7b4 100644 --- a/docs/resources/managed_account.md +++ b/docs/resources/managed_account.md @@ -30,7 +30,7 @@ resource "snowflake_managed_account" "account" { ### Required - `admin_name` (String) Identifier, as well as login name, for the initial user in the managed account. This user serves as the account administrator for the account. -- `admin_password` (String, Sensitive) Password for the initial user in the managed account. +- `admin_password` (String, Sensitive) Password for the initial user in the managed account. Check [Snowflake-provided password policy](https://docs.snowflake.com/en/user-guide/admin-user-management#snowflake-provided-password-policy). - `name` (String) Identifier for the managed account; must be unique for your account. ### Optional diff --git a/docs/resources/masking_policy_grant.md b/docs/resources/masking_policy_grant.md deleted file mode 100644 index 4fe2cc4472..0000000000 --- a/docs/resources/masking_policy_grant.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -page_title: "snowflake_masking_policy_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_masking_policy_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_masking_policy_grant" "example" { - masking_policy_name = "EXAMPLE_MASKING_POLICY_NAME" - database_name = "EXAMPLE_DB_NAME" - schema_name = "EXAMPLE_SCHEMA_NAME" - privilege = "APPLY" - roles = ["ROLE1_NAME", "ROLE2_NAME"] - with_grant_option = true - enable_multiple_grants = true -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the masking policy on which to grant privileges. -- `masking_policy_name` (String) The name of the masking policy on which to grant privileges immediately. -- `schema_name` (String) The name of the schema containing the masking policy on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the masking policy. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|masking_policy_name|privilege|with_grant_option|roles -terraform import snowflake_masking_policy_grant.example "dbName|schemaName|maskingPolicyName|USAGE|false|role1,role2" -``` diff --git a/docs/resources/materialized_view_grant.md b/docs/resources/materialized_view_grant.md deleted file mode 100644 index a8a74748b8..0000000000 --- a/docs/resources/materialized_view_grant.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -page_title: "snowflake_materialized_view_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_materialized_view_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_materialized_view_grant" "grant" { - database_name = "database" - schema_name = "schema" - materialized_view_name = "materialized_view" - - privilege = "SELECT" - roles = ["role1", "role2"] - - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future materialized views on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `materialized_view_name` (String) The name of the materialized view on which to grant privileges immediately (only valid if on_future and on_all are false). -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all future materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future materialized view. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `schema_name` (String) The name of the schema containing the current or future materialized views on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future and on_all are false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|materialized_view_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_materialized_view_grant.example "MY_DATABASE|MY_SCHEMA|MY_MV_NAME|SELECT|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/pipe_grant.md b/docs/resources/pipe_grant.md deleted file mode 100644 index 91ad256fed..0000000000 --- a/docs/resources/pipe_grant.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -page_title: "snowflake_pipe_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_pipe_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_pipe_grant" "grant" { - database_name = "database" - schema_name = "schema" - pipe_name = "pipe" - - privilege = "OPERATE" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future pipes on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future pipes in the given schema. When this is true and no schema_name is provided apply this grant on all future pipes in the given database. The pipe_name field must be unset in order to use on_future. -- `pipe_name` (String) The name of the pipe on which to grant privileges immediately (only valid if on_future is false). -- `privilege` (String) The privilege to grant on the current or future pipe. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `schema_name` (String) The name of the schema containing the current or future pipes on which to grant privileges. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|pipe_name|privilege|with_grant_option|on_future|roles -terraform import snowflake_pipe_grant.example "MY_DATABASE|MY_SCHEMA|MY_PIPE_NAME|OPERATE|false|false|role1,role2' -``` diff --git a/docs/resources/procedure_grant.md b/docs/resources/procedure_grant.md deleted file mode 100644 index a47c3a0198..0000000000 --- a/docs/resources/procedure_grant.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -page_title: "snowflake_procedure_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_procedure_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_procedure_grant" "grant" { - database_name = "database" - schema_name = "schema" - procedure_name = "procedure" - argument_data_types = ["array", "string"] - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future procedures on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `argument_data_types` (List of String) List of the argument data types for the procedure (must be present if procedure has arguments and procedure_name is present) -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all procedures in the given schema. When this is true and no schema_name is provided apply this grant on all procedures in the given database. The procedure_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future procedures in the given schema. When this is true and no schema_name is provided apply this grant on all future procedures in the given database. The procedure_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future procedure. To grant all privileges, use the value `ALL PRIVILEGES` -- `procedure_name` (String) The name of the procedure on which to grant privileges immediately (only valid if on_future is false). -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future procedures on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future is false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|procedure_name|argument_data_types|privilege|with_grant_option|on_future|roles|shares -terraform import snowflake_procedure_grant.example "MY_DATABASE|MY_SCHEMA|MY_PROCEDURE|ARG1TYPE,ARG2TYPE|USAGE|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/resource_monitor_grant.md b/docs/resources/resource_monitor_grant.md deleted file mode 100644 index 8f282de283..0000000000 --- a/docs/resources/resource_monitor_grant.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -page_title: "snowflake_resource_monitor_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_resource_monitor_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_resource_monitor_grant" "grant" { - monitor_name = "monitor" - privilege = "MODIFY" - roles = ["role1"] - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `monitor_name` (String) Identifier for the resource monitor; must be unique for your account. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the resource monitor. To grant all privileges, use the value `ALL PRIVILEGES` -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is monitor_name|privilege|with_grant_option|roles -terraform import snowflake_resource_monitor_grant.example "MY_RESOURCE_MONITOR|MONITOR|false|role1,role2" -``` diff --git a/docs/resources/role_grants.md b/docs/resources/role_grants.md deleted file mode 100644 index e5ad1493b3..0000000000 --- a/docs/resources/role_grants.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -page_title: "snowflake_role_grants Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_role_grants (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_account_role](./grant_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_role" "role" { - name = "rking_test_role" - comment = "for testing" -} - -resource "snowflake_user" "user" { - name = "rking_test_user" - comment = "for testing" -} - -resource "snowflake_user" "user2" { - name = "rking_test_user2" - comment = "for testing" -} - -resource "snowflake_role" "other_role" { - name = "rking_test_role2" -} - -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - - roles = [ - snowflake_role.other_role.name, - ] - - users = [ - snowflake_user.user.name, - snowflake_user.user2.name, - ] -} -``` - - -## Schema - -### Required - -- `role_name` (String) The name of the role we are granting. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `roles` (Set of String) Grants role to this specified role. -- `users` (Set of String) Grants role to this specified user. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is role_name|roles|users -terraform import snowflake_role_grants.example "role_name|role1,role2|user1,user2" -``` diff --git a/docs/resources/role_ownership_grant.md b/docs/resources/role_ownership_grant.md deleted file mode 100644 index 9900c25079..0000000000 --- a/docs/resources/role_ownership_grant.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -page_title: "snowflake_role_ownership_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_role_ownership_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_ownership](./grant_ownership) instead. - -## Example Usage - -```terraform -resource "snowflake_role" "role" { - name = "rking_test_role" - comment = "for testing" -} - -resource "snowflake_role" "other_role" { - name = "rking_test_role2" -} - -# ensure the Terraform user inherits ownership privileges for the rking_test_role role -# otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - - roles = [ - "ACCOUNTADMIN", - ] -} - -resource "snowflake_role_ownership_grant" "grant" { - on_role_name = snowflake_role.role.name - to_role_name = snowflake_role.other_role.name - current_grants = "COPY" -} -``` - - -## Schema - -### Required - -- `on_role_name` (String) The name of the role ownership is granted on. -- `to_role_name` (String) The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access. - -### Optional - -- `current_grants` (String) Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -terraform import snowflake_role_ownership_grant.example "||" -``` diff --git a/docs/resources/row_access_policy_grant.md b/docs/resources/row_access_policy_grant.md deleted file mode 100644 index 44937520de..0000000000 --- a/docs/resources/row_access_policy_grant.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -page_title: "snowflake_row_access_policy_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_row_access_policy_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_row_access_policy_grant" "grant" { - database_name = "database" - schema_name = "schema" - row_access_policy_name = "row_access_policy" - - privilege = "APPLY" - roles = ["role1", "role2"] - - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the row access policy on which to grant privileges. -- `row_access_policy_name` (String) The name of the row access policy on which to grant privileges immediately. -- `schema_name` (String) The name of the schema containing the row access policy on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the row access policy. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|row_access_policy_name|privilege|with_grant_option|roles -terraform import snowflake_row_access_policy_grant.example "MY_DATABASE|MY_SCHEMA|MY_ROW_ACCESS_POLICY_NAME|SELECT|false|role1,role2" -``` diff --git a/docs/resources/schema_grant.md b/docs/resources/schema_grant.md deleted file mode 100644 index f7edbec88e..0000000000 --- a/docs/resources/schema_grant.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -page_title: "snowflake_schema_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_schema_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_schema_grant" "grant" { - database_name = "database" - schema_name = "schema" - - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the schema on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true, apply this grant on all schemas in the given database. The schema_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true, apply this grant on all future schemas in the given database. The schema_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future schema. Note that if "OWNERSHIP" is specified, ensure that the role that terraform is using is granted access. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `schema_name` (String) The name of the schema on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future and on_all are unset). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_schema_grant.example "MY_DATABASE|MY_SCHEMA|USAGE|false|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/sequence_grant.md b/docs/resources/sequence_grant.md deleted file mode 100644 index 5fd4e8d25c..0000000000 --- a/docs/resources/sequence_grant.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -page_title: "snowflake_sequence_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_sequence_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_sequence_grant" "grant" { - database_name = "database" - schema_name = "schema" - sequence_name = "sequence" - - privilege = "SELECT" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future sequences on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all sequences in the given schema. When this is true and no schema_name is provided apply this grant on all sequences in the given database. The sequence_name field must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future sequences in the given schema. When this is true and no schema_name is provided apply this grant on all future sequences in the given database. The sequence_name field must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future sequence. To grant all privileges, use the value `ALL PRIVILEGES` -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future sequences on which to grant privileges. -- `sequence_name` (String) The name of the sequence on which to grant privileges immediately (only valid if on_future is false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|sequence_name|privilege|with_grant_option|on_future|roles -terraform import snowflake_sequence_grant.example "MY_DATABASE|MY_SCHEMA|MY_SEQUENCE|USAGE|false|false|role1,role2" -``` diff --git a/docs/resources/stage_grant.md b/docs/resources/stage_grant.md deleted file mode 100644 index 7dd90a4e51..0000000000 --- a/docs/resources/stage_grant.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -page_title: "snowflake_stage_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_stage_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_stage_grant" "grant" { - database_name = "database" - schema_name = "schema" - stage_name = "stage" - - privilege = "USAGE" - - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current stage on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all stages in the given schema. When this is true and no schema_name is provided apply this grant on all stages in the given database. The stage_name field must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future stages in the given schema. When this is true and no schema_name is provided apply this grant on all future stages in the given database. The stage_name field must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the stage. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current stage on which to grant privileges. -- `stage_name` (String) The name of the stage on which to grant privilege (only valid if on_future and on_all are false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|stage_name|privilege|with_grant_option|on_future|on_all|roles -terraform import snowflake_stage_grant.example "MY_DATABASE|MY_SCHEMA|MY_STAGE|USAGE|false|false|false|role1,role2" -``` diff --git a/docs/resources/stream_grant.md b/docs/resources/stream_grant.md deleted file mode 100644 index 5c8c2fef0c..0000000000 --- a/docs/resources/stream_grant.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -page_title: "snowflake_stream_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_stream_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_stream_grant" "grant" { - database_name = "database" - schema_name = "schema" - stream_name = "view" - - privilege = "SELECT" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future streams on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all streams in the given schema. When this is true and no schema_name is provided apply this grant on all streams in the given database. The stream_name field must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future streams in the given schema. When this is true and no schema_name is provided apply this grant on all future streams in the given database. The stream_name field must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future stream. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future streams on which to grant privileges. -- `stream_name` (String) The name of the stream on which to grant privileges immediately (only valid if on_future is false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|stream_name|privilege|with_grant_option|on_future|roles" -terraform import snowflake_stream_grant.example "MY_DATABASE|MY_SCHEMA|MY_STREAM|SELECT|false|false|role1,role2" -``` diff --git a/docs/resources/table_grant.md b/docs/resources/table_grant.md deleted file mode 100644 index 95f778f1fb..0000000000 --- a/docs/resources/table_grant.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -page_title: "snowflake_table_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_table_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_table_grant" "grant" { - database_name = "database" - schema_name = "schema" - table_name = "table" - - privilege = "SELECT" - roles = ["role1"] - shares = ["share1"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future tables on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all tables in the given schema. When this is true and no schema_name is provided apply this grant on all tables in the given database. The table_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future tables in the given schema. When this is true and no schema_name is provided apply this grant on all future tables in the given database. The table_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future table. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `schema_name` (String) The name of the schema containing the current or future tables on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future or on_all are unset). -- `table_name` (String) The name of the table on which to grant privileges immediately (only valid if on_future or on_all are unset). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|table_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_table_grant.example "MY_DATABASE|MY_SCHEMA|MY_TABLE|USAGE|false|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/tag_grant.md b/docs/resources/tag_grant.md deleted file mode 100644 index 960914f35f..0000000000 --- a/docs/resources/tag_grant.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -page_title: "snowflake_tag_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_tag_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_tag_grant" "example" { - database_name = "database" - schema_name = "schema" - tag_name = "tag" - roles = ["TEST_ROLE"] - privilege = "OWNERSHIP" - -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the tag on which to grant privileges. -- `schema_name` (String) The name of the schema containing the tag on which to grant privileges. -- `tag_name` (String) The name of the tag on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the tag. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database|schema|tag|privilege|with_grant_option|roles -terraform import snowflake_tag_grant.example "MY_DATABASE|MY_SCHEMA|MY_TAG|USAGE|false|role1,role2" -``` diff --git a/docs/resources/task_grant.md b/docs/resources/task_grant.md deleted file mode 100644 index ca75987f41..0000000000 --- a/docs/resources/task_grant.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -page_title: "snowflake_task_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_task_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_task_grant" "grant" { - database_name = "database" - schema_name = "schema" - task_name = "task" - - privilege = "OPERATE" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future tasks on which to grant privileges. -- `roles` (Set of String) Grants privilege to these roles. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all tasks in the given schema. When this is true and no schema_name is provided apply this grant on all tasks in the given database. The task_name field must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future tasks in the given schema. When this is true and no schema_name is provided apply this grant on all future tasks in the given database. The task_name field must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future task. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `schema_name` (String) The name of the schema containing the current or future tasks on which to grant privileges. -- `task_name` (String) The name of the task on which to grant privileges immediately (only valid if on_future is false). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|task_name|privilege|with_grant_option|on_future|on_all|roles" -terraform import snowflake_task_grant.example "MY_DATABASE|MY_SCHEMA|MY_TASK|OPERATE|false|false|false|role1,role2" -``` diff --git a/docs/resources/user_grant.md b/docs/resources/user_grant.md deleted file mode 100644 index 57ed62482d..0000000000 --- a/docs/resources/user_grant.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -page_title: "snowflake_user_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_user_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_user_grant" "grant" { - user_name = "user" - privilege = "MONITOR" - - roles = ["role1", "role2"] - - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `privilege` (String) The privilege to grant on the user. To grant all privileges, use the value `ALL PRIVILEGES`. -- `user_name` (String) The name of the user on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is user_name|privilege|with_grant_option|roles -terraform import snowflake_user_grant.example "USERNAME|MONITOR|false|role1,role2" -``` diff --git a/docs/resources/user_ownership_grant.md b/docs/resources/user_ownership_grant.md deleted file mode 100644 index f0edabd44b..0000000000 --- a/docs/resources/user_ownership_grant.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -page_title: "snowflake_user_ownership_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_user_ownership_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_ownership](./grant_ownership) instead. - - - - -## Schema - -### Required - -- `on_user_name` (String) The name of the user ownership is granted on. -- `to_role_name` (String) The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access. - -### Optional - -- `current_grants` (String) Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. - -### Read-Only - -- `id` (String) The ID of this resource. diff --git a/docs/resources/view_grant.md b/docs/resources/view_grant.md deleted file mode 100644 index 837a24cacf..0000000000 --- a/docs/resources/view_grant.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -page_title: "snowflake_view_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_view_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_view_grant" "grant" { - database_name = "database" - schema_name = "schema" - view_name = "view" - - privilege = "SELECT" - roles = ["role1", "role2"] - - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} - -/* -Snowflake view grant is an object level grant, not a schema level grant. To add schema level -grants, use the `snowflake_schema_grant` resource -*/ - -resource "snowflake_schema_grant" "grant" { - database_name = "database" - schema_name = "schema" - - privilege = "USAGE" - roles = ["role1", "role2"] -} -``` - - -## Schema - -### Required - -- `database_name` (String) The name of the database containing the current or future views on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all views in the given schema. When this is true and no schema_name is provided apply this grant on all views in the given database. The view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. -- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future views in the given schema. When this is true and no schema_name is provided apply this grant on all future views in the given database. The view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all. -- `privilege` (String) The privilege to grant on the current or future view. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `schema_name` (String) The name of the schema containing the current or future views on which to grant privileges. -- `shares` (Set of String) Grants privilege to these shares (only valid if on_future and on_all are unset). -- `view_name` (String) The name of the view on which to grant privileges immediately (only valid if on_future and on_all are unset). -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is database_name|schema_name|view_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_view_grant.example "MY_DATABASE|MY_SCHEMA|MY_VIEW|USAGE|false|false|false|role1,role2|share1,share2" -``` diff --git a/docs/resources/warehouse_grant.md b/docs/resources/warehouse_grant.md deleted file mode 100644 index 13097c5fc0..0000000000 --- a/docs/resources/warehouse_grant.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -page_title: "snowflake_warehouse_grant Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_warehouse_grant (Resource) - -~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use [snowflake_grant_privileges_to_account_role](./grant_privileges_to_account_role) instead. - -## Example Usage - -```terraform -resource "snowflake_warehouse_grant" "grant" { - warehouse_name = "warehouse" - privilege = "MODIFY" - - roles = ["role1", "role2"] - - with_grant_option = false -} -``` - - -## Schema - -### Required - -- `warehouse_name` (String) The name of the warehouse on which to grant privileges. - -### Optional - -- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform. -- `privilege` (String) The privilege to grant on the warehouse. To grant all privileges, use the value `ALL PRIVILEGES`. -- `revert_ownership_to_role_name` (String) The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP` -- `roles` (Set of String) Grants privilege to these roles. -- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles. - -### Read-Only - -- `id` (String) The ID of this resource. - -## Import - -Import is supported using the following syntax: - -```shell -# format is warehouse_name|privilege|with_grant_option|roles -terraform import snowflake_warehouse_grant.example "MY_WAREHOUSE|MODIFY|false|role1,role2" -``` diff --git a/examples/additional/deprecated_resources.MD b/examples/additional/deprecated_resources.MD index 01bdc91bbe..979b77f0fd 100644 --- a/examples/additional/deprecated_resources.MD +++ b/examples/additional/deprecated_resources.MD @@ -1,31 +1,4 @@ ## Currently deprecated resources -- [snowflake_account_grant](./docs/resources/account_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_database_grant](./docs/resources/database_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead - [snowflake_database_old](./docs/resources/database_old) -- [snowflake_external_table_grant](./docs/resources/external_table_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_failover_group_grant](./docs/resources/failover_group_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_file_format_grant](./docs/resources/file_format_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_function_grant](./docs/resources/function_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_grant_privileges_to_role](./docs/resources/grant_privileges_to_role) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_integration_grant](./docs/resources/integration_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_masking_policy_grant](./docs/resources/masking_policy_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_materialized_view_grant](./docs/resources/materialized_view_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_pipe_grant](./docs/resources/pipe_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_procedure_grant](./docs/resources/procedure_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_resource_monitor_grant](./docs/resources/resource_monitor_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_role_grants](./docs/resources/role_grants) - use [snowflake_grant_account_role](./docs/resources/grant_account_role) instead -- [snowflake_role_ownership_grant](./docs/resources/role_ownership_grant) - use [snowflake_grant_ownership](./docs/resources/grant_ownership) instead -- [snowflake_row_access_policy_grant](./docs/resources/row_access_policy_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_schema_grant](./docs/resources/schema_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_sequence_grant](./docs/resources/sequence_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_stage_grant](./docs/resources/stage_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_stream_grant](./docs/resources/stream_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_table_grant](./docs/resources/table_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_tag_grant](./docs/resources/tag_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_task_grant](./docs/resources/task_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead - [snowflake_unsafe_execute](./docs/resources/unsafe_execute) -- [snowflake_user_grant](./docs/resources/user_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_user_ownership_grant](./docs/resources/user_ownership_grant) - use [snowflake_grant_ownership](./docs/resources/grant_ownership) instead -- [snowflake_view_grant](./docs/resources/view_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead -- [snowflake_warehouse_grant](./docs/resources/warehouse_grant) - use [snowflake_grant_privileges_to_account_role](./docs/resources/grant_privileges_to_account_role) instead diff --git a/examples/resources/snowflake_account_grant/import.sh b/examples/resources/snowflake_account_grant/import.sh deleted file mode 100644 index e19092da0d..0000000000 --- a/examples/resources/snowflake_account_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is privilege|with_grant_option|roles -terraform import snowflake_account_grant.example "privilege|false|role1,role2" diff --git a/examples/resources/snowflake_account_grant/resource.tf b/examples/resources/snowflake_account_grant/resource.tf deleted file mode 100644 index 4ef5b1c3d6..0000000000 --- a/examples/resources/snowflake_account_grant/resource.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "snowflake_account_grant" "grant" { - roles = ["role1", "role2"] - privilege = "CREATE ROLE" - with_grant_option = false -} diff --git a/examples/resources/snowflake_database_grant/import.sh b/examples/resources/snowflake_database_grant/import.sh deleted file mode 100644 index 4f821668f0..0000000000 --- a/examples/resources/snowflake_database_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|privilege|with_grant_option|roles|shares -terraform import snowflake_database_grant.example "MY_DATABASE|USAGE|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_database_grant/resource.tf b/examples/resources/snowflake_database_grant/resource.tf deleted file mode 100644 index c4698335e0..0000000000 --- a/examples/resources/snowflake_database_grant/resource.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "snowflake_database_grant" "grant" { - database_name = "database" - - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - - with_grant_option = false -} diff --git a/examples/resources/snowflake_external_table_grant/import.sh b/examples/resources/snowflake_external_table_grant/import.sh deleted file mode 100644 index 4950d964be..0000000000 --- a/examples/resources/snowflake_external_table_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database|schema|external_table|privilege|with_grant_option|on_future|roles|shares -terraform import snowflake_external_table_grant.example "MY_DATABASE|MY_SCHEMA|MY_TABLE_NAME|SELECT|false|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_external_table_grant/resource.tf b/examples/resources/snowflake_external_table_grant/resource.tf deleted file mode 100644 index fd0fb8e859..0000000000 --- a/examples/resources/snowflake_external_table_grant/resource.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "snowflake_external_table_grant" "grant" { - database_name = "database" - schema_name = "schema" - external_table_name = "external_table" - - privilege = "SELECT" - roles = ["role1", "role2"] - - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_file_format_grant/import.sh b/examples/resources/snowflake_file_format_grant/import.sh deleted file mode 100644 index 1fcab4b8e8..0000000000 --- a/examples/resources/snowflake_file_format_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|file_format_name|privilege|with_grant_option|on_future|roles -terraform import snowflake_file_format_grant.example "MY_DATABASE|MY_SCHEMA|MY_FILE_FORMAT|USAGE|false|false|role1,role2' diff --git a/examples/resources/snowflake_file_format_grant/resource.tf b/examples/resources/snowflake_file_format_grant/resource.tf deleted file mode 100644 index b1d7ca5342..0000000000 --- a/examples/resources/snowflake_file_format_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_file_format_grant" "grant" { - database_name = "database" - schema_name = "schema" - file_format_name = "file_format" - - privilege = "SELECT" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_function_grant/import.sh b/examples/resources/snowflake_function_grant/import.sh deleted file mode 100644 index 211912ead4..0000000000 --- a/examples/resources/snowflake_function_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|function_name|argument_data_types|privilege|with_grant_option|on_future|roles|shares -terraform import snowflake_function_grant.example "MY_DATABASE|MY_SCHEMA|MY_FUNCTION|ARG1TYPE,ARG2TYPE|USAGE|false|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_function_grant/resource.tf b/examples/resources/snowflake_function_grant/resource.tf deleted file mode 100644 index ef5d04fc33..0000000000 --- a/examples/resources/snowflake_function_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_function_grant" "grant" { - database_name = "database" - schema_name = "schema" - function_name = "function" - argument_data_types = ["array", "string"] - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_grant_privileges_to_role/import.sh b/examples/resources/snowflake_grant_privileges_to_role/import.sh deleted file mode 100644 index b70f10c79c..0000000000 --- a/examples/resources/snowflake_grant_privileges_to_role/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is role_name (string) | privileges (comma-delimited string) | all_privileges (bool) |with_grant_option (bool) | on_account (bool) | on_account_object (bool) | on_schema (bool) | on_schema_object (bool) | all (bool) | future (bool) | object_type (string) | object_name (string) | object_type_plural (string) | in_schema (bool) | schema_name (string) | in_database (bool) | database_name (string) -terraform import "test_role|MANAGE GRANTS,MONITOR USAGE|false|false|true|false|false|false|false|false||||false||false|" diff --git a/examples/resources/snowflake_grant_privileges_to_role/resource.tf b/examples/resources/snowflake_grant_privileges_to_role/resource.tf deleted file mode 100644 index b54bc9c934..0000000000 --- a/examples/resources/snowflake_grant_privileges_to_role/resource.tf +++ /dev/null @@ -1,157 +0,0 @@ -################################## -### global privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g1" { - privileges = ["MODIFY", "USAGE"] - role_name = snowflake_role.r.name - on_account = true -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g2" { - role_name = snowflake_role.r.name - on_account = true - all_privileges = true - with_grant_option = true -} - -################################## -### account object privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g3" { - privileges = ["CREATE", "MONITOR"] - role_name = snowflake_role.r.name - on_account_object { - object_type = "DATABASE" - object_name = snowflake_database.d.name - } -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g4" { - role_name = snowflake_role.r.name - on_account_object { - object_type = "DATABASE" - object_name = snowflake_database.d.name - } - all_privileges = true - with_grant_option = true -} - -################################## -### schema privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g5" { - privileges = ["MODIFY", "CREATE TABLE"] - role_name = snowflake_role.r.name - on_schema { - schema_name = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g6" { - role_name = snowflake_role.r.name - on_schema { - schema_name = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } - all_privileges = true - with_grant_option = true -} - -# all schemas in database -resource "snowflake_grant_privileges_to_role" "g7" { - privileges = ["MODIFY", "CREATE TABLE"] - role_name = snowflake_role.r.name - on_schema { - all_schemas_in_database = snowflake_database.d.name - } -} - -# future schemas in database -resource "snowflake_grant_privileges_to_role" "g8" { - privileges = ["MODIFY", "CREATE TABLE"] - role_name = snowflake_role.r.name - on_schema { - future_schemas_in_database = snowflake_database.d.name - } -} - -################################## -### schema object privileges -################################## - -# list of privileges -resource "snowflake_grant_privileges_to_role" "g9" { - privileges = ["SELECT", "REFERENCES"] - role_name = snowflake_role.r.name - on_schema_object { - object_type = "VIEW" - object_name = "\"my_db\".\"my_schema\".\"my_view\"" # note this is a fully qualified name! - } -} - -# all privileges + grant option -resource "snowflake_grant_privileges_to_role" "g10" { - role_name = snowflake_role.r.name - on_schema_object { - object_type = "VIEW" - object_name = "\"my_db\".\"my_schema\".\"my_view\"" # note this is a fully qualified name! - } - all_privileges = true - with_grant_option = true -} - -# all in database -resource "snowflake_grant_privileges_to_role" "g11" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - all { - object_type_plural = "TABLES" - in_database = snowflake_database.d.name - } - } -} - -# all in schema -resource "snowflake_grant_privileges_to_role" "g12" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - all { - object_type_plural = "TABLES" - in_schema = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } - } -} - -# future in database -resource "snowflake_grant_privileges_to_role" "g13" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - future { - object_type_plural = "TABLES" - in_database = snowflake_database.d.name - } - } -} - -# future in schema -resource "snowflake_grant_privileges_to_role" "g14" { - privileges = ["SELECT", "INSERT"] - role_name = snowflake_role.r.name - on_schema_object { - future { - object_type_plural = "TABLES" - in_schema = "\"my_db\".\"my_schema\"" # note this is a fully qualified name! - } - } -} diff --git a/examples/resources/snowflake_integration_grant/import.sh b/examples/resources/snowflake_integration_grant/import.sh deleted file mode 100644 index 275f01efd1..0000000000 --- a/examples/resources/snowflake_integration_grant/import.sh +++ /dev/null @@ -1,3 +0,0 @@ -# format is integration_name|privilege|with_grant_option|roles -terraform import snowflake_integration_grant.example "MY_INTEGRATION|USAGE|false|role1,role2" - diff --git a/examples/resources/snowflake_integration_grant/resource.tf b/examples/resources/snowflake_integration_grant/resource.tf deleted file mode 100644 index 9f7491ff77..0000000000 --- a/examples/resources/snowflake_integration_grant/resource.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "snowflake_integration_grant" "grant" { - integration_name = "integration" - - privilege = "USAGE" - roles = ["role1", "role2"] - - with_grant_option = false -} diff --git a/examples/resources/snowflake_masking_policy_grant/import.sh b/examples/resources/snowflake_masking_policy_grant/import.sh deleted file mode 100644 index f8012c60f9..0000000000 --- a/examples/resources/snowflake_masking_policy_grant/import.sh +++ /dev/null @@ -1,3 +0,0 @@ -# format is database_name|schema_name|masking_policy_name|privilege|with_grant_option|roles -terraform import snowflake_masking_policy_grant.example "dbName|schemaName|maskingPolicyName|USAGE|false|role1,role2" - diff --git a/examples/resources/snowflake_masking_policy_grant/resource.tf b/examples/resources/snowflake_masking_policy_grant/resource.tf deleted file mode 100644 index 65ef85b378..0000000000 --- a/examples/resources/snowflake_masking_policy_grant/resource.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "snowflake_masking_policy_grant" "example" { - masking_policy_name = "EXAMPLE_MASKING_POLICY_NAME" - database_name = "EXAMPLE_DB_NAME" - schema_name = "EXAMPLE_SCHEMA_NAME" - privilege = "APPLY" - roles = ["ROLE1_NAME", "ROLE2_NAME"] - with_grant_option = true - enable_multiple_grants = true -} diff --git a/examples/resources/snowflake_materialized_view_grant/import.sh b/examples/resources/snowflake_materialized_view_grant/import.sh deleted file mode 100644 index 4f04f6b684..0000000000 --- a/examples/resources/snowflake_materialized_view_grant/import.sh +++ /dev/null @@ -1,3 +0,0 @@ -# format is database_name|schema_name|materialized_view_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_materialized_view_grant.example "MY_DATABASE|MY_SCHEMA|MY_MV_NAME|SELECT|false|false|role1,role2|share1,share2" - diff --git a/examples/resources/snowflake_materialized_view_grant/resource.tf b/examples/resources/snowflake_materialized_view_grant/resource.tf deleted file mode 100644 index 18cb66a908..0000000000 --- a/examples/resources/snowflake_materialized_view_grant/resource.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "snowflake_materialized_view_grant" "grant" { - database_name = "database" - schema_name = "schema" - materialized_view_name = "materialized_view" - - privilege = "SELECT" - roles = ["role1", "role2"] - - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_pipe_grant/import.sh b/examples/resources/snowflake_pipe_grant/import.sh deleted file mode 100644 index d20eed63ee..0000000000 --- a/examples/resources/snowflake_pipe_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|pipe_name|privilege|with_grant_option|on_future|roles -terraform import snowflake_pipe_grant.example "MY_DATABASE|MY_SCHEMA|MY_PIPE_NAME|OPERATE|false|false|role1,role2' diff --git a/examples/resources/snowflake_pipe_grant/resource.tf b/examples/resources/snowflake_pipe_grant/resource.tf deleted file mode 100644 index 45e23bbaa9..0000000000 --- a/examples/resources/snowflake_pipe_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_pipe_grant" "grant" { - database_name = "database" - schema_name = "schema" - pipe_name = "pipe" - - privilege = "OPERATE" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_procedure_grant/import.sh b/examples/resources/snowflake_procedure_grant/import.sh deleted file mode 100644 index 8c1c89ae22..0000000000 --- a/examples/resources/snowflake_procedure_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|procedure_name|argument_data_types|privilege|with_grant_option|on_future|roles|shares -terraform import snowflake_procedure_grant.example "MY_DATABASE|MY_SCHEMA|MY_PROCEDURE|ARG1TYPE,ARG2TYPE|USAGE|false|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_procedure_grant/resource.tf b/examples/resources/snowflake_procedure_grant/resource.tf deleted file mode 100644 index e6defdc307..0000000000 --- a/examples/resources/snowflake_procedure_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_procedure_grant" "grant" { - database_name = "database" - schema_name = "schema" - procedure_name = "procedure" - argument_data_types = ["array", "string"] - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_resource_monitor_grant/import.sh b/examples/resources/snowflake_resource_monitor_grant/import.sh deleted file mode 100644 index e48621a50f..0000000000 --- a/examples/resources/snowflake_resource_monitor_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is monitor_name|privilege|with_grant_option|roles -terraform import snowflake_resource_monitor_grant.example "MY_RESOURCE_MONITOR|MONITOR|false|role1,role2" diff --git a/examples/resources/snowflake_resource_monitor_grant/resource.tf b/examples/resources/snowflake_resource_monitor_grant/resource.tf deleted file mode 100644 index 31a56ec72d..0000000000 --- a/examples/resources/snowflake_resource_monitor_grant/resource.tf +++ /dev/null @@ -1,6 +0,0 @@ -resource "snowflake_resource_monitor_grant" "grant" { - monitor_name = "monitor" - privilege = "MODIFY" - roles = ["role1"] - with_grant_option = false -} diff --git a/examples/resources/snowflake_role_grants/import.sh b/examples/resources/snowflake_role_grants/import.sh deleted file mode 100644 index 122c292b9a..0000000000 --- a/examples/resources/snowflake_role_grants/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is role_name|roles|users -terraform import snowflake_role_grants.example "role_name|role1,role2|user1,user2" diff --git a/examples/resources/snowflake_role_grants/resource.tf b/examples/resources/snowflake_role_grants/resource.tf deleted file mode 100644 index 4cae3c2e5b..0000000000 --- a/examples/resources/snowflake_role_grants/resource.tf +++ /dev/null @@ -1,31 +0,0 @@ -resource "snowflake_role" "role" { - name = "rking_test_role" - comment = "for testing" -} - -resource "snowflake_user" "user" { - name = "rking_test_user" - comment = "for testing" -} - -resource "snowflake_user" "user2" { - name = "rking_test_user2" - comment = "for testing" -} - -resource "snowflake_role" "other_role" { - name = "rking_test_role2" -} - -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - - roles = [ - snowflake_role.other_role.name, - ] - - users = [ - snowflake_user.user.name, - snowflake_user.user2.name, - ] -} diff --git a/examples/resources/snowflake_row_access_policy_grant/import.sh b/examples/resources/snowflake_row_access_policy_grant/import.sh deleted file mode 100644 index 400fd993d1..0000000000 --- a/examples/resources/snowflake_row_access_policy_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|row_access_policy_name|privilege|with_grant_option|roles -terraform import snowflake_row_access_policy_grant.example "MY_DATABASE|MY_SCHEMA|MY_ROW_ACCESS_POLICY_NAME|SELECT|false|role1,role2" diff --git a/examples/resources/snowflake_row_access_policy_grant/resource.tf b/examples/resources/snowflake_row_access_policy_grant/resource.tf deleted file mode 100644 index 02864cce88..0000000000 --- a/examples/resources/snowflake_row_access_policy_grant/resource.tf +++ /dev/null @@ -1,10 +0,0 @@ -resource "snowflake_row_access_policy_grant" "grant" { - database_name = "database" - schema_name = "schema" - row_access_policy_name = "row_access_policy" - - privilege = "APPLY" - roles = ["role1", "role2"] - - with_grant_option = false -} diff --git a/examples/resources/snowflake_schema_grant/import.sh b/examples/resources/snowflake_schema_grant/import.sh deleted file mode 100644 index 0efd19b128..0000000000 --- a/examples/resources/snowflake_schema_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_schema_grant.example "MY_DATABASE|MY_SCHEMA|USAGE|false|false|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_schema_grant/resource.tf b/examples/resources/snowflake_schema_grant/resource.tf deleted file mode 100644 index 65d80921d2..0000000000 --- a/examples/resources/snowflake_schema_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_schema_grant" "grant" { - database_name = "database" - schema_name = "schema" - - privilege = "USAGE" - roles = ["role1", "role2"] - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_sequence_grant/import.sh b/examples/resources/snowflake_sequence_grant/import.sh deleted file mode 100644 index 5e719d24e1..0000000000 --- a/examples/resources/snowflake_sequence_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|sequence_name|privilege|with_grant_option|on_future|roles -terraform import snowflake_sequence_grant.example "MY_DATABASE|MY_SCHEMA|MY_SEQUENCE|USAGE|false|false|role1,role2" diff --git a/examples/resources/snowflake_sequence_grant/resource.tf b/examples/resources/snowflake_sequence_grant/resource.tf deleted file mode 100644 index 6bc2affa91..0000000000 --- a/examples/resources/snowflake_sequence_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_sequence_grant" "grant" { - database_name = "database" - schema_name = "schema" - sequence_name = "sequence" - - privilege = "SELECT" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_stage_grant/import.sh b/examples/resources/snowflake_stage_grant/import.sh deleted file mode 100644 index a5f3d09629..0000000000 --- a/examples/resources/snowflake_stage_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|stage_name|privilege|with_grant_option|on_future|on_all|roles -terraform import snowflake_stage_grant.example "MY_DATABASE|MY_SCHEMA|MY_STAGE|USAGE|false|false|false|role1,role2" diff --git a/examples/resources/snowflake_stage_grant/resource.tf b/examples/resources/snowflake_stage_grant/resource.tf deleted file mode 100644 index b091b30fcc..0000000000 --- a/examples/resources/snowflake_stage_grant/resource.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "snowflake_stage_grant" "grant" { - database_name = "database" - schema_name = "schema" - stage_name = "stage" - - privilege = "USAGE" - - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_stream_grant/import.sh b/examples/resources/snowflake_stream_grant/import.sh deleted file mode 100644 index e630491bb3..0000000000 --- a/examples/resources/snowflake_stream_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|stream_name|privilege|with_grant_option|on_future|roles" -terraform import snowflake_stream_grant.example "MY_DATABASE|MY_SCHEMA|MY_STREAM|SELECT|false|false|role1,role2" diff --git a/examples/resources/snowflake_stream_grant/resource.tf b/examples/resources/snowflake_stream_grant/resource.tf deleted file mode 100644 index bc79b7fe53..0000000000 --- a/examples/resources/snowflake_stream_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_stream_grant" "grant" { - database_name = "database" - schema_name = "schema" - stream_name = "view" - - privilege = "SELECT" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_table_grant/import.sh b/examples/resources/snowflake_table_grant/import.sh deleted file mode 100644 index 0fac8ef63b..0000000000 --- a/examples/resources/snowflake_table_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|table_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_table_grant.example "MY_DATABASE|MY_SCHEMA|MY_TABLE|USAGE|false|false|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_table_grant/resource.tf b/examples/resources/snowflake_table_grant/resource.tf deleted file mode 100644 index dbcf2d0940..0000000000 --- a/examples/resources/snowflake_table_grant/resource.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "snowflake_table_grant" "grant" { - database_name = "database" - schema_name = "schema" - table_name = "table" - - privilege = "SELECT" - roles = ["role1"] - shares = ["share1"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_tag_grant/import.sh b/examples/resources/snowflake_tag_grant/import.sh deleted file mode 100644 index 6172f26ec2..0000000000 --- a/examples/resources/snowflake_tag_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database|schema|tag|privilege|with_grant_option|roles -terraform import snowflake_tag_grant.example "MY_DATABASE|MY_SCHEMA|MY_TAG|USAGE|false|role1,role2" diff --git a/examples/resources/snowflake_tag_grant/resource.tf b/examples/resources/snowflake_tag_grant/resource.tf deleted file mode 100644 index 079ffd8a1d..0000000000 --- a/examples/resources/snowflake_tag_grant/resource.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "snowflake_tag_grant" "example" { - database_name = "database" - schema_name = "schema" - tag_name = "tag" - roles = ["TEST_ROLE"] - privilege = "OWNERSHIP" - -} diff --git a/examples/resources/snowflake_task_grant/import.sh b/examples/resources/snowflake_task_grant/import.sh deleted file mode 100644 index b4089b7ea8..0000000000 --- a/examples/resources/snowflake_task_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|task_name|privilege|with_grant_option|on_future|on_all|roles" -terraform import snowflake_task_grant.example "MY_DATABASE|MY_SCHEMA|MY_TASK|OPERATE|false|false|false|role1,role2" diff --git a/examples/resources/snowflake_task_grant/resource.tf b/examples/resources/snowflake_task_grant/resource.tf deleted file mode 100644 index a021191f59..0000000000 --- a/examples/resources/snowflake_task_grant/resource.tf +++ /dev/null @@ -1,11 +0,0 @@ -resource "snowflake_task_grant" "grant" { - database_name = "database" - schema_name = "schema" - task_name = "task" - - privilege = "OPERATE" - roles = ["role1", "role2"] - - on_future = false - with_grant_option = false -} diff --git a/examples/resources/snowflake_user_grant/import.sh b/examples/resources/snowflake_user_grant/import.sh deleted file mode 100644 index 643dfbdc06..0000000000 --- a/examples/resources/snowflake_user_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is user_name|privilege|with_grant_option|roles -terraform import snowflake_user_grant.example "USERNAME|MONITOR|false|role1,role2" diff --git a/examples/resources/snowflake_user_grant/resource.tf b/examples/resources/snowflake_user_grant/resource.tf deleted file mode 100644 index cb726649b3..0000000000 --- a/examples/resources/snowflake_user_grant/resource.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "snowflake_user_grant" "grant" { - user_name = "user" - privilege = "MONITOR" - - roles = ["role1", "role2"] - - with_grant_option = false -} diff --git a/examples/resources/snowflake_view_grant/import.sh b/examples/resources/snowflake_view_grant/import.sh deleted file mode 100644 index 6c4c79ddba..0000000000 --- a/examples/resources/snowflake_view_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is database_name|schema_name|view_name|privilege|with_grant_option|on_future|on_all|roles|shares -terraform import snowflake_view_grant.example "MY_DATABASE|MY_SCHEMA|MY_VIEW|USAGE|false|false|false|role1,role2|share1,share2" diff --git a/examples/resources/snowflake_view_grant/resource.tf b/examples/resources/snowflake_view_grant/resource.tf deleted file mode 100644 index 38afaaa078..0000000000 --- a/examples/resources/snowflake_view_grant/resource.tf +++ /dev/null @@ -1,26 +0,0 @@ -resource "snowflake_view_grant" "grant" { - database_name = "database" - schema_name = "schema" - view_name = "view" - - privilege = "SELECT" - roles = ["role1", "role2"] - - shares = ["share1", "share2"] - - on_future = false - with_grant_option = false -} - -/* -Snowflake view grant is an object level grant, not a schema level grant. To add schema level -grants, use the `snowflake_schema_grant` resource -*/ - -resource "snowflake_schema_grant" "grant" { - database_name = "database" - schema_name = "schema" - - privilege = "USAGE" - roles = ["role1", "role2"] -} diff --git a/examples/resources/snowflake_warehouse_grant/import.sh b/examples/resources/snowflake_warehouse_grant/import.sh deleted file mode 100644 index a171da0c0f..0000000000 --- a/examples/resources/snowflake_warehouse_grant/import.sh +++ /dev/null @@ -1,2 +0,0 @@ -# format is warehouse_name|privilege|with_grant_option|roles -terraform import snowflake_warehouse_grant.example "MY_WAREHOUSE|MODIFY|false|role1,role2" diff --git a/examples/resources/snowflake_warehouse_grant/resource.tf b/examples/resources/snowflake_warehouse_grant/resource.tf deleted file mode 100644 index 223386eff4..0000000000 --- a/examples/resources/snowflake_warehouse_grant/resource.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "snowflake_warehouse_grant" "grant" { - warehouse_name = "warehouse" - privilege = "MODIFY" - - roles = ["role1", "role2"] - - with_grant_option = false -} diff --git a/framework/provider/provider_helpers.go b/framework/provider/provider_helpers.go index 8d61b79f49..76dac3c27c 100644 --- a/framework/provider/provider_helpers.go +++ b/framework/provider/provider_helpers.go @@ -13,23 +13,12 @@ import ( "strconv" "strings" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/mitchellh/go-homedir" "github.com/snowflakedb/gosnowflake" "github.com/youmark/pkcs8" "golang.org/x/crypto/ssh" ) -func mergeSchemas(schemaCollections ...map[string]*schema.Resource) map[string]*schema.Resource { - out := map[string]*schema.Resource{} - for _, schemaCollection := range schemaCollections { - for name, s := range schemaCollection { - out[name] = s - } - } - return out -} - func getPrivateKey(privateKeyPath, privateKeyString, privateKeyPassphrase string) (*rsa.PrivateKey, error) { privateKeyBytes := []byte(privateKeyString) var err error diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index e6922f1155..0c4686249a 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -419,38 +419,8 @@ func Provider() *schema.Provider { } } -func GetGrantResources() resources.TerraformGrantResources { - grants := resources.TerraformGrantResources{ - "snowflake_account_grant": resources.AccountGrant(), - "snowflake_database_grant": resources.DatabaseGrant(), - "snowflake_external_table_grant": resources.ExternalTableGrant(), - "snowflake_failover_group_grant": resources.FailoverGroupGrant(), - "snowflake_file_format_grant": resources.FileFormatGrant(), - "snowflake_function_grant": resources.FunctionGrant(), - "snowflake_integration_grant": resources.IntegrationGrant(), - "snowflake_masking_policy_grant": resources.MaskingPolicyGrant(), - "snowflake_materialized_view_grant": resources.MaterializedViewGrant(), - "snowflake_pipe_grant": resources.PipeGrant(), - "snowflake_procedure_grant": resources.ProcedureGrant(), - "snowflake_resource_monitor_grant": resources.ResourceMonitorGrant(), - "snowflake_row_access_policy_grant": resources.RowAccessPolicyGrant(), - "snowflake_schema_grant": resources.SchemaGrant(), - "snowflake_sequence_grant": resources.SequenceGrant(), - "snowflake_stage_grant": resources.StageGrant(), - "snowflake_stream_grant": resources.StreamGrant(), - "snowflake_table_grant": resources.TableGrant(), - "snowflake_tag_grant": resources.TagGrant(), - "snowflake_task_grant": resources.TaskGrant(), - "snowflake_user_grant": resources.UserGrant(), - "snowflake_view_grant": resources.ViewGrant(), - "snowflake_warehouse_grant": resources.WarehouseGrant(), - } - return grants -} - func getResources() map[string]*schema.Resource { - // NOTE(): do not add grant resources here - others := map[string]*schema.Resource{ + return map[string]*schema.Resource{ "snowflake_account": resources.Account(), "snowflake_account_password_policy_attachment": resources.AccountPasswordPolicyAttachment(), "snowflake_account_parameter": resources.AccountParameter(), @@ -471,7 +441,6 @@ func getResources() map[string]*schema.Resource { "snowflake_grant_application_role": resources.GrantApplicationRole(), "snowflake_grant_database_role": resources.GrantDatabaseRole(), "snowflake_grant_ownership": resources.GrantOwnership(), - "snowflake_grant_privileges_to_role": resources.GrantPrivilegesToRole(), "snowflake_grant_privileges_to_account_role": resources.GrantPrivilegesToAccountRole(), "snowflake_grant_privileges_to_database_role": resources.GrantPrivilegesToDatabaseRole(), "snowflake_grant_privileges_to_share": resources.GrantPrivilegesToShare(), @@ -489,8 +458,6 @@ func getResources() map[string]*schema.Resource { "snowflake_procedure": resources.Procedure(), "snowflake_resource_monitor": resources.ResourceMonitor(), "snowflake_role": resources.Role(), - "snowflake_role_grants": resources.RoleGrants(), - "snowflake_role_ownership_grant": resources.RoleOwnershipGrant(), "snowflake_row_access_policy": resources.RowAccessPolicy(), "snowflake_saml_integration": resources.SAMLIntegration(), "snowflake_schema": resources.Schema(), @@ -512,21 +479,15 @@ func getResources() map[string]*schema.Resource { "snowflake_task": resources.Task(), "snowflake_unsafe_execute": resources.UnsafeExecute(), "snowflake_user": resources.User(), - "snowflake_user_ownership_grant": resources.UserOwnershipGrant(), "snowflake_user_password_policy_attachment": resources.UserPasswordPolicyAttachment(), "snowflake_user_public_keys": resources.UserPublicKeys(), "snowflake_view": resources.View(), "snowflake_warehouse": resources.Warehouse(), } - - return mergeSchemas( - others, - GetGrantResources().GetTfSchemas(), - ) } func getDataSources() map[string]*schema.Resource { - dataSources := map[string]*schema.Resource{ + return map[string]*schema.Resource{ "snowflake_accounts": datasources.Accounts(), "snowflake_alerts": datasources.Alerts(), "snowflake_current_account": datasources.CurrentAccount(), @@ -567,8 +528,6 @@ func getDataSources() map[string]*schema.Resource { "snowflake_views": datasources.Views(), "snowflake_warehouses": datasources.Warehouses(), } - - return dataSources } var ( diff --git a/pkg/resources/account_grant.go b/pkg/resources/account_grant.go deleted file mode 100644 index e85577e64c..0000000000 --- a/pkg/resources/account_grant.go +++ /dev/null @@ -1,185 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validAccountPrivileges = NewPrivilegeSet( - privilegeApplyMaskingPolicy, - privilegeApplyPasswordPolicy, - privilegeApplyRowAccessPolicy, - privilegeApplySessionPolicy, - privilegeApplyTag, - privilegeAttachPolicy, - privilegeAudit, - privilegeCreateAccount, - privilegeCreateCredential, - privilegeCreateDatabase, - privilegeCreateDataExchangeListing, - privilegeCreateFailoverGroup, - privilegeCreateIntegration, - privilegeCreateNetworkPolicy, - privilegeCreateRole, - privilegeCreateShare, - privilegeCreateUser, - privilegeCreateWarehouse, - privilegeExecuteTask, - privilegeImportShare, - privilegeManageGrants, - privilegeManageWarehouses, - privilegeMonitor, - privilegeMonitorUsage, - privilegeMonitorExecution, - privilegeMonitorSecurity, - privilegeOverrideShareRestrictions, - privilegeExecuteManagedTask, - privilegeOrganizationSupportCases, - privilegeProvisionApplication, - privilegePurchaseDataExchangeListing, - privilegeAccountSupportCases, - privilegeUserSupportCases, - privilegeResolveAll, - privilegeAllPrivileges, -) - -var accountGrantSchema = map[string]*schema.Schema{ - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The account privilege to grant. Valid privileges are those in [globalPrivileges](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege.html). To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: privilegeMonitorUsage, - ValidateFunc: validation.StringInSlice(validAccountPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, -} - -// AccountGrant returns a pointer to the resource representing an account grant. -func AccountGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateAccountGrant, - Read: ReadAccountGrant, - 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_account_role instead.", - Schema: accountGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 3 { - return nil, errors.New("id should be in the format 'privilege|with_grant_option|roles'") - } - if err := d.Set("privilege", parts[0]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[1])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[2])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validAccountPrivileges, - } -} - -// CreateAccountGrant implements schema.CreateFunc. -func CreateAccountGrant(d *schema.ResourceData, meta interface{}) error { - builder := snowflake.AccountGrant() - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - privilege := d.Get("privilege").(string) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - withGrantOption := d.Get("with_grant_option").(bool) - grantID := helpers.EncodeSnowflakeID(privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadAccountGrant(d, meta) -} - -// ReadAccountGrant implements schema.ReadFunc. -func ReadAccountGrant(d *schema.ResourceData, meta interface{}) error { - privilege := d.Get("privilege").(string) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - withGrantOption := d.Get("with_grant_option").(bool) - - builder := snowflake.AccountGrant() - err := readGenericGrant(d, meta, accountGrantSchema, builder, false, false, validAccountPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(privilege, withGrantOption, roles) - // if the ID is not in the new format, rewrite it - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteAccountGrant implements schema.DeleteFunc. -func DeleteAccountGrant(d *schema.ResourceData, meta interface{}) error { - builder := snowflake.AccountGrant() - return deleteGenericGrant(d, meta, builder) -} - -// UpdateAccountGrant implements schema.UpdateFunc. -func UpdateAccountGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update is roles. - // if nothing changed, nothing to update and we're done. - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - - builder := snowflake.AccountGrant() - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // first revoke - if err := deleteGenericGrantRolesAndShares(meta, builder, privilege, "", rolesToRevoke, nil); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares(meta, builder, privilege, withGrantOption, rolesToAdd, nil); err != nil { - return err - } - - // done, refresh state - return ReadAccountGrant(d, meta) -} diff --git a/pkg/resources/account_grant_acceptance_test.go b/pkg/resources/account_grant_acceptance_test.go deleted file mode 100644 index e207950c58..0000000000 --- a/pkg/resources/account_grant_acceptance_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_AccountGrant_defaults(t *testing.T) { - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: accountGrantConfig(roleName, "MONITOR USAGE"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_account_grant.test", "privilege", "MONITOR USAGE"), - ), - }, - /*// UPDATE ALL PRIVILEGES - { - Config: accountGrantConfig(roleName, "ALL PRIVILEGES"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_account_grant.test", "privilege", "ALL PRIVILEGES"), - ), - },*/ - // IMPORT - { - ResourceName: "snowflake_account_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_AccountGrantManagedTask(t *testing.T) { - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: accountGrantConfig(roleName, "EXECUTE MANAGED TASK"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_account_grant.test", "privilege", "EXECUTE MANAGED TASK"), - ), - }, - }, - }) -} - -func TestAcc_AccountGrantManageSupportCases(t *testing.T) { - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: accountGrantConfig(roleName, "MANAGE ACCOUNT SUPPORT CASES"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_account_grant.test", "privilege", "MANAGE ACCOUNT SUPPORT CASES"), - ), - }, - }, - }) -} - -func TestAcc_AccountGrantManageWarehouses(t *testing.T) { - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: accountGrantConfig(roleName, "MANAGE WAREHOUSES"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_account_grant.test", "privilege", "MANAGE WAREHOUSES"), - ), - }, - }, - }) -} - -func accountGrantConfig(role, privilege string) string { - return fmt.Sprintf(` - -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_account_grant" "test" { - roles = [snowflake_role.test.name] - privilege = "%s" -} -`, role, privilege) -} diff --git a/pkg/resources/account_grant_test.go b/pkg/resources/account_grant_test.go deleted file mode 100644 index f079590efe..0000000000 --- a/pkg/resources/account_grant_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -// lintignore:AT003 -func TestAccountGrant(t *testing.T) { - r := require.New(t) - err := resources.AccountGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -// lintignore:AT003 -func TestAccountGrantCreate(t *testing.T) { // lintignore:AT003 - r := require.New(t) - - in := map[string]interface{}{ - "privilege": "CREATE DATABASE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.AccountGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT CREATE DATABASE ON ACCOUNT TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT CREATE DATABASE ON ACCOUNT TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadAccountGrant(mock) - err := resources.CreateAccountGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -// lintignore:AT003 -func TestAccountGrantRead(t *testing.T) { - r := require.New(t) - - d := accountGrant(t, "ACCOUNT|||MANAGE GRANTS||true", map[string]interface{}{ - "privilege": "MANAGE GRANTS", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadAccountGrant(mock) - err := resources.ReadAccountGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestMonitorExecution(t *testing.T) { - r := require.New(t) - - d := accountGrant(t, "ACCOUNT|||MONITOR EXECUTION||true", map[string]interface{}{ - "privilege": "MONITOR EXECUTION", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadAccountGrant(mock) - err := resources.ReadAccountGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestExecuteTask(t *testing.T) { - r := require.New(t) - - d := accountGrant(t, "ACCOUNT|||EXECUTE TASK||false", map[string]interface{}{ - "privilege": "EXECUTE TASK", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadAccountGrant(mock) - err := resources.ReadAccountGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadAccountGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "MANAGE GRANTS", "ACCOUNT", "", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "MANAGE GRANTS", "ACCOUNT", "", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON ACCOUNT$`).WillReturnRows(rows) -} - -func TestApplyMaskingPolicy(t *testing.T) { - r := require.New(t) - - d := accountGrant(t, "ACCOUNT|||APPLY MASKING POLICY||true", map[string]interface{}{ - "privilege": "APPLY MASKING POLICY", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadAccountGrant(mock) - err := resources.ReadAccountGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go deleted file mode 100644 index cb851f3ce5..0000000000 --- a/pkg/resources/database_grant.go +++ /dev/null @@ -1,231 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validDatabasePrivileges = NewPrivilegeSet( - privilegeCreateDatabaseRole, - privilegeCreateSchema, - privilegeImportedPrivileges, - privilegeModify, - privilegeMonitor, - privilegeOwnership, - privilegeReferenceUsage, - privilegeUsage, - privilegeAllPrivileges, -) - -var databaseGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the database. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: "USAGE", - ForceNew: true, - ValidateFunc: validation.StringInSlice(validDatabasePrivileges.ToList(), true), - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// DatabaseGrant returns a pointer to the resource representing a database grant. -func DatabaseGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateDatabaseGrant, - Read: ReadDatabaseGrant, - Delete: DeleteDatabaseGrant, - Update: UpdateDatabaseGrant, - - 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: databaseGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 5 { - return nil, fmt.Errorf("invalid ID specified: %v, expected database_name|privilege|with_grant_option|roles|shares", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[1]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[2])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[4])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validDatabasePrivileges, - } -} - -// CreateDatabaseGrant implements schema.CreateFunc. -func CreateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - builder := snowflake.DatabaseGrant(databaseName) - if err := createGenericGrant(d, meta, builder); err != nil { - return fmt.Errorf("error creating database grant err = %w", err) - } - - privilege := d.Get("privilege").(string) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - withGrantOption := d.Get("with_grant_option").(bool) - grantID := helpers.EncodeSnowflakeID(databaseName, privilege, withGrantOption, roles, shares) - d.SetId(grantID) - - return ReadDatabaseGrant(d, meta) -} - -// ReadDatabaseGrant implements schema.ReadFunc. -func ReadDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - privilege := d.Get("privilege").(string) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - withGrantOption := d.Get("with_grant_option").(bool) - - // IMPORTED PRIVILEGES is not a real resource but - // it is needed to grant usage for the snowflake database to custom roles. - // We have to set to usage to check Snowflake for the grant - if privilege == "IMPORTED PRIVILEGES" { - err := d.Set("privilege", "USAGE") - if err != nil { - return fmt.Errorf("error setting privilege to USAGE: %w", err) - } - } - - builder := snowflake.DatabaseGrant(databaseName) - err := readGenericGrant(d, meta, databaseGrantSchema, builder, false, false, validDatabasePrivileges) - if err != nil { - return fmt.Errorf("error reading database grant: %w", err) - } - - // Then set it back to imported privledges for Terraform to execute the grant. - if privilege == "IMPORTED PRIVILEGES" { - err := d.Set("privilege", "IMPORTED PRIVILEGES") - if err != nil { - return fmt.Errorf("error setting privilege to IMPORTED PRIVILEGES: %w", err) - } - } - - grantID := helpers.EncodeSnowflakeID(databaseName, privilege, withGrantOption, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteDatabaseGrant implements schema.DeleteFunc. -func DeleteDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - builder := snowflake.DatabaseGrant(databaseName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateDatabaseGrant implements schema.UpdateFunc. -func UpdateDatabaseGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - - databaseName := d.Get("database_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - // create the builder - builder := snowflake.DatabaseGrant(databaseName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, - builder, - privilege, - reversionRole, - rolesToRevoke, - sharesToRevoke, - ); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares( - meta, - builder, - privilege, - withGrantOption, - rolesToAdd, - sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadDatabaseGrant(d, meta) -} diff --git a/pkg/resources/database_grant_acceptance_test.go b/pkg/resources/database_grant_acceptance_test.go deleted file mode 100644 index 1992eae9ee..0000000000 --- a/pkg/resources/database_grant_acceptance_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func testRolesAndShares(t *testing.T, path string, roles []string) func(*terraform.State) error { - t.Helper() - return func(state *terraform.State) error { - is := state.RootModule().Resources[path].Primary - - if c, ok := is.Attributes["roles.#"]; !ok || mustParseInt(t, c) != int64(len(roles)) { - return fmt.Errorf("expected roles.# to equal %d but got %s", len(roles), c) - } - r, err := extractList(is.Attributes, "roles") - if err != nil { - return err - } - - // TODO case sensitive? - if !listSetEqual(roles, r) { - return fmt.Errorf("expected roles %#v but got %#v", roles, r) - } - - return nil - } -} - -func TestAcc_DatabaseGrant(t *testing.T) { - roleName := acc.TestClient().Ids.Alpha() - shareName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: databaseGrantConfig(roleName, shareName, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_database_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_database_grant.test", "privilege", "USAGE"), - resource.TestCheckResourceAttr("snowflake_database_grant.test", "roles.#", "1"), - resource.TestCheckResourceAttr("snowflake_database_grant.test", "shares.#", "1"), - resource.TestCheckResourceAttr("snowflake_database_grant.test", "shares.#", "1"), - testRolesAndShares(t, "snowflake_database_grant.test", []string{roleName}), - ), - }, - // IMPORT - { - PreConfig: func() { fmt.Println("[DEBUG] IMPORT") }, - ResourceName: "snowflake_database_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -// TODO(el): fix this test -// func TestAccDatabaseGrant_dbNotExists(t *testing.T) { -// dbName := acc.TestClient().Ids.Alpha() -// roleName := acc.TestClient().Ids.Alpha() - -// resource.Test(t, resource.TestCase{ -// ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, -// TerraformVersionChecks: []tfversion.TerraformVersionCheck{ -// tfversion.RequireAbove(tfversion.Version1_5_0), -// }, -// Steps: []resource.TestStep{ -// { -// // Note the DB we're trying to grant to doesn't exist -// // This tests we don't error out, but do delete remote state -// Config: fmt.Sprintf(` -// resource "snowflake_database_grant" "test" { -// database_name = "%v" -// roles = ["%v"] -// }`, dbName, roleName), -// ResourceName: "snowflake_database_grant.test", -// ImportStateId: , -// Check: resource.ComposeTestCheckFunc( -// func(state *terraform.State) error { -// id := state.RootModule().Resources["snowflake_database_grant.test"].Primary.ID -// if id != "" { -// return errors.Errorf("Expected empty ID but got %s", id) -// } -// return nil -// }, -// ), -// }, -// }, -// }) -// } - -func databaseGrantConfig(role, share, databaseName string) string { - return fmt.Sprintf(` -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_share" "test" { - name = "%v" -} - -resource "snowflake_database_grant" "test" { - database_name = "%s" - roles = [snowflake_role.test.name] - shares = [snowflake_share.test.name] -} -`, role, share, databaseName) -} diff --git a/pkg/resources/database_grant_test.go b/pkg/resources/database_grant_test.go deleted file mode 100644 index d828346cb0..0000000000 --- a/pkg/resources/database_grant_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/stretchr/testify/require" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" -) - -func TestDatabaseGrant(t *testing.T) { - r := require.New(t) - err := resources.DatabaseGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestDatabaseGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "database_name": "test-database", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.DatabaseGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT USAGE ON DATABASE "test-database" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON DATABASE "test-database" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON DATABASE "test-database" TO SHARE "test-share-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON DATABASE "test-database" TO SHARE "test-share-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadDatabaseGrant(mock) - err := resources.CreateDatabaseGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestDatabaseGrantRead(t *testing.T) { - r := require.New(t) - - d := databaseGrant(t, "test-database|||USAGE||false", map[string]interface{}{ - "database_name": "test-database", - "privilege": "USAGE", - "roles": []interface{}{}, - "shares": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadDatabaseGrant(mock) - err := resources.ReadDatabaseGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) - - shares := d.Get("shares").(*schema.Set) - r.True(shares.Contains("test-share-1")) - r.True(shares.Contains("test-share-2")) - r.Equal(2, shares.Len()) -} - -func expectReadDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "DATABASE", "test-database", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "DATABASE", "test-database", "ROLE", "test-role-2", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "DATABASE", "test-database", "SHARE", "test-share-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "DATABASE", "test-database", "SHARE", "test-share-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON DATABASE "test-database"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/deprecated_helpers_test.go b/pkg/resources/deprecated_helpers_test.go index 324f745d3a..34601967d1 100644 --- a/pkg/resources/deprecated_helpers_test.go +++ b/pkg/resources/deprecated_helpers_test.go @@ -9,118 +9,9 @@ import ( ) /** - * Most functions from this file will be removed while removing old grant resources. - * The rest will be removed while adding security integrations to the SDK. + * Will be removed while adding security integrations to the SDK. */ -func databaseGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.DatabaseGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func schemaGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.SchemaGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func stageGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.StageGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func tableGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.TableGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func viewGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.ViewGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func materializedViewGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.MaterializedViewGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func resourceMonitorGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.ResourceMonitorGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func integrationGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.IntegrationGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func accountGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.AccountGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func roleGrants(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.RoleGrants().Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func userOwnershipGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.UserOwnershipGrant().Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func roleOwnershipGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.RoleOwnershipGrant().Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - func samlIntegration(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { t.Helper() r := require.New(t) @@ -130,15 +21,6 @@ func samlIntegration(t *testing.T, id string, params map[string]interface{}) *sc return d } -func scimIntegration(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.SCIMIntegration().Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - func oauthIntegration(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { t.Helper() r := require.New(t) @@ -147,84 +29,3 @@ func oauthIntegration(t *testing.T, id string, params map[string]interface{}) *s d.SetId(id) return d } - -func externalTableGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.ExternalTableGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func fileFormatGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.FileFormatGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func sequenceGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.SequenceGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func streamGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.StreamGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func maskingPolicyGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.MaskingPolicyGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func pipeGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.PipeGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func taskGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.TaskGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func rowAccessPolicyGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.RowAccessPolicyGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} - -func tagGrant(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData { - t.Helper() - r := require.New(t) - d := schema.TestResourceDataRaw(t, resources.TagGrant().Resource.Schema, params) - r.NotNil(d) - d.SetId(id) - return d -} diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go deleted file mode 100644 index 601e7b0535..0000000000 --- a/pkg/resources/external_table_grant.go +++ /dev/null @@ -1,301 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validExternalTablePrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeReferences, - privilegeSelect, - privilegeAllPrivileges, -) - -var externalTableGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future external tables on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "external_table_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the external table on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future external tables in the given schema. When this is true and no schema_name is provided apply this grant on all future external tables in the given database. The external_table_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all external tables in the given schema. When this is true and no schema_name is provided apply this grant on all external tables in the given database. The external_table_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future external table. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "SELECT", - ValidateFunc: validation.StringInSlice(validExternalTablePrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future external tables on which to grant privileges.", - ForceNew: true, - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future is false).", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// ExternalTableGrant returns a pointer to the resource representing a external table grant. -func ExternalTableGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateExternalTableGrant, - 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_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) - if len(parts) != 9 { - return nil, errors.New("external table grant ID should be in the format database|schema|external_table|privilege|with_grant_option|on_future|roles|shares") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("external_table_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[8])); err != nil { - return nil, err - } - - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validExternalTablePrivileges, - } -} - -// CreateExternalTableGrant implements schema.CreateFunc. -func CreateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { - externalTableName := d.Get("external_table_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - if onFuture && onAll { - return errors.New("on_future and on_all cannot both be true") - } - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - if (externalTableName == "") && !onFuture && !onAll { - return errors.New("external_table_name must be set unless on_future or on_all is true") - } - if (externalTableName != "") && (onFuture || onAll) { - return errors.New("external_table_name must be empty if on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureExternalTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllExternalTableGrant(databaseName, schemaName) - default: - builder = snowflake.ExternalTableGrant(databaseName, schemaName, externalTableName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, externalTableName, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - - return ReadExternalTableGrant(d, meta) -} - -// ReadExternalTableGrant implements schema.ReadFunc. -func ReadExternalTableGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - externalTableName := d.Get("external_table_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureExternalTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllExternalTableGrant(databaseName, schemaName) - default: - builder = snowflake.ExternalTableGrant(databaseName, schemaName, externalTableName) - } - - err := readGenericGrant(d, meta, externalTableGrantSchema, builder, onFuture, onAll, validExternalTablePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, externalTableName, privilege, withGrantOption, onFuture, onAll, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteExternalTableGrant implements schema.DeleteFunc. -func DeleteExternalTableGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - externalTableName := d.Get("external_table_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureExternalTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllExternalTableGrant(databaseName, schemaName) - default: - builder = snowflake.ExternalTableGrant(databaseName, schemaName, externalTableName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateExternalTableGrant implements schema.UpdateFunc. -func UpdateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - externalTableName := d.Get("external_table_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - // create the builder - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureExternalTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllExternalTableGrant(databaseName, schemaName) - default: - builder = snowflake.ExternalTableGrant(databaseName, schemaName, externalTableName) - } - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, sharesToRevoke, - ); err != nil { - return err - } - // then add - - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadExternalTableGrant(d, meta) -} diff --git a/pkg/resources/external_table_grant_acceptance_test.go b/pkg/resources/external_table_grant_acceptance_test.go deleted file mode 100644 index be6250ca3a..0000000000 --- a/pkg/resources/external_table_grant_acceptance_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_ExternalTableGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: externalTableGrantConfig(name, onAll, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_external_table_grant.test", "external_table_name"), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "privilege", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_external_table_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_ExternalTableGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: externalTableGrantConfig(name, onFuture, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_external_table_grant.test", "external_table_name"), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_external_table_grant.test", "privilege", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_external_table_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func externalTableGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var externalTableNameConfig string - switch grantType { - case onFuture: - externalTableNameConfig = "on_future = true" - case onAll: - externalTableNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource "snowflake_role" "test" { - name = "%s" -} - -resource "snowflake_external_table_grant" "test" { - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - %s - privilege = "%s" -} -`, name, databaseName, schemaName, externalTableNameConfig, privilege) -} diff --git a/pkg/resources/external_table_grant_test.go b/pkg/resources/external_table_grant_test.go deleted file mode 100644 index e12ae61f3b..0000000000 --- a/pkg/resources/external_table_grant_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestExternalTableGrant(t *testing.T) { - r := require.New(t) - err := resources.ExternalTableGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestExternalTableGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "external_table_name": "test-external-table", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.ExternalTableGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT SELECT ON EXTERNAL TABLE "test-db"."PUBLIC"."test-external-table" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON EXTERNAL TABLE "test-db"."PUBLIC"."test-external-table" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON EXTERNAL TABLE "test-db"."PUBLIC"."test-external-table" TO SHARE "test-share-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON EXTERNAL TABLE "test-db"."PUBLIC"."test-external-table" TO SHARE "test-share-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadExternalTableGrant(mock) - err := resources.CreateExternalTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestExternalTableGrantRead(t *testing.T) { - r := require.New(t) - - d := externalTableGrant(t, "test-db|PUBLIC|test-external-table|SELECT||false", map[string]interface{}{ - "external_table_name": "test-external-table", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{}, - "shares": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadExternalTableGrant(mock) - err := resources.ReadExternalTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) - - shares := d.Get("shares").(*schema.Set) - r.True(shares.Contains("test-share-1")) - r.True(shares.Contains("test-share-2")) - r.Equal(2, shares.Len()) -} - -func expectReadExternalTableGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL_TABLE", "test-external-table", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL_TABLE", "test-external-table", "ROLE", "test-role-2", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL_TABLE", "test-external-table", "SHARE", "test-share-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL_TABLE", "test-external-table", "SHARE", "test-share-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON EXTERNAL TABLE "test-db"."PUBLIC"."test-external-table"$`).WillReturnRows(rows) -} - -func TestFutureExternalTableGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.ExternalTableGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureExternalTableGrant(mock) - err := resources.CreateExternalTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.ExternalTableGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureExternalTableDatabaseGrant(mock) - err := resources.CreateExternalTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) - - c := require.New(t) - - in = map[string]interface{}{ - "database_name": "test-db", - "external_table_name": "test-table", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.ExternalTableGrant().Resource.Schema, in) - c.NotNil(d) - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - err := resources.CreateExternalTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - c.Error(err) - }) -} - -func expectReadFutureExternalTableGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL TABLE", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL TABLE", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureExternalTableDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL TABLE", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "EXTERNAL TABLE", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/failover_group_grant.go b/pkg/resources/failover_group_grant.go deleted file mode 100644 index df32bc419b..0000000000 --- a/pkg/resources/failover_group_grant.go +++ /dev/null @@ -1,184 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validFailoverGroupPrivileges = NewPrivilegeSet( - privilegeFailover, - privilegeMonitor, - privilegeOwnership, - privilegeReplicate, - privilegeAllPrivileges, -) - -var failoverGroupGrantSchema = map[string]*schema.Schema{ - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "failover_group_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the failover group on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the failover group. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validFailoverGroupPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// FailoverGroup returns a pointer to the resource representing a file format grant. -func FailoverGroupGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateFailoverGroupGrant, - 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_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) - if len(parts) != 4 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected failover_group_name|privilege|with_grant_option|roles", d.Id()) - } - - if err := d.Set("failover_group_name", parts[0]); err != nil { - return nil, err - } - - if err := d.Set("privilege", parts[1]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[2])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validFailoverGroupPrivileges, - } -} - -// CreateFailoverGroupGrant implements schema.CreateFunc. -func CreateFailoverGroupGrant(d *schema.ResourceData, meta interface{}) error { - failoverGroupName := d.Get("failover_group_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.FailoverGroupGrant(failoverGroupName) - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(failoverGroupName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadFailoverGroupGrant(d, meta) -} - -// ReadFailoverGroupGrant implements schema.ReadFunc. -func ReadFailoverGroupGrant(d *schema.ResourceData, meta interface{}) error { - failoverGroupName := d.Get("failover_group_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - builder := snowflake.FailoverGroupGrant(failoverGroupName) - - err := readGenericGrant(d, meta, failoverGroupGrantSchema, builder, false, false, validFailoverGroupPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(failoverGroupName, privilege, withGrantOption, roles) - if d.Id() != grantID { - d.SetId(grantID) - } - return nil -} - -// DeleteFailoverGroupGrant implements schema.DeleteFunc. -func DeleteFailoverGroupGrant(d *schema.ResourceData, meta interface{}) error { - failoverGroupName := d.Get("failover_group_name").(string) - builder := snowflake.FailoverGroupGrant(failoverGroupName) - return deleteGenericGrant(d, meta, builder) -} - -// UpdateFailoverGroupGrant implements schema.UpdateFunc. -func UpdateFailoverGroupGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - failoverGroupName := d.Get("failover_group_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - builder := snowflake.FailoverGroupGrant(failoverGroupName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadFileFormatGrant(d, meta) -} diff --git a/pkg/resources/failover_group_grant_acceptance_test.go b/pkg/resources/failover_group_grant_acceptance_test.go deleted file mode 100644 index 59a301dfad..0000000000 --- a/pkg/resources/failover_group_grant_acceptance_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_FailoverGroupGrant(t *testing.T) { - // TODO [SNOW-1002023]: Unskip; Business Critical Snowflake Edition needed - _ = testenvs.GetOrSkipTest(t, testenvs.TestFailoverGroups) - - accountName := testenvs.GetOrSkipTest(t, testenvs.BusinessCriticalAccount) - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: failoverGroupGrantConfig(name, accountName, "FAILOVER"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_failover_group_grant.g", "failover_group_name", name), - resource.TestCheckResourceAttr("snowflake_failover_group_grant.g", "privilege", "FAILOVER"), - resource.TestCheckResourceAttr("snowflake_failover_group_grant.g", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_failover_group_grant.g", "roles.#", "1"), - resource.TestCheckResourceAttr("snowflake_failover_group_grant.g", "roles.0", name), - ), - }, - // IMPORT - { - ResourceName: "snowflake_failover_group_grant.g", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func failoverGroupGrantConfig(name string, allowedAccount string, privilege string) string { - return fmt.Sprintf(` - -resource "snowflake_failover_group" "fg" { - name = "%s" - object_types = ["ROLES"] - allowed_accounts= ["%s"] -} - -resource "snowflake_role" "test" { - name = "%s" -} - -resource "snowflake_failover_group_grant" "g" { - failover_group_name = snowflake_failover_group.fg.name - privilege = "%s" - roles = [ - snowflake_role.test.name - ] -} -`, name, allowedAccount, name, privilege) -} diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go deleted file mode 100644 index afc098115f..0000000000 --- a/pkg/resources/file_format_grant.go +++ /dev/null @@ -1,282 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validFileFormatPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, -) - -var fileFormatGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future file formats on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "file_format_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the file format on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future file formats in the given schema. When this is true and no schema_name is provided apply this grant on all future file formats in the given database. The file_format_name field must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"file_format_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all file formats in the given schema. When this is true and no schema_name is provided apply this grant on all file formats in the given database. The file_format_name field must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"file_format_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future file format. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validFileFormatPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future file formats on which to grant privileges.", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// FileFormatGrant returns a pointer to the resource representing a file format grant. -func FileFormatGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateFileFormatGrant, - 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_account_role instead.", - Schema: fileFormatGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 8 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected database_name|schema_name|file_format_name|privilege|with_grant_option|on_future|roles", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("file_format_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validFileFormatPrivileges, - } -} - -// CreateFileFormatGrant implements schema.CreateFunc. -func CreateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - fileFormatName := d.Get("file_format_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if (fileFormatName == "") && !onFuture && !onAll { - return errors.New("file_format_name must be set unless on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFileFormatGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFileFormatGrant(databaseName, schemaName) - default: - builder = snowflake.FileFormatGrant(databaseName, schemaName, fileFormatName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, fileFormatName, privilege, withGrantOption, onFuture, onAll, roles) - d.SetId(grantID) - - return ReadFileFormatGrant(d, meta) -} - -// ReadFileFormatGrant implements schema.ReadFunc. -func ReadFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - fileFormatName := d.Get("file_format_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFileFormatGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFileFormatGrant(databaseName, schemaName) - default: - builder = snowflake.FileFormatGrant(databaseName, schemaName, fileFormatName) - } - - err := readGenericGrant(d, meta, fileFormatGrantSchema, builder, onFuture, onAll, validFileFormatPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, fileFormatName, privilege, withGrantOption, onFuture, onAll, roles) - if d.Id() != grantID { - d.SetId(grantID) - } - return nil -} - -// DeleteFileFormatGrant implements schema.DeleteFunc. -func DeleteFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - fileFormatName := d.Get("file_format_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFileFormatGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFileFormatGrant(databaseName, schemaName) - default: - builder = snowflake.FileFormatGrant(databaseName, schemaName, fileFormatName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateFileFormatGrant implements schema.UpdateFunc. -func UpdateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - fileFormatName := d.Get("file_format_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFileFormatGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFileFormatGrant(databaseName, schemaName) - default: - builder = snowflake.FileFormatGrant(databaseName, schemaName, fileFormatName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadFileFormatGrant(d, meta) -} diff --git a/pkg/resources/file_format_grant_acceptance_test.go b/pkg/resources/file_format_grant_acceptance_test.go deleted file mode 100644 index 9843ad31fe..0000000000 --- a/pkg/resources/file_format_grant_acceptance_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_FileFormatGrant_defaults(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: fileFormatGrantConfig(name, normal, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "file_format_name", name), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "privilege", "USAGE"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: fileFormatGrantConfig(name, normal, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "file_format_name", name), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_file_format_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_FileFormatGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: fileFormatGrantConfig(name, onAll, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_file_format_grant.test", "file_format_name"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "privilege", "USAGE"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_file_format_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_FileFormatGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: fileFormatGrantConfig(name, onFuture, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_file_format_grant.test", "file_format_name"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_file_format_grant.test", "privilege", "USAGE"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_file_format_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func fileFormatGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var fileFormatNameConfig string - switch grantType { - case normal: - fileFormatNameConfig = "file_format_name = snowflake_file_format.test.name" - case onFuture: - fileFormatNameConfig = "on_future = true" - case onAll: - fileFormatNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource snowflake_role test { - name = "%s" -} - -resource snowflake_file_format test { - name = "%s" - database = "%s" - schema = "%s" - format_type = "PARQUET" - - compression = "AUTO" -} - -resource snowflake_file_format_grant test { - %s - database_name = "%s" - schema_name = "%s" - privilege = "%s" - roles = [ - snowflake_role.test.name - ] -} -`, name, name, databaseName, schemaName, fileFormatNameConfig, databaseName, schemaName, privilege) -} diff --git a/pkg/resources/file_format_grant_test.go b/pkg/resources/file_format_grant_test.go deleted file mode 100644 index 84af0bfb64..0000000000 --- a/pkg/resources/file_format_grant_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestFileFormatGrant(t *testing.T) { - r := require.New(t) - err := resources.FileFormatGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestFileFormatGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "file_format_name": "test-file-format", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.FileFormatGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT USAGE ON FILE FORMAT "test-db"."PUBLIC"."test-file-format" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON FILE FORMAT "test-db"."PUBLIC"."test-file-format" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFileFormatGrant(mock) - err := resources.CreateFileFormatGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestFileFormatGrantRead(t *testing.T) { - r := require.New(t) - - d := fileFormatGrant(t, "test-db|PUBLIC|test-file-format|USAGE||false", map[string]interface{}{ - "file_format_name": "test-file-format", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadFileFormatGrant(mock) - err := resources.ReadFileFormatGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadFileFormatGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "FILE_FORMAT", "test-file-format", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "FILE_FORMAT", "test-file-format", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON FILE FORMAT "test-db"."PUBLIC"."test-file-format"$`).WillReturnRows(rows) -} - -func TestFutureFileFormatGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.FileFormatGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE FILE FORMATS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE FILE FORMATS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureFileFormatGrant(mock) - err := resources.CreateFileFormatGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.FileFormatGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE FILE FORMATS IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE FILE FORMATS IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureFileFormatDatabaseGrant(mock) - err := resources.CreateFileFormatGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureFileFormatGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "FILE FORMAT", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "FILE FORMAT", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureFileFormatDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "FILE FORMAT", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "FILE FORMAT", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go deleted file mode 100644 index 03ca88f404..0000000000 --- a/pkg/resources/function_grant.go +++ /dev/null @@ -1,321 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validFunctionPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, -) - -var functionGrantSchema = map[string]*schema.Schema{ - "argument_data_types": { - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "List of the argument data types for the function (must be present if function has arguments and function_name is present)", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "function_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the function on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future functions on which to grant privileges.", - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future functions in the given schema. When this is true and no schema_name is provided apply this grant on all future functions in the given database. The function_name, arguments, return_type, and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"function_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all functions in the given schema. When this is true and no schema_name is provided apply this grant on all functions in the given database. The function_name, arguments, return_type, and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"function_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future function. Must be one of `USAGE` or `OWNERSHIP`. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validFunctionPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future functions on which to grant privileges.", - ForceNew: true, - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future is false).", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// FunctionGrant returns a pointer to the resource representing a function grant. -func FunctionGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateFunctionGrant, - 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_account_role instead.", - Schema: functionGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 10 { - return nil, errors.New("function grant ID must be specified as database_name|schema_name|function_name|argument_data_types|privilege|with_grant_option|on_future|roles|shares") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("function_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("argument_data_types", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[4]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[7])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[8])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[9])); err != nil { - return nil, err - } - - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validFunctionPrivileges, - } -} - -// CreateFunctionGrant implements schema.CreateFunc. -func CreateFunctionGrant(d *schema.ResourceData, meta interface{}) error { - functionName := d.Get("function_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - var argumentDataTypes []string - // support deprecated arguments - if v, ok := d.GetOk("arguments"); ok { - arguments := v.([]interface{}) - for _, argument := range arguments { - argumentMap := argument.(map[string]interface{}) - argumentDataTypes = append(argumentDataTypes, argumentMap["type"].(string)) - } - } - if v, ok := d.GetOk("argument_data_types"); ok { - argumentDataTypes = expandStringList(v.([]interface{})) - } - - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - if (functionName == "") && !onFuture && !onAll { - return errors.New("function_name must be set unless on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFunctionGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFunctionGrant(databaseName, schemaName) - default: - builder = snowflake.FunctionGrant(databaseName, schemaName, functionName, argumentDataTypes) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, functionName, argumentDataTypes, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - return ReadFunctionGrant(d, meta) -} - -// ReadFunctionGrant implements schema.ReadFunc. -func ReadFunctionGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - functionName := d.Get("function_name").(string) - argumentDataTypes := expandStringList(d.Get("argument_data_types").([]interface{})) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFunctionGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFunctionGrant(databaseName, schemaName) - default: - builder = snowflake.FunctionGrant(databaseName, schemaName, functionName, argumentDataTypes) - } - - err := readGenericGrant(d, meta, functionGrantSchema, builder, onFuture, onAll, validFunctionPrivileges) - if err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, functionName, argumentDataTypes, privilege, withGrantOption, onFuture, onAll, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteFunctionGrant implements schema.DeleteFunc. -func DeleteFunctionGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - functionName := d.Get("function_name").(string) - argumentDataTypes := expandStringList(d.Get("argument_data_types").([]interface{})) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFunctionGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFunctionGrant(databaseName, schemaName) - default: - builder = snowflake.FunctionGrant(databaseName, schemaName, functionName, argumentDataTypes) - } - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateFunctionGrant implements schema.UpdateFunc. -func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - functionName := d.Get("function_name").(string) - argumentDataTypes := expandStringList(d.Get("argument_data_types").([]interface{})) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - // create the builder - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureFunctionGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllFunctionGrant(databaseName, schemaName) - default: - builder = snowflake.FunctionGrant(databaseName, schemaName, functionName, argumentDataTypes) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, sharesToRevoke, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadFunctionGrant(d, meta) -} diff --git a/pkg/resources/function_grant_acceptance_test.go b/pkg/resources/function_grant_acceptance_test.go deleted file mode 100644 index c921a81b9e..0000000000 --- a/pkg/resources/function_grant_acceptance_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_FunctionGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: functionGrantConfig(name, onFuture, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_function_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_function_grant.test", "function_name"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "privilege", "USAGE"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_function_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_FunctionGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: functionGrantConfig(name, onAll, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_function_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_function_grant.test", "function_name"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "privilege", "USAGE"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: functionGrantConfig(name, onAll, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_function_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_function_grant.test", "function_name"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_function_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_function_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func functionGrantConfig(name string, grantType grantType, privilege, databaseName, schemaName string) string { - var functionNameConfig string - switch grantType { - case onFuture: - functionNameConfig = "on_future = true" - case onAll: - functionNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource snowflake_role test { - name = "%s" -} - -resource "snowflake_function_grant" "test" { - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - %s - privilege = "%s" -} -`, name, databaseName, schemaName, functionNameConfig, privilege) -} diff --git a/pkg/resources/grant_helpers.go b/pkg/resources/grant_helpers.go index 6217041957..16a422f493 100644 --- a/pkg/resources/grant_helpers.go +++ b/pkg/resources/grant_helpers.go @@ -1,407 +1,20 @@ package resources import ( - "database/sql" - "log" "strings" - "time" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/jmoiron/sqlx" - "github.com/snowflakedb/gosnowflake" ) -// TerraformGrantResource augments terraform's *schema.Resource with extra context. -type TerraformGrantResource struct { - Resource *schema.Resource - ValidPrivs PrivilegeSet -} - -type TerraformGrantResources map[string]*TerraformGrantResource - -func (t TerraformGrantResources) GetTfSchemas() map[string]*schema.Resource { - out := map[string]*schema.Resource{} - for name, grant := range t { - out[name] = grant.Resource - } - return out -} - -// currentGrant represents a generic grant of a privilege from a grant (the target) to a -// grantee. This type can be used in conjunction with github.com/jmoiron/sqlx to -// build a nice go representation of a grant. -type currentGrant struct { - CreatedOn time.Time `db:"created_on"` - Privilege string `db:"privilege"` - GrantType string `db:"granted_on"` - GrantName string `db:"name"` - GranteeType string `db:"granted_to"` - GranteeName string `db:"grantee_name"` - GrantOption bool `db:"grant_option"` - GrantedBy string `db:"granted_by"` -} - -// futureGrant represents the columns in the response from `SHOW FUTURE GRANTS -// IN SCHEMA...` and can be used in conjunction with sqlx. -type futureGrant struct { - CreatedOn time.Time `db:"created_on"` - Privilege string `db:"privilege"` - GrantType string `db:"grant_on"` - GrantName string `db:"name"` - GranteeType string `db:"grant_to"` - GranteeName string `db:"grantee_name"` - GrantOption bool `db:"grant_option"` -} - -// grant is simply the least common denominator of fields in currentGrant and -// futureGrant. -type grant struct { - CreatedOn time.Time - Privilege string - GrantType string - GrantName string - GranteeType string - GranteeName string - GrantOption bool -} - -// createGenericGrantRolesAndShares will create generic grants for a set of roles and shares. -func createGenericGrantRolesAndShares( - meta interface{}, - builder snowflake.GrantBuilder, - priv string, - grantOption bool, - roles []string, - shares []string, -) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - for _, role := range roles { - if err := snowflake.Exec(db, builder.Role(role).Grant(priv, grantOption)); err != nil { - return err - } - } - - for _, share := range shares { - if err := snowflake.Exec(db, builder.Share(share).Grant(priv, grantOption)); err != nil { - return err - } - } - return nil -} - -func createGenericGrant(d *schema.ResourceData, meta interface{}, builder snowflake.GrantBuilder) error { - priv := d.Get("privilege").(string) - grantOption := d.Get("with_grant_option").(bool) - roles, shares := expandRolesAndShares(d) - - return createGenericGrantRolesAndShares( - meta, - builder, - priv, - grantOption, - roles, - shares, - ) -} - -func readGenericGrant( - d *schema.ResourceData, - meta interface{}, - grantSchema map[string]*schema.Schema, - builder snowflake.GrantBuilder, - futureObjects bool, - allObjects bool, - _ PrivilegeSet, -) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - var grants []*grant - var err error - - priv := d.Get("privilege").(string) - - if priv == "ALL PRIVILEGES" { - // When running e.g. GRANT ALL PRIVILEGES ON TABLE TO ROLE ..., then Snowflake creates a grant for each individual permission - // There is no way to attribute existing grants to a GRANT ALL PRIVILEGES grant. Thus they cannot be checked. However they can still be revoked. - return nil - } - switch { - case futureObjects: - grants, err = readGenericFutureGrants(db, builder) - case allObjects: - // When running e.g. GRANT SELECT ON ALL TABLES IN ..., then Snowflake creates a grant for each individual existing table. - // There is no way to attribute existing table grants to a GRANT SELECT ON ALL TABLES grant. Thus they cannot be checked (or removed). - return nil - default: - grants, err = readGenericCurrentGrants(db, builder) - } - if err != nil { - // HACK HACK: If the object doesn't exist or not authorized then we can assume someone deleted it - // We also check the error number matches - // We set the tf id == blank and return. - // I don't know of a better way to work around this issue - if snowflakeErr, ok := err.(*gosnowflake.SnowflakeError); ok && //nolint:errorlint // todo: should be fixed - snowflakeErr.Number == 2003 && - strings.Contains(err.Error(), "does not exist or not authorized") { - log.Printf("[WARN] resource (%s) not found, removing from state file", d.Id()) - d.SetId("") - return nil - } - return err - } - - grantOption := d.Get("with_grant_option").(bool) - - // Map of roles to privileges - rolePrivileges := map[string]PrivilegeSet{} - sharePrivileges := map[string]PrivilegeSet{} - - // List of all grants for each schema_database - for _, grant := range grants { - switch grant.GranteeType { - case "ROLE": - roleName := grant.GranteeName - // Find set of privileges - privileges, ok := rolePrivileges[roleName] - if !ok { - // If not there, create an empty set - privileges = PrivilegeSet{} - } - - if strings.ReplaceAll(builder.GrantType(), " ", "_") == grant.GrantType { - privileges.addString(grant.Privilege) - } - // Reassign set back - rolePrivileges[roleName] = privileges - case "SHARE": - // Strip account name from grantee name - s := grant.GranteeName - granteeNameStrippedAccount := s[strings.LastIndex(s, ".")+1:] - // Find set of privileges - privileges, ok := sharePrivileges[granteeNameStrippedAccount] - if !ok { - // If not there, create an empty set - privileges = PrivilegeSet{} - } - // Add privilege to the set - privileges.addString(grant.Privilege) - // Reassign set back - sharePrivileges[granteeNameStrippedAccount] = privileges - case "DATABASE_ROLE": - log.Printf("[WARN] DATABASE_ROLE is not supported by grant helpers") - case "APPLICATION_ROLE": - log.Printf("[WARN] APPLICATION_ROLE is not supported by grant helpers") - } - } - - existingRoles := schema.NewSet(schema.HashString, []interface{}{}) - if v, ok := d.GetOk("roles"); ok && v != nil { - existingRoles = v.(*schema.Set) - } - multipleGrantFeatureFlag := d.Get("enable_multiple_grants").(bool) - var roles, shares []string - // Now see which roles have our privilege. - for roleName, privileges := range rolePrivileges { - if privileges.hasString(priv) { - // CASE A: Whatever role we were already managing, continue to do so. - caseA := existingRoles.Contains(roleName) - // CASE B : If multiple grants is not enabled (meaning this is an authoritative resource) then we care about what roles have privilege unless on_future is enabled in which case we don't care (because we will get flooded with diffs) - caseB := !multipleGrantFeatureFlag && !futureObjects - if caseA || caseB { - roles = append(roles, roleName) - } - } - } - - existingShares := schema.NewSet(schema.HashString, []interface{}{}) - if v, ok := d.GetOk("shares"); ok && v != nil { - existingShares = v.(*schema.Set) - } - // Now see which shares have our privilege. - for shareName, privileges := range sharePrivileges { - if privileges.hasString(priv) { - // CASE A: Whatever share we were already managing, continue to do so. - caseA := existingShares.Contains(shareName) - // CASE B : If multiple grants is not enabled (meaning this is an authoritative resource) then we care about what shares have privilege unless on_future is enabled in which case we don't care (because we will get flooded with diffs) - caseB := !multipleGrantFeatureFlag && !futureObjects - if caseA || caseB { - shares = append(shares, shareName) - } - } - } - - if err := d.Set("privilege", priv); err != nil { - return err - } - if err := d.Set("roles", roles); err != nil { - return err - } - - _, sharesOk := grantSchema["shares"] - if sharesOk && !futureObjects { - if err := d.Set("shares", shares); err != nil { - return err - } - } - if err := d.Set("with_grant_option", grantOption); err != nil { - return err - } - return nil -} - -func readGenericCurrentGrants(db *sql.DB, builder snowflake.GrantBuilder) ([]*grant, error) { - stmt := builder.Show() - rows, err := snowflake.Query(db, stmt) - if err != nil { - return nil, err - } - defer rows.Close() - - var grants []*grant - for rows.Next() { - currentGrant := ¤tGrant{} - if err := rows.StructScan(currentGrant); err != nil { - return nil, err - } - if currentGrant.GrantedBy == "" { - // If GrantedBy is empty string, terraform can't - // manage the grant because the grant is a default - // grant seeded by Snowflake. - continue - } - - grant := &grant{ - CreatedOn: currentGrant.CreatedOn, - Privilege: currentGrant.Privilege, - GrantType: currentGrant.GrantType, - GrantName: currentGrant.GrantName, - GranteeType: currentGrant.GranteeType, - GranteeName: currentGrant.GranteeName, - GrantOption: currentGrant.GrantOption, - } - grants = append(grants, grant) - } - - return grants, nil -} - -func readGenericFutureGrants(db *sql.DB, builder snowflake.GrantBuilder) ([]*grant, error) { - conn := sqlx.NewDb(db, "snowflake") - - stmt := builder.Show() - rows, err := conn.Queryx(stmt) - if err != nil { - return nil, err - } - defer rows.Close() - - var grants []*grant - for rows.Next() { - futureGrant := &futureGrant{} - if err := rows.StructScan(futureGrant); err != nil { - return nil, err - } - grant := &grant{ - CreatedOn: futureGrant.CreatedOn, - Privilege: futureGrant.Privilege, - GrantType: futureGrant.GrantType, - GrantName: futureGrant.GrantName, - GranteeType: futureGrant.GranteeType, - GranteeName: futureGrant.GranteeName, - GrantOption: futureGrant.GrantOption, - } - grants = append(grants, grant) - } - - return grants, nil -} - -// Deletes specific roles and shares from a grant -// Does not modify TF remote state. -func deleteGenericGrantRolesAndShares( - meta interface{}, - builder snowflake.GrantBuilder, - priv string, - reversionRole string, - roles []string, - shares []string, -) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - - for _, role := range roles { - executable := builder.Role(role).Revoke(priv) - if priv == "OWNERSHIP" { - executable = builder.Role(role).RevokeOwnership(reversionRole) - } - if err := snowflake.ExecMulti(db, executable); err != nil { - return err - } - } - - for _, share := range shares { - executable := builder.Share(share).Revoke(priv) - if priv == "OWNERSHIP" { - executable = builder.Share(share).RevokeOwnership(reversionRole) - } - if err := snowflake.ExecMulti(db, executable); err != nil { - return err - } - } - return nil -} - -func deleteGenericGrant(d *schema.ResourceData, meta interface{}, builder snowflake.GrantBuilder) error { - priv := d.Get("privilege").(string) - rr := d.Get("revert_ownership_to_role_name") - var reversionRole string - if rr != nil { - reversionRole = rr.(string) - } - roles, shares := expandRolesAndShares(d) - if err := deleteGenericGrantRolesAndShares(meta, builder, priv, reversionRole, roles, shares); err != nil { - return err - } - d.SetId("") - return nil -} - -func expandRolesAndShares(d *schema.ResourceData) ([]string, []string) { - var roles, shares []string - if _, ok := d.GetOk("roles"); ok { - roles = expandStringList(d.Get("roles").(*schema.Set).List()) - } - - if _, ok := d.GetOk("shares"); ok { - shares = expandStringList(d.Get("shares").(*schema.Set).List()) - } - return roles, shares -} - -// changeDiff calculates roles/shares to add/revoke. -func changeDiff(d *schema.ResourceData, key string) (toAdd []string, toRemove []string) { - o, n := d.GetChange(key) - oldSet := o.(*schema.Set) - newSet := n.(*schema.Set) - toAdd = expandStringList(newSet.Difference(oldSet).List()) - 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)", + Severity: diag.Error, + Summary: "Unsupported privilege 'OWNERSHIP'", + Detail: "Granting ownership is only allowed in snowflake_grant_ownership resource.", AttributePath: nil, }) } diff --git a/pkg/resources/grant_privileges_to_role.go b/pkg/resources/grant_privileges_to_role.go deleted file mode 100644 index 357e26d36b..0000000000 --- a/pkg/resources/grant_privileges_to_role.go +++ /dev/null @@ -1,895 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "log" - "slices" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/logging" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var grantPrivilegesToRoleSchema = map[string]*schema.Schema{ - // According to docs https://docs.snowflake.com/en/user-guide/data-exchange-marketplace-privileges#usage-notes IMPORTED PRIVILEGES - // will be returned as USAGE in SHOW GRANTS command. In addition, USAGE itself is a valid privilege, but both cannot be set at the - // same time (IMPORTED PRIVILEGES can only be granted to the database created from SHARE and USAGE in every other case). - // To handle both cases, additional logic was added in read operation where IMPORTED PRIVILEGES is replaced with USAGE. - "privileges": { - Type: schema.TypeSet, - Optional: true, - Description: "The privileges to grant on the account role.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - ConflictsWith: []string{ - "all_privileges", - }, - }, - "all_privileges": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Grant all privileges on the account role.", - ConflictsWith: []string{ - "privileges", - }, - }, - "on_account": { - Type: schema.TypeBool, - Optional: true, - Default: false, - ForceNew: true, - Description: "If true, the privileges will be granted on the account.", - ConflictsWith: []string{"on_account_object", "on_schema", "on_schema_object"}, - }, - "on_account_object": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - MaxItems: 1, - ConflictsWith: []string{"on_account", "on_schema", "on_schema_object"}, - Description: "Specifies the account object on which privileges will be granted ", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "object_type": { - Type: schema.TypeString, - Required: true, - Description: "The object type of the account object on which privileges will be granted. Valid values are: USER | RESOURCE MONITOR | WAREHOUSE | DATABASE | INTEGRATION | FAILOVER GROUP | REPLICATION GROUP | EXTERNAL VOLUME", - ValidateFunc: validation.StringInSlice([]string{ - "USER", - "RESOURCE MONITOR", - "WAREHOUSE", - "DATABASE", - "INTEGRATION", - "FAILOVER GROUP", - "REPLICATION GROUP", - "EXTERNAL VOLUME", - }, true), - }, - "object_name": { - Type: schema.TypeString, - Required: 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, - MaxItems: 1, - ConflictsWith: []string{"on_account", "on_account_object", "on_schema_object"}, - Description: "Specifies the schema on which privileges will be granted.", - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The fully qualified name of the schema.", - ConflictsWith: []string{"on_schema.0.all_schemas_in_database", "on_schema.0.future_schemas_in_database"}, - ForceNew: true, - ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](), - }, - "all_schemas_in_database": { - Type: schema.TypeString, - Optional: true, - Description: "The fully qualified name of the database.", - ConflictsWith: []string{"on_schema.0.schema_name", "on_schema.0.future_schemas_in_database"}, - ForceNew: true, - ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), - }, - "future_schemas_in_database": { - Type: schema.TypeString, - Optional: true, - Description: "The fully qualified name of the database.", - ConflictsWith: []string{"on_schema.0.schema_name", "on_schema.0.all_schemas_in_database"}, - ForceNew: true, - ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), - }, - }, - }, - }, - "on_schema_object": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - ConflictsWith: []string{"on_account", "on_account_object", "on_schema"}, - Description: "Specifies the schema object on which privileges will be granted.", - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "object_type": { - Type: schema.TypeString, - Optional: true, - Description: fmt.Sprintf("The object type of the schema object on which privileges will be granted. Valid values are: %s", strings.Join(sdk.ValidGrantToObjectTypesString, " | ")), - RequiredWith: []string{"on_schema_object.0.object_name"}, - ConflictsWith: []string{"on_schema_object.0.all", "on_schema_object.0.future"}, - ForceNew: true, - ValidateDiagFunc: StringInSlice(sdk.ValidGrantToObjectTypesString, true), - }, - "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"}, - ConflictsWith: []string{"on_schema_object.0.all", "on_schema_object.0.future"}, - ValidateDiagFunc: IsValidIdentifier[sdk.SchemaObjectIdentifier](), - }, - "all": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "Configures the privilege to be granted on all objects in eihter a database or schema.", - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "object_type_plural": { - Type: schema.TypeString, - Required: true, - Description: fmt.Sprintf("The plural object type of the schema object on which privileges will be granted. Valid values are: %s", strings.Join(sdk.ValidGrantToPluralObjectTypesString, " | ")), - ForceNew: true, - ValidateDiagFunc: StringInSlice(sdk.ValidGrantToPluralObjectTypesString, true), - }, - "in_database": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The fully qualified name of the database.", - ConflictsWith: []string{"on_schema_object.0.all.in_schema"}, - ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), - }, - "in_schema": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Description: "The fully qualified name of the schema.", - ConflictsWith: []string{"on_schema_object.0.all.in_database"}, - ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](), - }, - }, - }, - }, - "future": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Description: "Configures the privilege to be granted on future objects in eihter a database or schema.", - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "object_type_plural": { - Type: schema.TypeString, - Required: true, - Description: fmt.Sprintf("The plural object type of the schema object on which privileges will be granted. Valid values are: %s", strings.Join(sdk.ValidGrantToFuturePluralObjectTypesString, " | ")), - ForceNew: true, - ValidateDiagFunc: StringInSlice(sdk.ValidGrantToFuturePluralObjectTypesString, true), - }, - "in_database": { - Type: schema.TypeString, - Optional: true, - Description: "The fully qualified name of the database.", - ConflictsWith: []string{"on_schema_object.0.all.in_schema"}, - ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), - ForceNew: true, - }, - "in_schema": { - Type: schema.TypeString, - Optional: true, - Description: "The fully qualified name of the schema.", - ConflictsWith: []string{"on_schema_object.0.all.in_database"}, - ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](), - ForceNew: true, - }, - }, - }, - }, - }, - }, - }, - "role_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The fully qualified name of the role to which privileges will be granted.", - ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "Specifies whether the grantee can grant the privileges to other users.", - Default: false, - ForceNew: true, - }, -} - -func GrantPrivilegesToRole() *schema.Resource { - return &schema.Resource{ - 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 := NewGrantPrivilegesToRoleID(d.Id()) - if err := d.Set("role_name", resourceID.RoleName); err != nil { - return nil, err - } - if err := d.Set("privileges", resourceID.Privileges); err != nil { - return nil, err - } - if err := d.Set("all_privileges", resourceID.AllPrivileges); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", resourceID.WithGrantOption); err != nil { - return nil, err - } - if err := d.Set("on_account", resourceID.OnAccount); err != nil { - return nil, err - } - if resourceID.OnAccountObject { - if err := d.Set("on_account_object", []map[string]interface{}{{ - "object_type": resourceID.ObjectType, - "object_name": resourceID.ObjectName, - }}); err != nil { - return nil, err - } - } - if resourceID.OnSchema { - var onSchema []interface{} - if resourceID.SchemaName != "" { - onSchema = append(onSchema, map[string]interface{}{ - "schema_name": resourceID.SchemaName, - }) - } - if resourceID.All { - onSchema = append(onSchema, map[string]interface{}{ - "all_schemas_in_database": resourceID.DatabaseName, - }) - } - if resourceID.Future { - onSchema = append(onSchema, map[string]interface{}{ - "future_schemas_in_database": resourceID.DatabaseName, - }) - } - if err := d.Set("on_schema", onSchema); err != nil { - return nil, err - } - } - - if resourceID.OnSchemaObject { - var onSchemaObject []interface{} - if resourceID.ObjectName != "" { - onSchemaObject = append(onSchemaObject, map[string]interface{}{ - "object_name": resourceID.ObjectName, - "object_type": resourceID.ObjectType, - }) - } - if resourceID.All { - all := make([]interface{}, 0) - m := map[string]interface{}{ - "object_type_plural": resourceID.ObjectTypePlural, - } - - if resourceID.InSchema { - m["in_schema"] = resourceID.SchemaName - } - if resourceID.InDatabase { - m["in_database"] = resourceID.DatabaseName - } - all = append(all, m) - onSchemaObject = append(onSchemaObject, map[string]interface{}{ - "all": all, - }) - } - if resourceID.Future { - future := make([]interface{}, 0) - m := map[string]interface{}{ - "object_type_plural": resourceID.ObjectTypePlural, - } - if resourceID.InSchema { - m["in_schema"] = resourceID.SchemaName - } - if resourceID.InDatabase { - m["in_database"] = resourceID.DatabaseName - } - future = append(future, m) - onSchemaObject = append(onSchemaObject, map[string]interface{}{ - "future": future, - }) - } - if err := d.Set("on_schema_object", onSchemaObject); err != nil { - return nil, err - } - } - - return []*schema.ResourceData{d}, nil - }, - }, - } -} - -// we need to keep track of literally everything to construct a unique identifier that can be imported -type GrantPrivilegesToRoleID struct { - RoleName string - Privileges []string - AllPrivileges bool - WithGrantOption bool - OnAccount bool - OnAccountObject bool - OnSchema bool - OnSchemaObject bool - All bool - Future bool - ObjectType string - ObjectName string - ObjectTypePlural string - InSchema bool - SchemaName string - InDatabase bool - DatabaseName string -} - -func NewGrantPrivilegesToRoleID(id string) GrantPrivilegesToRoleID { - parts := strings.Split(id, "|") - privileges := strings.Split(parts[1], ",") - if len(privileges) == 1 && privileges[0] == "" { - privileges = []string{} - } - return GrantPrivilegesToRoleID{ - RoleName: parts[0], - Privileges: privileges, - AllPrivileges: parts[2] == "true", - WithGrantOption: parts[3] == "true", - OnAccount: parts[4] == "true", - OnAccountObject: parts[5] == "true", - OnSchema: parts[6] == "true", - OnSchemaObject: parts[7] == "true", - All: parts[8] == "true", - Future: parts[9] == "true", - ObjectType: parts[10], - ObjectName: parts[11], - ObjectTypePlural: parts[12], - InSchema: parts[13] == "true", - SchemaName: parts[14], - InDatabase: parts[15] == "true", - DatabaseName: parts[16], - } -} - -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) -} - -func CreateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error { - logging.DebugLogger.Printf("[DEBUG] Entering create grant privileges to role") - client := meta.(*provider.Context).Client - logging.DebugLogger.Printf("[DEBUG] Creating new client from db") - ctx := context.Background() - resourceID := &GrantPrivilegesToRoleID{} - var privileges []string - if p, ok := d.GetOk("privileges"); ok { - logging.DebugLogger.Printf("[DEBUG] Building privileges list based on config") - privileges = expandStringList(p.(*schema.Set).List()) - resourceID.Privileges = privileges - } - allPrivileges := d.Get("all_privileges").(bool) - resourceID.AllPrivileges = allPrivileges - privilegesToGrant, on, err := configureRoleGrantPrivilegeOptions(d, privileges, allPrivileges, resourceID) - if err != nil { - return fmt.Errorf("error configuring account role grant privilege options: %w", err) - } - withGrantOption := d.Get("with_grant_option").(bool) - resourceID.WithGrantOption = withGrantOption - opts := sdk.GrantPrivilegesToAccountRoleOptions{ - WithGrantOption: sdk.Bool(withGrantOption), - } - roleName := d.Get("role_name").(string) - resourceID.RoleName = roleName - roleID := sdk.NewAccountObjectIdentifier(roleName) - logging.DebugLogger.Printf("[DEBUG] About to grant privileges to account role") - err = client.Grants.GrantPrivilegesToAccountRole(ctx, privilegesToGrant, on, roleID, &opts) - logging.DebugLogger.Printf("[DEBUG] After granting privileges to account role: err = %v", err) - if err != nil { - return fmt.Errorf("error granting privileges to account role: %w", err) - } - - logging.DebugLogger.Printf("[DEBUG] Setting ID to %s", resourceID.String()) - d.SetId(resourceID.String()) - return ReadGrantPrivilegesToRole(d, meta) -} - -func ReadGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error { - logging.DebugLogger.Printf("[DEBUG] Entering read grant privileges to role") - client := meta.(*provider.Context).Client - logging.DebugLogger.Printf("[DEBUG] Creating new client from db") - ctx := context.Background() - resourceID := NewGrantPrivilegesToRoleID(d.Id()) - roleName := resourceID.RoleName - allPrivileges := resourceID.AllPrivileges - if allPrivileges { - log.Printf("[DEBUG] cannot read ALL PRIVILEGES on grant to role %s because this is not returned by API", roleName) - return nil // cannot read all privileges because its not something returned by API. We can check only if specific privileges are granted to the role - } - var opts sdk.ShowGrantOptions - var grantOn sdk.ObjectType - if resourceID.OnAccount { - logging.DebugLogger.Printf("[DEBUG] Preparing to read privileges: on account") - grantOn = sdk.ObjectTypeAccount - opts = sdk.ShowGrantOptions{ - On: &sdk.ShowGrantsOn{ - Account: sdk.Bool(true), - }, - } - } - - if resourceID.OnAccountObject { - logging.DebugLogger.Printf("[DEBUG] Preparing to read privileges: on account object") - objectType := sdk.ObjectType(resourceID.ObjectType) - grantOn = objectType - opts = sdk.ShowGrantOptions{ - On: &sdk.ShowGrantsOn{ - Object: &sdk.Object{ - ObjectType: objectType, - Name: sdk.NewAccountObjectIdentifierFromFullyQualifiedName(resourceID.ObjectName), - }, - }, - } - } - - if resourceID.OnSchema { - logging.DebugLogger.Printf("[DEBUG] Preparing to read privileges: on schema") - grantOn = sdk.ObjectTypeSchema - if resourceID.SchemaName != "" { - opts = sdk.ShowGrantOptions{ - On: &sdk.ShowGrantsOn{ - Object: &sdk.Object{ - ObjectType: sdk.ObjectTypeSchema, - Name: sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(resourceID.SchemaName), - }, - }, - } - } - if resourceID.All { - log.Printf("[DEBUG] cannot read ALL SCHEMAS IN DATABASE on grant to role %s because this is not returned by API", roleName) - return nil // on_all is not supported by API - } - if resourceID.Future { - opts = sdk.ShowGrantOptions{ - Future: sdk.Bool(true), - In: &sdk.ShowGrantsIn{ - Database: sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(resourceID.DatabaseName)), - }, - } - } - } - - if resourceID.OnSchemaObject { - logging.DebugLogger.Printf("[DEBUG] Preparing to read privileges: on schema object") - if resourceID.ObjectName != "" { - objectType := sdk.ObjectType(resourceID.ObjectType) - grantOn = objectType - opts = sdk.ShowGrantOptions{ - On: &sdk.ShowGrantsOn{ - Object: &sdk.Object{ - ObjectType: objectType, - Name: sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(resourceID.ObjectName), - }, - }, - } - } - - if resourceID.All { - return nil // on_all is not supported by API - } - - if resourceID.Future { - grantOn = sdk.PluralObjectType(resourceID.ObjectTypePlural).Singular() - if resourceID.InSchema { - opts = sdk.ShowGrantOptions{ - Future: sdk.Bool(true), - In: &sdk.ShowGrantsIn{ - Schema: sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(resourceID.SchemaName)), - }, - } - } - if resourceID.InDatabase { - opts = sdk.ShowGrantOptions{ - Future: sdk.Bool(true), - In: &sdk.ShowGrantsIn{ - Database: sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(resourceID.DatabaseName)), - }, - } - } - } - } - - err := readRoleGrantPrivileges(ctx, client, grantOn, resourceID, &opts, d) - if err != nil { - return err - } - return nil -} - -func UpdateGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error { - logging.DebugLogger.Printf("[DEBUG] Entering update grant privileges to role") - client := meta.(*provider.Context).Client - logging.DebugLogger.Printf("[DEBUG] Creating new client from db") - ctx := context.Background() - - // the only thing that can change is "privileges" - roleName := d.Get("role_name").(string) - roleID := sdk.NewAccountObjectIdentifier(roleName) - - logging.DebugLogger.Printf("[DEBUG] Checking if privileges have changed") - if d.HasChange("privileges") { - logging.DebugLogger.Printf("[DEBUG] Privileges have changed") - old, new := d.GetChange("privileges") - oldPrivileges := expandStringList(old.(*schema.Set).List()) - newPrivileges := expandStringList(new.(*schema.Set).List()) - - addPrivileges := []string{} - removePrivileges := []string{} - for _, oldPrivilege := range oldPrivileges { - if !slices.Contains(newPrivileges, oldPrivilege) { - removePrivileges = append(removePrivileges, oldPrivilege) - } - } - - for _, newPrivilege := range newPrivileges { - if !slices.Contains(oldPrivileges, newPrivilege) { - addPrivileges = append(addPrivileges, newPrivilege) - } - } - - // first add new privileges - if len(addPrivileges) > 0 { - logging.DebugLogger.Printf("[DEBUG] Adding new privileges") - privilegesToGrant, on, err := configureRoleGrantPrivilegeOptions(d, addPrivileges, false, &GrantPrivilegesToRoleID{}) - if err != nil { - return fmt.Errorf("error configuring account role grant privilege options: %w", err) - } - logging.DebugLogger.Printf("[DEBUG] About to grant privileges to account role") - err = client.Grants.GrantPrivilegesToAccountRole(ctx, privilegesToGrant, on, roleID, nil) - logging.DebugLogger.Printf("[DEBUG] After granting privileges to account role: err = %v", err) - if err != nil { - return fmt.Errorf("error granting privileges to account role: %w", err) - } - } - - // then remove old privileges - if len(removePrivileges) > 0 { - logging.DebugLogger.Printf("[DEBUG] Removing old privileges") - privilegesToRevoke, on, err := configureRoleGrantPrivilegeOptions(d, removePrivileges, false, &GrantPrivilegesToRoleID{}) - if err != nil { - return fmt.Errorf("error configuring account role grant privilege options: %w", err) - } - logging.DebugLogger.Printf("[DEBUG] About to revoke privileges from account role") - err = client.Grants.RevokePrivilegesFromAccountRole(ctx, privilegesToRevoke, on, roleID, nil) - logging.DebugLogger.Printf("[DEBUG] After revoking privileges from account role: err = %v", err) - if err != nil { - return fmt.Errorf("error revoking privileges from account role: %w", err) - } - } - logging.DebugLogger.Printf("[DEBUG] Setting new values") - resourceID := NewGrantPrivilegesToRoleID(d.Id()) - resourceID.Privileges = newPrivileges - d.SetId(resourceID.String()) - } - return ReadGrantPrivilegesToRole(d, meta) -} - -func DeleteGrantPrivilegesToRole(d *schema.ResourceData, meta interface{}) error { - logging.DebugLogger.Printf("[DEBUG] Entering delete grant privileges to role") - client := meta.(*provider.Context).Client - logging.DebugLogger.Printf("[DEBUG] Creating new client from db") - ctx := context.Background() - - roleName := d.Get("role_name").(string) - roleID := sdk.NewAccountObjectIdentifier(roleName) - - var privileges []string - if p, ok := d.GetOk("privileges"); ok { - privileges = expandStringList(p.(*schema.Set).List()) - } - allPrivileges := d.Get("all_privileges").(bool) - privilegesToRevoke, on, err := configureRoleGrantPrivilegeOptions(d, privileges, allPrivileges, &GrantPrivilegesToRoleID{}) - if err != nil { - return fmt.Errorf("error configuring account role grant privilege options: %w", err) - } - logging.DebugLogger.Printf("[DEBUG] About to revoke privileges from account role") - err = client.Grants.RevokePrivilegesFromAccountRole(ctx, privilegesToRevoke, on, roleID, nil) - logging.DebugLogger.Printf("[DEBUG] After revoking privileges from account role: err = %v", err) - if err != nil { - return fmt.Errorf("error revoking privileges from account role: %w", err) - } - logging.DebugLogger.Printf("[DEBUG] Cleaning resource id") - d.SetId("") - return nil -} - -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{} - if v, ok := d.GetOk("on_account"); ok && v.(bool) { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: on account") - on.Account = sdk.Bool(true) - resourceID.OnAccount = true - privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, true, false, false, false) - return privilegesToGrant, &on, nil - } - - if v, ok := d.GetOk("on_account_object"); ok && len(v.([]interface{})) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: on account object") - on.AccountObject = &sdk.GrantOnAccountObject{} - resourceID.OnAccountObject = true - onAccountObject := v.([]interface{})[0].(map[string]interface{}) - objectType := sdk.ObjectType(onAccountObject["object_type"].(string)) - resourceID.ObjectType = objectType.String() - objectName := onAccountObject["object_name"].(string) - resourceID.ObjectName = objectName - objectID := sdk.NewAccountObjectIdentifierFromFullyQualifiedName(objectName) - switch objectType { - case sdk.ObjectTypeDatabase: - on.AccountObject.Database = &objectID - case sdk.ObjectTypeFailoverGroup: - on.AccountObject.FailoverGroup = &objectID - case sdk.ObjectTypeIntegration: - on.AccountObject.Integration = &objectID - case sdk.ObjectTypeReplicationGroup: - on.AccountObject.ReplicationGroup = &objectID - case sdk.ObjectTypeResourceMonitor: - on.AccountObject.ResourceMonitor = &objectID - case sdk.ObjectTypeUser: - on.AccountObject.User = &objectID - case sdk.ObjectTypeWarehouse: - on.AccountObject.Warehouse = &objectID - case sdk.ObjectTypeExternalVolume: - on.AccountObject.ExternalVolume = &objectID - default: - return nil, nil, fmt.Errorf("invalid object type %s", objectType) - } - privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, false, true, false, false) - return privilegesToGrant, &on, nil - } - - if v, ok := d.GetOk("on_schema"); ok && len(v.([]interface{})) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: on schema") - onSchema := v.([]interface{})[0].(map[string]interface{}) - on.Schema = &sdk.GrantOnSchema{} - resourceID.OnSchema = true - if v, ok := onSchema["schema_name"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting schema name") - resourceID.SchemaName = v.(string) - on.Schema.Schema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(v.(string))) - } - if v, ok := onSchema["all_schemas_in_database"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting all schemas in database") - resourceID.All = true - resourceID.InDatabase = true - resourceID.DatabaseName = v.(string) - on.Schema.AllSchemasInDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(v.(string))) - } - - if v, ok := onSchema["future_schemas_in_database"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting future schemas in database") - resourceID.Future = true - resourceID.InDatabase = true - resourceID.DatabaseName = v.(string) - on.Schema.FutureSchemasInDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(v.(string))) - } - privilegesToGrant = setRolePrivilegeOptions(privileges, allPrivileges, false, false, true, false) - return privilegesToGrant, &on, nil - } - - if v, ok := d.GetOk("on_schema_object"); ok && len(v.([]interface{})) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: on schema object") - onSchemaObject := v.([]interface{})[0].(map[string]interface{}) - on.SchemaObject = &sdk.GrantOnSchemaObject{} - resourceID.OnSchemaObject = true - if v, ok := onSchemaObject["object_type"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting schema object type") - resourceID.ObjectType = v.(string) - on.SchemaObject.SchemaObject = &sdk.Object{ - ObjectType: sdk.ObjectType(v.(string)), - } - } - if v, ok := onSchemaObject["object_name"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting schema object name") - resourceID.ObjectName = v.(string) - on.SchemaObject.SchemaObject.Name = sdk.Pointer(sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(v.(string))) - } - if v, ok := onSchemaObject["all"]; ok && len(v.([]interface{})) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting all") - all := v.([]interface{})[0].(map[string]interface{}) - on.SchemaObject.All = &sdk.GrantOnSchemaObjectIn{} - resourceID.All = true - pluralObjectType := all["object_type_plural"].(string) - resourceID.ObjectTypePlural = pluralObjectType - on.SchemaObject.All.PluralObjectType = sdk.PluralObjectType(pluralObjectType) - if v, ok := all["in_database"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting all in database") - resourceID.InDatabase = true - resourceID.DatabaseName = v.(string) - on.SchemaObject.All.InDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(v.(string))) - } - if v, ok := all["in_schema"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting all in schema") - resourceID.InSchema = true - resourceID.SchemaName = v.(string) - on.SchemaObject.All.InSchema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(v.(string))) - } - } - - if v, ok := onSchemaObject["future"]; ok && len(v.([]interface{})) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting future") - future := v.([]interface{})[0].(map[string]interface{}) - resourceID.Future = true - on.SchemaObject.Future = &sdk.GrantOnSchemaObjectIn{} - pluralObjectType := future["object_type_plural"].(string) - resourceID.ObjectTypePlural = pluralObjectType - on.SchemaObject.Future.PluralObjectType = sdk.PluralObjectType(pluralObjectType) - if v, ok := future["in_database"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting future in database") - resourceID.InDatabase = true - resourceID.DatabaseName = v.(string) - on.SchemaObject.Future.InDatabase = sdk.Pointer(sdk.NewAccountObjectIdentifierFromFullyQualifiedName(v.(string))) - } - if v, ok := future["in_schema"]; ok && len(v.(string)) > 0 { - logging.DebugLogger.Printf("[DEBUG] Configuring account role grant privileges options: setting future in schema") - resourceID.InSchema = true - resourceID.SchemaName = v.(string) - on.SchemaObject.Future.InSchema = sdk.Pointer(sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(v.(string))) - } - } - - 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 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") - privilegesToGrant.AllPrivileges = sdk.Bool(true) - return privilegesToGrant - } - if onAccount { - logging.DebugLogger.Printf("[DEBUG] Setting global privileges on privileges to grant") - privilegesToGrant.GlobalPrivileges = []sdk.GlobalPrivilege{} - for _, privilege := range privileges { - privilegesToGrant.GlobalPrivileges = append(privilegesToGrant.GlobalPrivileges, sdk.GlobalPrivilege(privilege)) - } - return privilegesToGrant - } - if onAccountObject { - logging.DebugLogger.Printf("[DEBUG] Setting account object privileges on privileges to grant") - privilegesToGrant.AccountObjectPrivileges = []sdk.AccountObjectPrivilege{} - for _, privilege := range privileges { - privilegesToGrant.AccountObjectPrivileges = append(privilegesToGrant.AccountObjectPrivileges, sdk.AccountObjectPrivilege(privilege)) - } - return privilegesToGrant - } - if onSchema { - logging.DebugLogger.Printf("[DEBUG] Setting schema privileges on privileges to grant") - privilegesToGrant.SchemaPrivileges = []sdk.SchemaPrivilege{} - for _, privilege := range privileges { - privilegesToGrant.SchemaPrivileges = append(privilegesToGrant.SchemaPrivileges, sdk.SchemaPrivilege(privilege)) - } - return privilegesToGrant - } - if onSchemaObject { - logging.DebugLogger.Printf("[DEBUG] Setting schema object privileges on privileges to grant") - privilegesToGrant.SchemaObjectPrivileges = []sdk.SchemaObjectPrivilege{} - for _, privilege := range privileges { - privilegesToGrant.SchemaObjectPrivileges = append(privilegesToGrant.SchemaObjectPrivileges, sdk.SchemaObjectPrivilege(privilege)) - } - return privilegesToGrant - } - logging.DebugLogger.Printf("[DEBUG] Not setting any privileges on privileges to grant") - return nil -} - -func readRoleGrantPrivileges(ctx context.Context, client *sdk.Client, grantedOn sdk.ObjectType, id GrantPrivilegesToRoleID, opts *sdk.ShowGrantOptions, d *schema.ResourceData) error { - if _, err := client.Roles.ShowByID(ctx, sdk.NewAccountObjectIdentifier(id.RoleName)); err != nil && errors.Is(err, sdk.ErrObjectNotFound) { - d.SetId("") - log.Printf("[DEBUG] Failed to retrieve account role. Marking the resource as removed.") - return nil - } - - 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) - if err != nil { - if errors.Is(err, sdk.ErrObjectNotExistOrAuthorized) { - d.SetId("") - log.Printf("[DEBUG] Failed to show grants: %s. Marking object as removed.", err) - return nil - } - return fmt.Errorf("error retrieving grants for account role: %w", err) - } - - withGrantOption := d.Get("with_grant_option").(bool) - roleName := d.Get("role_name").(string) - - actualPrivileges := make([]string, 0) - expectedPrivileges := make([]string, 0) - expectedPrivileges = append(expectedPrivileges, id.Privileges...) - - if slices.ContainsFunc(expectedPrivileges, func(s string) bool { - return strings.ToUpper(s) == sdk.AccountObjectPrivilegeImportedPrivileges.String() - }) { - expectedPrivileges = append(expectedPrivileges, sdk.AccountObjectPrivilegeUsage.String()) - } - - logging.DebugLogger.Printf("[DEBUG] Filtering grants to be set on account: count = %d", len(grants)) - for _, grant := range grants { - // Only consider privileges that are already present in the ID so we - // don't delete privileges managed by other resources. - if !slices.Contains(expectedPrivileges, grant.Privilege) { - continue - } - if grant.GrantOption == withGrantOption && grant.GranteeName.Name() == sdk.NewAccountObjectIdentifier(roleName).Name() { - // future grants do not have grantedBy, only current grants do. If grantedby - // is an empty string it means the grant could not have been created by terraform - if !id.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 { - actualPrivileges = append(actualPrivileges, grant.Privilege) - } - } - } - - usageIndex := slices.IndexFunc(actualPrivileges, func(s string) bool { return strings.ToUpper(s) == sdk.AccountObjectPrivilegeUsage.String() }) - if slices.ContainsFunc(expectedPrivileges, func(s string) bool { - return strings.ToUpper(s) == sdk.AccountObjectPrivilegeImportedPrivileges.String() - }) && usageIndex >= 0 { - actualPrivileges[usageIndex] = sdk.AccountObjectPrivilegeImportedPrivileges.String() - } - - logging.DebugLogger.Printf("[DEBUG] Setting privileges on account") - if err := d.Set("privileges", actualPrivileges); err != nil { - logging.DebugLogger.Printf("[DEBUG] Error setting privileges for account role: err = %v", err) - return fmt.Errorf("error setting privileges for account role: %w", err) - } - return nil -} diff --git a/pkg/resources/grant_privileges_to_role_acceptance_test.go b/pkg/resources/grant_privileges_to_role_acceptance_test.go deleted file mode 100644 index 121f1484a2..0000000000 --- a/pkg/resources/grant_privileges_to_role_acceptance_test.go +++ /dev/null @@ -1,1164 +0,0 @@ -package resources_test - -import ( - "fmt" - "regexp" - "strings" - "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/config" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/plancheck" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_GrantPrivilegesToRole_onAccount(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onAccountConfig(name, []string{"MONITOR USAGE"}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account", "true"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MONITOR USAGE"), - ), - }, - // ADD PRIVILEGE - { - Config: grantPrivilegesToRole_onAccountConfig(name, []string{"MONITOR USAGE", "MANAGE GRANTS"}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account", "true"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MANAGE GRANTS"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "MONITOR USAGE"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -// TestAcc_GrantPrivilegesToRole_OnSchema_InfinitePlan proves the fix for infinite plan, that was occurring. -// The cause of it was incorrect comparison in the Read operation. When snowflake_grant_privileges_to_role.role_name -// contains escaped identifier, it won't match in the comparison grant.GranteeName == role_name. This results in -// setting privileges to an empty array, which causes infinite plan. -func TestAcc_GrantPrivilegesToRole_OnSchema_InfinitePlan(t *testing.T) { - name := []byte(acc.TestClient().Ids.Alpha()) - name[3] = '.' - name[7] = '-' - databaseName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - Steps: []resource.TestStep{ - { - Config: fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%s" - } - - resource "snowflake_database" "db" { - name = "%s" - } - - resource "snowflake_grant_privileges_to_role" "g" { - depends_on = [snowflake_role.r, snowflake_database.db] - privileges = ["CREATE SCHEMA"] - role_name = "\"${snowflake_role.r.name}\"" - on_account_object { - object_type = "DATABASE" - object_name = snowflake_database.db.name - } - } - `, string(name), databaseName), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PostApplyPostRefresh: []plancheck.PlanCheck{ - plancheck.ExpectEmptyPlan(), - }, - }, - }, - }, - }) -} - -/* - func TestAcc_GrantPrivilegesToRole_onAccountAllPrivileges(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onAccountConfigAllPrivileges(name), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account", "true"), - resource.TestCheckNoResourceAttr("snowflake_grant_privileges_to_role.g", "privileges"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "all_privileges", "true"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) - } -*/ -func grantPrivilegesToRole_onAccountConfig(name string, privileges []string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - privileges = [%v] - role_name = snowflake_role.r.name - on_account = true - } - `, name, privilegesString) -} - -func grantPrivilegesToRole_onAccountConfigAllPrivileges(name string) string { - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - all_privileges = true - role_name = snowflake_role.r.name - on_account = true - } - `, name) -} - -func TestAcc_GrantPrivilegesToRole_onAccountObject(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onAccountObjectConfig(name, []string{"CREATE DATABASE ROLE"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account_object.0.object_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account_object.0.object_type", "DATABASE"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "CREATE DATABASE ROLE"), - ), - }, - // ADD PRIVILEGE - { - Config: grantPrivilegesToRole_onAccountObjectConfig(name, []string{"MONITOR", "CREATE SCHEMA"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "CREATE SCHEMA"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "MONITOR"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_onAccountObjectAllPrivileges(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onAccountObjectConfigAllPrivileges(name, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account_object.0.object_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_account_object.0.object_type", "DATABASE"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "all_privileges", "true"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onAccountObjectConfig(name string, privileges []string, databaseName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - privileges = [%v] - role_name = snowflake_role.r.name - on_account_object { - object_type = "DATABASE" - object_name = "%s" - } - } - `, name, privilegesString, databaseName) -} - -func grantPrivilegesToRole_onAccountObjectConfigAllPrivileges(name string, databaseName string) string { - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - all_privileges = true - role_name = snowflake_role.r.name - on_account_object { - object_type = "DATABASE" - object_name = "%s" - } - } - `, name, databaseName) -} - -func TestAcc_GrantPrivilegesToRole_onSchema(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaConfig(name, []string{"MONITOR", "USAGE"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.0.schema_name", fmt.Sprintf("\"%v\".\"%v\"", acc.TestDatabaseName, acc.TestSchemaName)), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MONITOR"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "USAGE"), - ), - }, - // ADD PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaConfig(name, []string{"MONITOR"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MONITOR"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchemaConfig(name string, privileges []string, databaseName string, schemaName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema { - schema_name = "\"%s\".\"%s\"" - } - } - `, name, privilegesString, databaseName, schemaName) -} - -func grantPrivilegesToRole_onSchemaConfigAllPrivileges(name string, databaseName string, schemaName string) string { - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - all_privileges = true - on_schema { - schema_name = "\"%s\".\"%s\"" - } - } - `, name, databaseName, schemaName) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaConfigAllPrivileges(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaConfigAllPrivileges(name, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.0.schema_name", fmt.Sprintf("\"%v\".\"%v\"", acc.TestDatabaseName, acc.TestSchemaName)), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "all_privileges", "true"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_onSchema_allSchemasInDatabase(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchema_allSchemasInDatabaseConfig(name, []string{"MONITOR", "USAGE"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.0.all_schemas_in_database", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MONITOR"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "USAGE"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchema_allSchemasInDatabaseConfig(name, []string{"MONITOR"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MONITOR"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_onSchema_futureSchemasInDatabase(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchema_futureSchemasInDatabaseConfig(name, []string{"MONITOR", "USAGE"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema.0.future_schemas_in_database", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "MONITOR"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "USAGE"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchema_allSchemasInDatabaseConfig(name string, privileges []string, databaseName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema { - all_schemas_in_database = "%s" - - } - } - `, name, privilegesString, databaseName) -} - -func grantPrivilegesToRole_onSchema_futureSchemasInDatabaseConfig(name string, privileges []string, databaseName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema { - future_schemas_in_database = "%s" - - } - } - `, name, privilegesString, databaseName) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_objectType(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaObject_objectType(name, []string{"SELECT", "REFERENCES"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.object_type", "VIEW"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.object_name", fmt.Sprintf(`"%v"."%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName, name)), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "REFERENCES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "SELECT"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaObject_objectType(name, []string{"SELECT"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchemaObject_objectType(name string, privileges []string, databaseName string, schemaName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_view" "v" { - name = "%v" - database = "%s" - schema = "%s" - is_secure = true - statement = "SELECT ROLE_NAME, ROLE_OWNER FROM INFORMATION_SCHEMA.APPLICABLE_ROLES" - } - - resource "snowflake_grant_privileges_to_role" "g" { - depends_on = [ snowflake_view.v] - role_name = snowflake_role.r.name - privileges = [%s] - on_schema_object { - object_type = "VIEW" - object_name = "\"%s\".\"%s\".\"%s\"" - } - } - `, name, name, databaseName, schemaName, privilegesString, databaseName, schemaName, name) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_allInSchema(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaObject_allInSchema(name, []string{"SELECT", "REFERENCES"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.all.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.all.0.object_type_plural", "TABLES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.all.0.in_schema", fmt.Sprintf(`"%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName)), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "REFERENCES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "SELECT"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaObject_allInSchema(name, []string{"SELECT"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchemaObject_allInSchema(name string, privileges []string, databaseName string, schemaName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema_object { - all { - object_type_plural = "TABLES" - in_schema = "\"%s\".\"%s\"" - } - } - } - `, name, privilegesString, databaseName, schemaName) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_allInDatabase(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaObject_allInDatabase(name, []string{"SELECT", "REFERENCES"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.all.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.all.0.object_type_plural", "TABLES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.all.0.in_database", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "REFERENCES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "SELECT"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaObject_allInDatabase(name, []string{"SELECT"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchemaObject_allInDatabase(name string, privileges []string, databaseName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema_object { - all { - object_type_plural = "TABLES" - in_database = "%s" - } - } - } - `, name, privilegesString, databaseName) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_futureInSchema(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaObject_futureInSchema(name, []string{"SELECT", "REFERENCES"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.0.object_type_plural", "TABLES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.0.in_schema", fmt.Sprintf(`"%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName)), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "REFERENCES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "SELECT"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaObject_futureInSchema(name, []string{"SELECT"}, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchemaObject_futureInSchema(name string, privileges []string, databaseName string, schemaName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema_object { - future { - object_type_plural = "TABLES" - in_schema = "\"%s\".\"%s\"" - } - } - } - `, name, privilegesString, databaseName, schemaName) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_futureInDatabase(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - objectType := "TABLES" - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaObject_futureInDatabase(name, objectType, []string{"SELECT", "REFERENCES"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.0.object_type_plural", "TABLES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.0.in_database", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "REFERENCES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "SELECT"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaObject_futureInDatabase(name, objectType, []string{"SELECT"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_onSchemaObject_futureInDatabase(name string, objectType string, privileges []string, databaseName string) string { - doubleQuotePrivileges := make([]string, len(privileges)) - for i, p := range privileges { - doubleQuotePrivileges[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString := strings.Join(doubleQuotePrivileges, ",") - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g" { - role_name = snowflake_role.r.name - privileges = [%s] - on_schema_object { - future { - object_type_plural = "%s" - in_database = "%s" - } - } - } - `, name, privilegesString, objectType, databaseName) -} - -func TestAcc_GrantPrivilegesToRole_multipleResources(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_multipleResources(name, []string{"CREATE ACCOUNT", "CREATE ROLE"}, []string{"IMPORT SHARE", "MANAGE GRANTS"}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g1", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g1", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g1", "privileges.0", "CREATE ACCOUNT"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g1", "privileges.1", "CREATE ROLE"), - - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g2", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g2", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g2", "privileges.0", "IMPORT SHARE"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g2", "privileges.1", "MANAGE GRANTS"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g1", - ImportState: true, - ImportStateVerify: true, - }, - { - ResourceName: "snowflake_grant_privileges_to_role.g2", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func grantPrivilegesToRole_multipleResources(name string, privileges1, privileges2 []string) string { - doubleQuotePrivileges1 := make([]string, len(privileges1)) - for i, p := range privileges1 { - doubleQuotePrivileges1[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString1 := strings.Join(doubleQuotePrivileges1, ",") - - doubleQuotePrivileges2 := make([]string, len(privileges2)) - for i, p := range privileges2 { - doubleQuotePrivileges2[i] = fmt.Sprintf(`"%v"`, p) - } - privilegesString2 := strings.Join(doubleQuotePrivileges2, ",") - - return fmt.Sprintf(` - resource "snowflake_role" "r" { - name = "%v" - } - - resource "snowflake_grant_privileges_to_role" "g1" { - role_name = snowflake_role.r.name - privileges = [%s] - on_account = true - } - - resource "snowflake_grant_privileges_to_role" "g2" { - role_name = snowflake_role.r.name - privileges = [%s] - on_account = true - } - `, name, privilegesString1, privilegesString2) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_futureInDatabase_externalTable(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - objectType := "EXTERNAL TABLES" - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: grantPrivilegesToRole_onSchemaObject_futureInDatabase(name, objectType, []string{"SELECT", "REFERENCES"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.0.object_type_plural", "EXTERNAL TABLES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "on_schema_object.0.future.0.in_database", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "2"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "REFERENCES"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.1", "SELECT"), - ), - }, - // REMOVE PRIVILEGE - { - Config: grantPrivilegesToRole_onSchemaObject_futureInDatabase(name, objectType, []string{"SELECT"}, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "role_name", name), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.g", "privileges.0", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_grant_privileges_to_role.g", - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_OnAllPipes(t *testing.T) { - roleId := acc.TestClient().Ids.RandomAccountObjectIdentifier() - roleFullyQualifiedName := roleId.FullyQualifiedName() - databaseName := acc.TestClient().Ids.DatabaseId().FullyQualifiedName() - configVariables := config.Variables{ - "name": config.StringVariable(roleFullyQualifiedName), - "privileges": config.ListVariable( - config.StringVariable(string(sdk.SchemaObjectPrivilegeMonitor)), - ), - "database": config.StringVariable(databaseName), - "with_grant_option": config.BoolVariable(false), - } - resourceName := "snowflake_grant_privileges_to_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: nil, - Steps: []resource.TestStep{ - { - PreConfig: func() { - _, roleCleanup := acc.TestClient().Role.CreateRoleWithIdentifier(t, roleId) - t.Cleanup(roleCleanup) - }, - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToRole/OnAllPipes"), - ConfigVariables: configVariables, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "role_name", roleFullyQualifiedName), - resource.TestCheckResourceAttr(resourceName, "privileges.#", "1"), - resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.SchemaObjectPrivilegeMonitor)), - 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.PluralObjectTypePipes)), - 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|MONITOR|false|false|false|false|false|true|true|false|||PIPES|false||true|%s", roleFullyQualifiedName, databaseName)), - ), - }, - { - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToRole/OnAllPipes"), - ConfigVariables: configVariables, - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_onSchemaObject_futureIcebergTables(t *testing.T) { - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - Steps: []resource.TestStep{ - { - Config: fmt.Sprintf(` -resource "snowflake_role" "role" { - name = "TEST_ROLE_123" -} - -resource "snowflake_grant_privileges_to_role" "grant" { - role_name = snowflake_role.role.name - privileges = ["SELECT"] - on_schema_object { - future { - object_type_plural = "ICEBERG TABLES" - in_schema = "\"%s\".\"%s\"" - } - } -} -`, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.grant", "on_schema_object.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.grant", "on_schema_object.0.future.#", "1"), - resource.TestCheckResourceAttr("snowflake_grant_privileges_to_role.grant", "on_schema_object.0.future.0.object_type_plural", string(sdk.PluralObjectTypeIcebergTables)), - ), - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_ValidatedIdentifiers(t *testing.T) { - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: fmt.Sprintf(` -resource "snowflake_role" "role" { - name = "TEST_ROLE_123" -} - -resource "snowflake_grant_privileges_to_role" "test_invalidation" { - role_name = snowflake_role.role.name - privileges = ["SELECT"] - on_schema_object { - future { - object_type_plural = "ICEBERG TABLES" - in_schema = "%s" - } - } -}`, acc.TestSchemaName), - ExpectError: regexp.MustCompile(".*Expected DatabaseObjectIdentifier identifier type.*"), - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_ImportedPrivileges(t *testing.T) { - sharedDatabaseId := acc.TestClient().Ids.RandomAccountObjectIdentifier() - sharedDatabaseName := sharedDatabaseId.Name() - shareId := acc.TestClient().Ids.RandomAccountObjectIdentifier() - roleName := acc.TestClient().Ids.Alpha() - configVariables := config.Variables{ - "role_name": config.StringVariable(roleName), - "shared_database_name": config.StringVariable(sharedDatabaseName), - "external_share_name": config.StringVariable(sdk.NewExternalObjectIdentifier( - acc.SecondaryTestClient().Account.GetAccountIdentifier(t), - shareId, - ).FullyQualifiedName()), - "privileges": config.ListVariable( - config.StringVariable(sdk.AccountObjectPrivilegeImportedPrivileges.String()), - ), - } - resourceName := "snowflake_grant_privileges_to_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: acc.CheckAccountRolePrivilegesRevoked(t), - Steps: []resource.TestStep{ - { - PreConfig: func() { createSharedDatabaseOnSecondaryAccount(t, sharedDatabaseId, shareId) }, - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToRole/ImportedPrivileges"), - ConfigVariables: configVariables, - ConfigPlanChecks: resource.ConfigPlanChecks{ - PostApplyPostRefresh: []plancheck.PlanCheck{ - plancheck.ExpectEmptyPlan(), - }, - }, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "privileges.#", "1"), - resource.TestCheckResourceAttr(resourceName, "privileges.0", sdk.AccountObjectPrivilegeImportedPrivileges.String()), - ), - }, - { - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToRole/ImportedPrivileges"), - ConfigVariables: configVariables, - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_GrantPrivilegesToRole_MultiplePartsInRoleName(t *testing.T) { - roleId := acc.TestClient().Ids.RandomAccountObjectIdentifierContaining(".") - configVariables := config.Variables{ - "name": config.StringVariable(roleId.Name()), - "privileges": config.ListVariable( - config.StringVariable(string(sdk.GlobalPrivilegeCreateDatabase)), - config.StringVariable(string(sdk.GlobalPrivilegeCreateRole)), - ), - "with_grant_option": config.BoolVariable(true), - } - resourceName := "snowflake_grant_privileges_to_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: nil, - Steps: []resource.TestStep{ - { - PreConfig: func() { - _, roleCleanup := acc.TestClient().Role.CreateRoleWithIdentifier(t, roleId) - t.Cleanup(roleCleanup) - }, - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToRole/OnAccount"), - ConfigVariables: configVariables, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "role_name", roleId.Name()), - ), - }, - }, - }) -} diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go deleted file mode 100644 index 959f104bfb..0000000000 --- a/pkg/resources/integration_grant.go +++ /dev/null @@ -1,183 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validIntegrationPrivileges = NewPrivilegeSet( - privilegeUsage, - privilegeOwnership, - privilegeAllPrivileges, -) - -var integrationGrantSchema = map[string]*schema.Schema{ - "integration_name": { - Type: schema.TypeString, - Required: true, - Description: "Identifier for the integration; must be unique for your account.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the integration. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validIntegrationPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// IntegrationGrant returns a pointer to the resource representing a integration grant. -func IntegrationGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateIntegrationGrant, - 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_account_role instead.", - Schema: integrationGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 4 { - return nil, fmt.Errorf("invalid ID %v: expected integration_name|privilege|with_grant_option|roles", d.Id()) - } - if err := d.Set("integration_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[1]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[2])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validIntegrationPrivileges, - } -} - -// CreateIntegrationGrant implements schema.CreateFunc. -func CreateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - integrationName := d.Get("integration_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.IntegrationGrant(integrationName) - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(integrationName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadIntegrationGrant(d, meta) -} - -// ReadIntegrationGrant implements schema.ReadFunc. -func ReadIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - integrationName := d.Get("integration_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.IntegrationGrant(integrationName) - - err := readGenericGrant(d, meta, integrationGrantSchema, builder, false, false, validIntegrationPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(integrationName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteIntegrationGrant implements schema.DeleteFunc. -func DeleteIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - integrationName := d.Get("integration_name").(string) - builder := snowflake.IntegrationGrant(integrationName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateIntegrationGrant implements schema.UpdateFunc. -func UpdateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - integrationName := d.Get("integration_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - // create the builder - builder := snowflake.IntegrationGrant(integrationName) - - // first revoke - - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadIntegrationGrant(d, meta) -} diff --git a/pkg/resources/integration_grant_test.go b/pkg/resources/integration_grant_test.go deleted file mode 100644 index 227eaa0204..0000000000 --- a/pkg/resources/integration_grant_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/stretchr/testify/require" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" -) - -func TestIntegrationGrant(t *testing.T) { - r := require.New(t) - err := resources.IntegrationGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestIntegrationGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "integration_name": "test-integration", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.IntegrationGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT USAGE ON INTEGRATION "test-integration" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON INTEGRATION "test-integration" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadIntegrationGrant(mock) - err := resources.CreateIntegrationGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestIntegrationGrantRead(t *testing.T) { - r := require.New(t) - - d := integrationGrant(t, "test-integration|||IMPORTED PRIVILEGES||false", map[string]interface{}{ - "integration_name": "test-integration", - "privilege": "IMPORTED PRIVILEGES", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadIntegrationGrant(mock) - err := resources.ReadIntegrationGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadIntegrationGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "INTEGRATION", "test-integration", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "INTEGRATION", "test-integration", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON INTEGRATION "test-integration"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go deleted file mode 100644 index 00943bb050..0000000000 --- a/pkg/resources/masking_policy_grant.go +++ /dev/null @@ -1,213 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validMaskingPoilcyPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeApply, - privilegeAllPrivileges, -) - -var maskingPolicyGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the masking policy on which to grant privileges.", - ForceNew: true, - }, - "masking_policy_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the masking policy on which to grant privileges immediately.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the masking policy. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "APPLY", - ValidateFunc: validation.StringInSlice(validMaskingPoilcyPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the schema containing the masking policy on which to grant privileges.", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// MaskingPolicyGrant returns a pointer to the resource representing a masking policy grant. -func MaskingPolicyGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateMaskingPolicyGrant, - 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_account_role instead.", - Schema: maskingPolicyGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 6 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected database_name|schema_name|masking_policy_name|privilege|with_grant_option|roles", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("masking_policy_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[5])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validMaskingPoilcyPrivileges, - } -} - -// CreateMaskingPolicyGrant implements schema.CreateFunc. -func CreateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { - maskingPolicyName := d.Get("masking_policy_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.MaskingPolicyGrant(databaseName, schemaName, maskingPolicyName) - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, maskingPolicyName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadMaskingPolicyGrant(d, meta) -} - -// ReadMaskingPolicyGrant implements schema.ReadFunc. -func ReadMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - maskingPolicyName := d.Get("masking_policy_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.MaskingPolicyGrant(databaseName, schemaName, maskingPolicyName) - - err := readGenericGrant(d, meta, maskingPolicyGrantSchema, builder, false, false, validMaskingPoilcyPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, maskingPolicyName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteMaskingPolicyGrant implements schema.DeleteFunc. -func DeleteMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - maskingPolicyName := d.Get("masking_policy_name").(string) - - builder := snowflake.MaskingPolicyGrant(databaseName, schemaName, maskingPolicyName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateMaskingPolicyGrant implements schema.UpdateFunc. -func UpdateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - maskingPolicyName := d.Get("masking_policy_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - builder := snowflake.MaskingPolicyGrant(databaseName, schemaName, maskingPolicyName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadMaskingPolicyGrant(d, meta) -} diff --git a/pkg/resources/masking_policy_grant_acceptance_test.go b/pkg/resources/masking_policy_grant_acceptance_test.go deleted file mode 100644 index c53f052025..0000000000 --- a/pkg/resources/masking_policy_grant_acceptance_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_MaskingPolicyGrant(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: maskingPolicyGrantConfig(accName, "APPLY", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "masking_policy_name", accName), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "privilege", "APPLY"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: maskingPolicyGrantConfig(accName, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "masking_policy_name", accName), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_masking_policy_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_masking_policy_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func maskingPolicyGrantConfig(name string, privilege string, databaseName string, schemaName string) string { - return fmt.Sprintf(` - resource "snowflake_role" "test" { - name = "%v" - } - - resource "snowflake_masking_policy" "test" { - name = "%v" - database = "%s" - schema = "%s" - signature { - column { - name = "val" - type = "VARCHAR" - } - } - masking_expression = "case when current_role() in ('ANALYST') then val else sha2(val, 512) end" - return_data_type = "VARCHAR" - comment = "Terraform acceptance test" - } - - resource "snowflake_masking_policy_grant" "test" { - masking_policy_name = snowflake_masking_policy.test.name - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - privilege = "%s" - } - `, name, name, databaseName, schemaName, databaseName, schemaName, privilege) -} diff --git a/pkg/resources/masking_policy_grant_test.go b/pkg/resources/masking_policy_grant_test.go deleted file mode 100644 index e756a15b09..0000000000 --- a/pkg/resources/masking_policy_grant_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestMaskingPolicyGrant(t *testing.T) { - r := require.New(t) - err := resources.MaskingPolicyGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestMaskingPolicyGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "masking_policy_name": "test-masking-policy", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "APPLY", - "roles": []interface{}{"test-role-1", "test-role-2"}, - } - d := schema.TestResourceDataRaw(t, resources.MaskingPolicyGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT APPLY ON MASKING POLICY "test-db"."PUBLIC"."test-masking-policy" TO ROLE "test-role-1"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT APPLY ON MASKING POLICY "test-db"."PUBLIC"."test-masking-policy" TO ROLE "test-role-2"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadMaskingPolicyGrant(mock) - err := resources.CreateMaskingPolicyGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestMaskingPolicyGrantRead(t *testing.T) { - r := require.New(t) - - d := maskingPolicyGrant(t, "test-db|PUBLIC|test-masking-policy|APPLY||false", map[string]interface{}{ - "masking_policy_name": "test-masking-policy", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "APPLY", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadMaskingPolicyGrant(mock) - err := resources.ReadMaskingPolicyGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadMaskingPolicyGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "APPLY", "MASKING_POLICY", "test-masking-policy", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "APPLY", "MASKING_POLICY", "test-masking-policy", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON MASKING POLICY "test-db"."PUBLIC"."test-masking-policy"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go deleted file mode 100644 index 6836d4d736..0000000000 --- a/pkg/resources/materialized_view_grant.go +++ /dev/null @@ -1,316 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -/* -NewPrivilegeSet creates a set of privileges that are allowed -They are used for validation in the schema object below. -*/ - -var validMaterializedViewPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeReferences, - privilegeSelect, - privilegeAllPrivileges, -) - -// The schema holds the resource variables that can be provided in the Terraform. -var materializedViewGrantSchema = map[string]*schema.Schema{ - "materialized_view_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the materialized view on which to grant privileges immediately (only valid if on_future and on_all are false).", - ForceNew: true, - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future materialized views on which to grant privileges.", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future materialized views on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future materialized view. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "SELECT", - ValidateFunc: validation.StringInSlice(validMaterializedViewPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future and on_all are false).", - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all future materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// MaterializedViewGrant returns a pointer to the resource representing a view grant. -func MaterializedViewGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateMaterializedViewGrant, - 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_account_role instead.", - Schema: materializedViewGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 9 { - return nil, errors.New("invalid ID specified for materialized view grant. Expecting {database}|{schema}|{materialized view}|{privilege}|{with_grant_option}|{on_future}|{on_all}|{roles}|{shares}") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("materialized_view_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[8])); err != nil { - return nil, err - } - - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validMaterializedViewPrivileges, - } -} - -// CreateMaterializedViewGrant implements schema.CreateFunc. -func CreateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { - materializedViewName := d.Get("materialized_view_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - if (materializedViewName == "") && !onFuture && !onAll { - return errors.New("materialized_view_name must be set unless on_future or on_all is true") - } - if (materializedViewName != "") && onFuture && onAll { - return errors.New("materialized_view_name must be empty if on_future and on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureMaterializedViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllMaterializedViewGrant(databaseName, schemaName) - default: - builder = snowflake.MaterializedViewGrant(databaseName, schemaName, materializedViewName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, materializedViewName, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - - return ReadMaterializedViewGrant(d, meta) -} - -// ReadMaterializedViewGrant implements schema.ReadFunc. -func ReadMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - materializedViewName := d.Get("materialized_view_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - if materializedViewName == "" && !onFuture && !onAll { - return errors.New("materialized_view_name must be set unless on_future or on_all is true") - } - if materializedViewName != "" && (onFuture || onAll) { - return errors.New("materialized_view_name must be empty if on_future or on_all is true") - } - if onAll && onFuture { - return errors.New("on_future and on_all cannot both be true") - } - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureMaterializedViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllMaterializedViewGrant(databaseName, schemaName) - default: - builder = snowflake.MaterializedViewGrant(databaseName, schemaName, materializedViewName) - } - - err := readGenericGrant(d, meta, materializedViewGrantSchema, builder, onFuture, onAll, validMaterializedViewPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, materializedViewName, privilege, withGrantOption, onFuture, onAll, roles, shares) - // if the ID is not in the new format, rewrite it - if d.Id() != grantID { - d.SetId(grantID) - } - return nil -} - -// DeleteMaterializedViewGrant implements schema.DeleteFunc. -func DeleteMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - materializedViewName := d.Get("materialized_view_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureMaterializedViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllMaterializedViewGrant(databaseName, schemaName) - default: - builder = snowflake.MaterializedViewGrant(databaseName, schemaName, materializedViewName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateMaterializedViewGrant implements schema.UpdateFunc. -func UpdateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update, and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - materializedViewName := d.Get("materialized_view_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureMaterializedViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllMaterializedViewGrant(databaseName, schemaName) - default: - builder = snowflake.MaterializedViewGrant(databaseName, schemaName, materializedViewName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, sharesToRevoke, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadMaterializedViewGrant(d, meta) -} diff --git a/pkg/resources/materialized_view_grant_acceptance_test.go b/pkg/resources/materialized_view_grant_acceptance_test.go deleted file mode 100644 index 867d6cd0c3..0000000000 --- a/pkg/resources/materialized_view_grant_acceptance_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_MaterializedViewFutureGrant(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: materializedViewGrantConfigFuture(name, onFuture, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_materialized_view_grant.test", "materialized_view_name"), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "privilege", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_materialized_view_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_MaterializedViewAllGrant(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: materializedViewGrantConfigFuture(name, onAll, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_materialized_view_grant.test", "materialized_view_name"), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_materialized_view_grant.test", "privilege", "SELECT"), - ), - }, - { - ResourceName: "snowflake_materialized_view_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func materializedViewGrantConfigFuture(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var materializedViewNameConfig string - switch grantType { - case onFuture: - materializedViewNameConfig = "on_future = true" - case onAll: - materializedViewNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource "snowflake_role" "test" { - name = "%s" -} - -resource "snowflake_materialized_view_grant" "test" { - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - %s - privilege = "%s" -} -`, name, databaseName, schemaName, materializedViewNameConfig, privilege) -} diff --git a/pkg/resources/materialized_view_grant_test.go b/pkg/resources/materialized_view_grant_test.go deleted file mode 100644 index 59a0f37a40..0000000000 --- a/pkg/resources/materialized_view_grant_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestMaterializedViewGrant(t *testing.T) { - r := require.New(t) - err := resources.MaterializedViewGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestMaterializedViewGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "materialized_view_name": "test-materialized-view", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.MaterializedViewGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-materialized-view" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-materialized-view" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-materialized-view" TO SHARE "test-share-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-materialized-view" TO SHARE "test-share-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadMaterializedViewGrant(mock) - err := resources.CreateMaterializedViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestMaterializedViewGrantRead(t *testing.T) { - r := require.New(t) - - d := materializedViewGrant(t, "test-db|PUBLIC|test-materialized-view|SELECT||false", map[string]interface{}{ - "materialized_view_name": "test-materialized-view", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{}, - "shares": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadMaterializedViewGrant(mock) - err := resources.ReadMaterializedViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) - - shares := d.Get("shares").(*schema.Set) - r.True(shares.Contains("test-share-1")) - r.True(shares.Contains("test-share-2")) - r.Equal(2, shares.Len()) -} - -func expectReadMaterializedViewGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-materialized-view", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-materialized-view", "ROLE", "test-role-2", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-materialized-view", "SHARE", "test-share-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-materialized-view", "SHARE", "test-share-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON MATERIALIZED VIEW "test-db"."PUBLIC"."test-materialized-view"$`).WillReturnRows(rows) -} - -func TestFutureMaterializedViewGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.MaterializedViewGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureMaterializedViewGrant(mock) - err := resources.CreateMaterializedViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.MaterializedViewGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureMaterializedViewDatabaseGrant(mock) - err := resources.CreateMaterializedViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) - - // Validate specifying on_future=false and schema_name="" generates an error - m := require.New(t) - - in = map[string]interface{}{ - "on_future": false, - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.MaterializedViewGrant().Resource.Schema, in) - m.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - err := resources.CreateMaterializedViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - m.Error(err) - }) -} - -func expectReadFutureMaterializedViewGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureMaterializedViewDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "MATERIALIZED_VIEW", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go deleted file mode 100644 index f7a79ac84d..0000000000 --- a/pkg/resources/pipe_grant.go +++ /dev/null @@ -1,266 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validPipePrivileges = NewPrivilegeSet( - privilegeMonitor, - privilegeOperate, - privilegeOwnership, - privilegeAllPrivileges, -) - -var pipeGrantSchema = map[string]*schema.Schema{ - "pipe_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the pipe on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future pipes on which to grant privileges.", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future pipes on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future pipe. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "OPERATE", - ValidateFunc: validation.StringInSlice(validPipePrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future pipes in the given schema. When this is true and no schema_name is provided apply this grant on all future pipes in the given database. The pipe_name field must be unset in order to use on_future.", - Default: false, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// PipeGrant returns a pointer to the resource representing a pipe grant. -func PipeGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreatePipeGrant, - 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_account_role instead.", - Schema: pipeGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 7 { - return nil, fmt.Errorf("pipe grant ID must be in the form database_name|schema_name|pipe_name|privilege|with_grant_option|on_future|roles") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("pipe_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[6])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validPipePrivileges, - } -} - -// CreatePipeGrant implements schema.CreateFunc. -func CreatePipeGrant(d *schema.ResourceData, meta interface{}) error { - pipeName := d.Get("pipe_name").(string) - var schemaName string - if name, ok := d.GetOk("schema_name"); ok { - schemaName = name.(string) - } - - databaseName := d.Get("database_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if (schemaName == "") && !onFuture { - return errors.New("schema_name must be set unless on_future is true") - } - if (pipeName == "") && !onFuture { - return errors.New("pipe_name must be set unless on_future is true") - } - - var builder snowflake.GrantBuilder - if onFuture { - builder = snowflake.FuturePipeGrant(databaseName, schemaName) - } else { - builder = snowflake.PipeGrant(databaseName, schemaName, pipeName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, pipeName, privilege, withGrantOption, onFuture, roles) - d.SetId(grantID) - - return ReadPipeGrant(d, meta) -} - -// ReadPipeGrant implements schema.ReadFunc. -func ReadPipeGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - pipeName := d.Get("pipe_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - onFuture := d.Get("on_future").(bool) - if pipeName == "" && !onFuture { - return errors.New("pipe_name must be set unless on_future is true") - } - if pipeName != "" && onFuture { - return errors.New("pipe_name must not be set when on_future is true") - } - - var builder snowflake.GrantBuilder - if onFuture { - builder = snowflake.FuturePipeGrant(databaseName, schemaName) - } else { - builder = snowflake.PipeGrant(databaseName, schemaName, pipeName) - } - // TODO - onAll := false - - err := readGenericGrant(d, meta, pipeGrantSchema, builder, onFuture, onAll, validPipePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, pipeName, privilege, withGrantOption, onFuture, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeletePipeGrant implements schema.DeleteFunc. -func DeletePipeGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - pipeName := d.Get("pipe_name").(string) - onFuture := d.Get("on_future").(bool) - - var builder snowflake.GrantBuilder - if onFuture { - builder = snowflake.FuturePipeGrant(databaseName, schemaName) - } else { - builder = snowflake.PipeGrant(databaseName, schemaName, pipeName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdatePipeGrant implements schema.UpdateFunc. -func UpdatePipeGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - pipeName := d.Get("pipe_name").(string) - onFuture := d.Get("on_future").(bool) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - var builder snowflake.GrantBuilder - if onFuture { - builder = snowflake.FuturePipeGrant(databaseName, schemaName) - } else { - builder = snowflake.PipeGrant(databaseName, schemaName, pipeName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadPipeGrant(d, meta) -} diff --git a/pkg/resources/pipe_grant_acceptance_test.go b/pkg/resources/pipe_grant_acceptance_test.go deleted file mode 100644 index 440c84f309..0000000000 --- a/pkg/resources/pipe_grant_acceptance_test.go +++ /dev/null @@ -1,188 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_PipeGrant(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: pipeGrantConfig(accName, "OPERATE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "pipe_name", accName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "privilege", "OPERATE"), - ), - }, - { - Config: pipeGrantConfig(accName, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "pipe_name", accName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - { - ResourceName: "snowflake_pipe_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_PipeGrantWithDefaultPrivilege(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: pipeGrantConfigWithDefaultPrivilege(accName, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "pipe_name", accName), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_pipe_grant.test", "privilege", "OPERATE"), - ), - }, - { - ResourceName: "snowflake_pipe_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func pipeGrantConfig(name string, privilege string, databaseName string, schemaName string) string { - s := ` -resource "snowflake_table" "test" { - name = "%s" - database = "%s" - schema = "%s" - column { - name = "id" - type = "NUMBER(5,0)" - } - column { - name = "data" - type = "VARCHAR(16)" - } -} - -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_stage" "test" { - name = "%s" - database = "%s" - schema = "%s" - comment = "Terraform acceptance test" -} - -resource "snowflake_pipe_grant" "test" { - pipe_name = snowflake_pipe.test.name - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - privilege = "%s" -} - -resource "snowflake_pipe" "test" { - name = "%s" - database = "%s" - schema = "%s" - comment = "Terraform acceptance test" - copy_statement = <", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "PIPE", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFuturePipeDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "PIPE", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "PIPE", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go deleted file mode 100644 index d646fe7a95..0000000000 --- a/pkg/resources/procedure_grant.go +++ /dev/null @@ -1,323 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validProcedurePrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, -) - -var procedureGrantSchema = map[string]*schema.Schema{ - "argument_data_types": { - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "List of the argument data types for the procedure (must be present if procedure has arguments and procedure_name is present)", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future procedures on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future procedures in the given schema. When this is true and no schema_name is provided apply this grant on all future procedures in the given database. The procedure_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"procedure_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all procedures in the given schema. When this is true and no schema_name is provided apply this grant on all procedures in the given database. The procedure_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"procedure_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future procedure. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validProcedurePrivileges.ToList(), true), - ForceNew: true, - }, - "procedure_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the procedure on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future procedures on which to grant privileges.", - ForceNew: true, - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future is false).", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// ProcedureGrant returns a pointer to the resource representing a procedure grant. -func ProcedureGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateProcedureGrant, - 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_account_role instead.", - Schema: procedureGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 10 { - return nil, errors.New("incorrect ID format (expecting database_name|schema_name|procedure_name|argument_data_types|privilege|with_grant_option|on_future|roles|shares)") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("procedure_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("argument_data_types", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[4]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[7])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[8])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[9])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validProcedurePrivileges, - } -} - -// CreateProcedureGrant implements schema.CreateFunc. -func CreateProcedureGrant(d *schema.ResourceData, meta interface{}) error { - procedureName := d.Get("procedure_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - - argumentDataTypes := make([]string, 0) - - if v, ok := d.GetOk("arguments"); ok { - arguments := v.([]interface{}) - for _, argument := range arguments { - argumentDataTypes = append(argumentDataTypes, argument.(map[string]interface{})["data_type"].(string)) - } - } - - if v, ok := d.GetOk("argument_data_types"); ok { - argumentDataTypes = expandStringList(v.([]interface{})) - } - - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - if (procedureName == "") && !onFuture && !onAll { - return errors.New("procedure_name must be set unless on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureProcedureGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllProcedureGrant(databaseName, schemaName) - default: - builder = snowflake.ProcedureGrant(databaseName, schemaName, procedureName, argumentDataTypes) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, procedureName, argumentDataTypes, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - return ReadProcedureGrant(d, meta) -} - -// ReadProcedureGrant implements schema.ReadFunc. -func ReadProcedureGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - procedureName := d.Get("procedure_name").(string) - argumentDataTypes := expandStringList(d.Get("argument_data_types").([]interface{})) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureProcedureGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllProcedureGrant(databaseName, schemaName) - default: - builder = snowflake.ProcedureGrant(databaseName, schemaName, procedureName, argumentDataTypes) - } - - err := readGenericGrant(d, meta, procedureGrantSchema, builder, onFuture, onAll, validProcedurePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, procedureName, argumentDataTypes, privilege, withGrantOption, onFuture, onAll, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteProcedureGrant implements schema.DeleteFunc. -func DeleteProcedureGrant(d *schema.ResourceData, meta interface{}) error { - procedureName := d.Get("procedure_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - argumentDataTypes := expandStringList(d.Get("argument_data_types").([]interface{})) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureProcedureGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllProcedureGrant(databaseName, schemaName) - default: - builder = snowflake.ProcedureGrant(databaseName, schemaName, procedureName, argumentDataTypes) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateProcedureGrant implements schema.UpdateFunc. -func UpdateProcedureGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - procedureName := d.Get("procedure_name").(string) - argumentDataTypes := expandStringList(d.Get("argument_data_types").([]interface{})) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureProcedureGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllProcedureGrant(databaseName, schemaName) - default: - builder = snowflake.ProcedureGrant(databaseName, schemaName, procedureName, argumentDataTypes) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, sharesToRevoke, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadProcedureGrant(d, meta) -} diff --git a/pkg/resources/procedure_grant_acceptance_test.go b/pkg/resources/procedure_grant_acceptance_test.go deleted file mode 100644 index 68a65d8c4c..0000000000 --- a/pkg/resources/procedure_grant_acceptance_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_ProcedureGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: procedureGrantConfig(name, onAll, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_procedure_grant.test", "procedure_name"), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "privilege", "USAGE"), - ), - }, - { - ResourceName: "snowflake_procedure_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_ProcedureGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: procedureGrantConfig(name, onFuture, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_procedure_grant.test", "procedure_name"), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_procedure_grant.test", "privilege", "USAGE"), - ), - }, - { - ResourceName: "snowflake_procedure_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func procedureGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var procedureNameConfig string - switch grantType { - case onFuture: - procedureNameConfig = "on_future = true" - case onAll: - procedureNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource snowflake_role test { - name = "%s" -} - -resource snowflake_procedure_grant test { - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - %s - privilege = "%s" -} -`, name, databaseName, schemaName, procedureNameConfig, privilege) -} diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go deleted file mode 100644 index eb9a312506..0000000000 --- a/pkg/resources/resource_monitor_grant.go +++ /dev/null @@ -1,176 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validResourceMonitorPrivileges = NewPrivilegeSet( - privilegeModify, - privilegeMonitor, - privilegeAllPrivileges, -) - -var resourceMonitorGrantSchema = map[string]*schema.Schema{ - "monitor_name": { - Type: schema.TypeString, - Required: true, - Description: "Identifier for the resource monitor; must be unique for your account.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the resource monitor. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "MONITOR", - ValidateFunc: validation.StringInSlice(validResourceMonitorPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, -} - -// ResourceMonitorGrant returns a pointer to the resource representing a resource monitor grant. -func ResourceMonitorGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateResourceMonitorGrant, - 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_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) - if len(parts) != 4 { - return nil, fmt.Errorf("incorrect ID %v: expected monitor_name|privilege|with_grant_option|roles", d.Id()) - } - if err := d.Set("monitor_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[1]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[2])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - Schema: resourceMonitorGrantSchema, - }, - ValidPrivs: validResourceMonitorPrivileges, - } -} - -// CreateResourceMonitorGrant implements schema.CreateFunc. -func CreateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - monitorName := d.Get("monitor_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - builder := snowflake.ResourceMonitorGrant(monitorName) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(monitorName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadResourceMonitorGrant(d, meta) -} - -// ReadResourceMonitorGrant implements schema.ReadFunc. -func ReadResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - monitorName := d.Get("monitor_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.ResourceMonitorGrant(monitorName) - err := readGenericGrant(d, meta, resourceMonitorGrantSchema, builder, false, false, validResourceMonitorPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(monitorName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteResourceMonitorGrant implements schema.DeleteFunc. -func DeleteResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - monitorName := d.Get("monitor_name").(string) - - builder := snowflake.ResourceMonitorGrant(monitorName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateResourceMonitorGrant implements schema.UpdateFunc. -func UpdateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - monitorName := d.Get("monitor_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - // create the builder - builder := snowflake.ResourceMonitorGrant(monitorName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, "", rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadResourceMonitorGrant(d, meta) -} diff --git a/pkg/resources/resource_monitor_grant_acceptance_test.go b/pkg/resources/resource_monitor_grant_acceptance_test.go deleted file mode 100644 index a8995304a5..0000000000 --- a/pkg/resources/resource_monitor_grant_acceptance_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_ResourceMonitor_defaults(t *testing.T) { - wName := acc.TestClient().Ids.Alpha() - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: resourceMonitorGrantConfig(wName, roleName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_resource_monitor_grant.test", "monitor_name", wName), - resource.TestCheckResourceAttr("snowflake_resource_monitor_grant.test", "privilege", "MONITOR"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_resource_monitor_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func resourceMonitorGrantConfig(n, role string) string { - return fmt.Sprintf(` - -resource "snowflake_resource_monitor" "test" { - name = "%v" -} - -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_resource_monitor_grant" "test" { - monitor_name = snowflake_resource_monitor.test.name - roles = [snowflake_role.test.name] -} -`, n, role) -} diff --git a/pkg/resources/resource_monitor_grant_test.go b/pkg/resources/resource_monitor_grant_test.go deleted file mode 100644 index d9547fd56a..0000000000 --- a/pkg/resources/resource_monitor_grant_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/stretchr/testify/require" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" -) - -func TestResourceMonitorGrant(t *testing.T) { - r := require.New(t) - err := resources.ResourceMonitorGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestResourceMonitorGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "monitor_name": "test-monitor", - "privilege": "MONITOR", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.ResourceMonitorGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT MONITOR ON RESOURCE MONITOR "test-monitor" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT MONITOR ON RESOURCE MONITOR "test-monitor" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadResourceMonitorGrant(mock) - err := resources.CreateResourceMonitorGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestResourceMonitorGrantRead(t *testing.T) { - r := require.New(t) - - d := resourceMonitorGrant(t, "test-monitor❄️MONITOR❄️❄️false", map[string]interface{}{ - "monitor_name": "test-monitor", - "privilege": "MONITOR", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadResourceMonitorGrant(mock) - err := resources.ReadResourceMonitorGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadResourceMonitorGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "MONITOR", "RESOURCE MONITOR", "test-monitor", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "MONITOR", "RESOURCE MONITOR", "test-monitor", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON RESOURCE MONITOR "test-monitor"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/role_grants.go b/pkg/resources/role_grants.go deleted file mode 100644 index e8b151510c..0000000000 --- a/pkg/resources/role_grants.go +++ /dev/null @@ -1,329 +0,0 @@ -package resources - -import ( - "context" - "database/sql" - "errors" - "fmt" - "log" - "slices" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/jmoiron/sqlx" - "github.com/snowflakedb/gosnowflake" -) - -func RoleGrants() *schema.Resource { - return &schema.Resource{ - Create: CreateRoleGrants, - Read: ReadRoleGrants, - Delete: DeleteRoleGrants, - Update: UpdateRoleGrants, - DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_account_role instead.", - - Schema: map[string]*schema.Schema{ - "role_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the role we are granting.", - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants role to this specified role.", - }, - "users": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants role to this specified user.", - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, - }, - - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 3 { - return nil, fmt.Errorf("invalid ID specified for role grants, expected {role_name}|{roles}|{users}, got %v", d.Id()) - } - if err := d.Set("role_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[1])); err != nil { - return nil, err - } - if err := d.Set("users", helpers.StringListToList(parts[2])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - } -} - -func CreateRoleGrants(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - roleName := d.Get("role_name").(string) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - users := expandStringList(d.Get("users").(*schema.Set).List()) - - if len(roles) == 0 && len(users) == 0 { - return fmt.Errorf("no users or roles specified for role grants") - } - - grantID := helpers.EncodeSnowflakeID(roleName, roles, users) - d.SetId(grantID) - - for _, role := range roles { - if err := grantRoleToRole(db, roleName, role); err != nil { - return err - } - } - - for _, user := range users { - if err := grantRoleToUser(db, roleName, user); err != nil { - return err - } - } - - return ReadRoleGrants(d, meta) -} - -func grantRoleToRole(db *sql.DB, role1, role2 string) error { - g := snowflake.RoleGrant(role1) - err := snowflake.Exec(db, g.Role(role2).Grant()) - return err -} - -func grantRoleToUser(db *sql.DB, role1, user string) error { - g := snowflake.RoleGrant(role1) - err := snowflake.Exec(db, g.User(user).Grant()) - return err -} - -type roleGrant struct { - CreatedOn sql.RawBytes `db:"created_on"` - Role sql.NullString `db:"role"` - GrantedTo sql.NullString `db:"granted_to"` - GranteeName sql.NullString `db:"grantee_name"` - Grantedby sql.NullString `db:"granted_by"` -} - -func ReadRoleGrants(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - roleName := d.Get("role_name").(string) - - roles := make([]string, 0) - users := make([]string, 0) - - builder := snowflake.NewRoleBuilder(db, roleName) - _, err := builder.Show() - if errors.Is(err, sql.ErrNoRows) { - // If not found, mark resource to be removed from state file during apply or refresh - log.Printf("[DEBUG] role (%s) not found", roleName) - d.SetId("") - return nil - } - - grants, err := readGrants(db, roleName) - if err != nil { - return err - } - - for _, grant := range grants { - switch grant.GrantedTo.String { - case "ROLE": - for _, tfRole := range d.Get("roles").(*schema.Set).List() { - if tfRole == grant.GranteeName.String { - roles = append(roles, grant.GranteeName.String) - } - } - case "USER": - for _, tfUser := range d.Get("users").(*schema.Set).List() { - if tfUser == grant.GranteeName.String { - users = append(users, grant.GranteeName.String) - } - } - default: - log.Printf("[WARN] Ignoring unknown grant type %s", grant.GrantedTo.String) - } - } - - if err := d.Set("roles", roles); err != nil { - return err - } - if err := d.Set("users", users); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(roleName, roles, users) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -func readGrants(db *sql.DB, roleName string) ([]*roleGrant, error) { - sdb := sqlx.NewDb(db, "snowflake") - - stmt := fmt.Sprintf(`SHOW GRANTS OF ROLE "%s"`, roleName) - rows, err := sdb.Queryx(stmt) - if err != nil { - return nil, err - } - defer rows.Close() - - grants := make([]*roleGrant, 0) - for rows.Next() { - g := &roleGrant{} - if err := rows.StructScan(g); err != nil { - return nil, err - } - grants = append(grants, g) - } - - for _, g := range grants { - if g.GranteeName.Valid { - s := g.GranteeName.String - s = strings.TrimPrefix(s, `"`) - s = strings.TrimSuffix(s, `"`) - g.GranteeName = sql.NullString{String: s} - } - } - - return grants, nil -} - -func DeleteRoleGrants(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - roleName := d.Get("role_name").(string) - - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - users := expandStringList(d.Get("users").(*schema.Set).List()) - - for _, role := range roles { - if err := revokeRoleFromRole(db, roleName, role); err != nil { - return err - } - } - - for _, user := range users { - if err := revokeRoleFromUser(db, roleName, user); err != nil { - return err - } - } - - d.SetId("") - return nil -} - -func revokeRoleFromRole(db *sql.DB, role1, role2 string) error { - rg := snowflake.RoleGrant(role1).Role(role2) - err := snowflake.Exec(db, rg.Revoke()) - log.Printf("revokeRoleFromRole %v", err) - if driverErr, ok := err.(*gosnowflake.SnowflakeError); ok { //nolint:errorlint // todo: should be fixed - if driverErr.Number == 2003 { - // handling error if a role has been deleted prior to revoking a role - // 002003 (02000): SQL compilation error: - // User 'XXX' does not exist or not authorized. - roles, _ := snowflake.ListRoles(db, role2) - roleNames := make([]string, len(roles)) - for i, r := range roles { - roleNames[i] = r.Name.String - } - if !slices.Contains(roleNames, role2) { - log.Printf("[WARN] Role %s does not exist. No need to revoke role %s", role2, role1) - return nil - } - } - } - return err -} - -func revokeRoleFromUser(db *sql.DB, role1, user string) error { - ctx := context.Background() - client := sdk.NewClientFromDB(db) - - rg := snowflake.RoleGrant(role1).User(user) - err := snowflake.Exec(db, rg.Revoke()) - if driverErr, ok := err.(*gosnowflake.SnowflakeError); ok { //nolint:errorlint // todo: should be fixed - // handling error if a user has been deleted prior to revoking a role - // 002003 (02000): SQL compilation error: - // User 'XXX' does not exist or not authorized. - if driverErr.Number == 2003 { - users, _ := client.Users.Show(ctx, &sdk.ShowUserOptions{ - Like: &sdk.Like{Pattern: sdk.String(user)}, - }) - logins := make([]string, len(users)) - for i, u := range users { - logins[i] = u.LoginName - } - if !snowflake.Contains(logins, user) { - log.Printf("[WARN] User %s does not exist. No need to revoke role %s", user, role1) - return nil - } - } - } - return err -} - -func UpdateRoleGrants(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - roleName := d.Get("role_name").(string) - - x := func(resource string, grant func(db *sql.DB, role string, target string) error, revoke func(db *sql.DB, role string, target string) error) error { - o, n := d.GetChange(resource) - - if o == nil { - o = new(schema.Set) - } - if n == nil { - n = new(schema.Set) - } - os := o.(*schema.Set) - ns := n.(*schema.Set) - - remove := expandStringList(os.Difference(ns).List()) - add := expandStringList(ns.Difference(os).List()) - - for _, user := range remove { - if err := revoke(db, roleName, user); err != nil { - return err - } - } - for _, user := range add { - if err := grant(db, roleName, user); err != nil { - return err - } - } - return nil - } - - if err := x("users", grantRoleToUser, revokeRoleFromUser); err != nil { - return err - } - - if err := x("roles", grantRoleToRole, revokeRoleFromRole); err != nil { - return err - } - - return ReadRoleGrants(d, meta) -} diff --git a/pkg/resources/role_grants_acceptance_test.go b/pkg/resources/role_grants_acceptance_test.go deleted file mode 100644 index e01aa958af..0000000000 --- a/pkg/resources/role_grants_acceptance_test.go +++ /dev/null @@ -1,246 +0,0 @@ -package resources_test - -import ( - "fmt" - "log" - "regexp" - "sort" - "strconv" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func mustParseInt(t *testing.T, input string) int64 { - t.Helper() - i, err := strconv.ParseInt(input, 10, 64) - if err != nil { - t.Error(err) - } - return i -} - -func extractList(in map[string]string, name string) ([]string, error) { - out := make([]string, 0) - r, err := regexp.Compile(fmt.Sprintf(`^%s.\d+$`, name)) - if err != nil { - return out, err - } - for k, v := range in { - if r.MatchString(k) { - log.Printf("[DEBUG] matched %s %s", k, v) - out = append(out, v) - } else { - log.Printf("[DEBUG] no match %s", k) - } - } - return out, nil -} - -func listSetEqual(a, b []string) bool { - if len(a) != len(b) { - return false - } - - sort.Strings(a) - sort.Strings(b) - - for i := range a { - if a[i] != b[i] { - return false - } - } - return true -} - -func testCheckRolesAndUsers(t *testing.T, path string, roles, users []string) func(state *terraform.State) error { - t.Helper() - return func(state *terraform.State) error { - is := state.RootModule().Resources[path].Primary - if c, ok := is.Attributes["roles.#"]; !ok || mustParseInt(t, c) != int64(len(roles)) { - return fmt.Errorf("expected roles.# to equal %d but got %s", len(roles), c) - } - r, err := extractList(is.Attributes, "roles") - if err != nil { - return err - } - - // TODO no longer case sensitive - if !listSetEqual(roles, r) { - return fmt.Errorf("expected roles %#v but got %#v", roles, r) - } - - if c, ok := is.Attributes["users.#"]; !ok || mustParseInt(t, c) != int64(len(users)) { - return fmt.Errorf("expected users.# to equal %d but got %s", len(users), c) - } - u, err := extractList(is.Attributes, "users") - if err != nil { - return err - } - - if !listSetEqual(users, u) { - return fmt.Errorf("expected users %#v but got %#v", users, u) - } - - return nil - } -} - -func TestAcc_RoleGrant(t *testing.T) { - role1 := acc.TestClient().Ids.Alpha() - role2 := acc.TestClient().Ids.Alpha() - role3 := acc.TestClient().Ids.Alpha() - user1 := acc.TestClient().Ids.Alpha() - user2 := acc.TestClient().Ids.Alpha() - - basicChecks := resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_role.r", "name", role1), - resource.TestCheckResourceAttr("snowflake_role.r2", "name", role2), - resource.TestCheckResourceAttr("snowflake_role_grants.w", "role_name", role1), - ) - - baselineStep := resource.TestStep{ - Config: rgConfig(role1, role2, role3, user1, user2), - ResourceName: "snowflake_role_grants.w", - Check: resource.ComposeTestCheckFunc( - basicChecks, - testCheckRolesAndUsers(t, "snowflake_role_grants.w", []string{role2, role3}, []string{user1, user2}), - ), - } - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - // test setup + removing a role - baselineStep, - { - Config: rgConfig2(role1, role2, role3, user1, user2), - ResourceName: "snowflake_role_grants.w", - Check: resource.ComposeTestCheckFunc( - basicChecks, - testCheckRolesAndUsers(t, "snowflake_role_grants.w", []string{role2}, []string{user1, user2})), - }, - // back to baseline, which means adding a role - baselineStep, - // then remove a user - { - Config: rgConfig3(role1, role2, role3, user1, user2), - ResourceName: "snowflake_role_grants.w", - - Check: resource.ComposeTestCheckFunc( - basicChecks, - testCheckRolesAndUsers(t, "snowflake_role_grants.w", []string{role2, role3}, []string{user1})), - }, - // add the user back to get back to baseline - baselineStep, - // now try reordering and ensure there is no diff - { - Config: rgConfig4(role1, role2, role3, user1, user2), - ResourceName: "snowflake_role_grants.w", - PlanOnly: true, - ExpectNonEmptyPlan: false, - - Check: resource.ComposeTestCheckFunc( - basicChecks, - func(state *terraform.State) error { - return nil - }, - ), - }, - baselineStep, - // IMPORT - { - ResourceName: "snowflake_role_grants.w", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"enable_multiple_grants"}, - }, - }, - }) -} - -func rolesAndUser(role1, role2, role3, user1, user2 string) string { - s := ` -resource "snowflake_role" "r" { - name = "%s" -} -resource "snowflake_role" "r2" { - name = "%s" -} -resource "snowflake_role" "r3" { - name = "%s" -} -resource "snowflake_user" "u" { - name = "%s" -} -resource "snowflake_user" "u2" { - name = "%s" -} -` - return fmt.Sprintf(s, role1, role2, role3, user1, user2) -} - -func rgConfig(role1, role2, role3, user1, user2 string) string { - s := ` - %s - - resource "snowflake_role_grants" "w" { - role_name = "${snowflake_role.r.name}" - roles = ["${snowflake_role.r2.name}", "${snowflake_role.r3.name}"] - users = ["${snowflake_user.u.name}", "${snowflake_user.u2.name}"] - } - ` - return fmt.Sprintf(s, rolesAndUser(role1, role2, role3, user1, user2)) -} - -func rgConfig2(role1, role2, role3, user1, user2 string) string { - s := ` - - %s - - resource "snowflake_role_grants" "w" { - role_name = "${snowflake_role.r.name}" - roles = ["${snowflake_role.r2.name}"] - users = ["${snowflake_user.u.name}", "${snowflake_user.u2.name}"] - } - ` - - return fmt.Sprintf(s, rolesAndUser(role1, role2, role3, user1, user2)) -} - -func rgConfig3(role1, role2, role3, user1, user2 string) string { - s := ` - - %s - - resource "snowflake_role_grants" "w" { - role_name = "${snowflake_role.r.name}" - roles = ["${snowflake_role.r2.name}", "${snowflake_role.r3.name}"] - users = ["${snowflake_user.u.name}"] - } - ` - - return fmt.Sprintf(s, rolesAndUser(role1, role2, role3, user1, user2)) -} - -func rgConfig4(role1, role2, role3, user1, user2 string) string { - s := ` - -%s - resource "snowflake_role_grants" "w" { - role_name = "${snowflake_role.r.name}" - roles = ["${snowflake_role.r3.name}", "${snowflake_role.r2.name}"] - users = ["${snowflake_user.u2.name}", "${snowflake_user.u.name}"] -} -` - return fmt.Sprintf(s, rolesAndUser(role1, role2, role3, user1, user2)) -} diff --git a/pkg/resources/role_grants_internal_test.go b/pkg/resources/role_grants_internal_test.go deleted file mode 100644 index 9aa3d2ab7c..0000000000 --- a/pkg/resources/role_grants_internal_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package resources - -import ( - "database/sql" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/stretchr/testify/require" -) - -func Test_grantToRole(t *testing.T) { - r := require.New(t) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT ROLE "foo" TO ROLE "bar"`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := grantRoleToRole(db, "foo", "bar") - r.NoError(err) - }) -} - -func Test_grantToUser(t *testing.T) { - r := require.New(t) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT ROLE "foo" TO USER "bar"`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := grantRoleToUser(db, "foo", "bar") - r.NoError(err) - }) -} - -func Test_readGrants(t *testing.T) { - r := require.New(t) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{"created_on", "role", "granted_to", "grantee_name", "granted_by"}).AddRow("_", "foo", "ROLE", "bam", "") - mock.ExpectQuery(`SHOW GRANTS OF ROLE "foo"`).WillReturnRows(rows) - read, err := readGrants(db, "foo") - r.NoError(err) - r.Len(read, 1) - g := read[0] - r.Equal("ROLE", g.GrantedTo.String) - r.Equal("bam", g.GranteeName.String) - }) -} - -func Test_revokeRoleFromRole(t *testing.T) { - r := require.New(t) - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`REVOKE ROLE "foo" FROM ROLE "bar"`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := revokeRoleFromRole(db, "foo", "bar") - r.NoError(err) - }) -} - -func Test_revokeRoleFromUser(t *testing.T) { - r := require.New(t) - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`REVOKE ROLE "foo" FROM USER "bar"`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := revokeRoleFromUser(db, "foo", "bar") - r.NoError(err) - }) -} diff --git a/pkg/resources/role_grants_test.go b/pkg/resources/role_grants_test.go deleted file mode 100644 index 831c32b587..0000000000 --- a/pkg/resources/role_grants_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestRoleGrants(t *testing.T) { - r := require.New(t) - err := resources.RoleGrants().InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestRoleGrantsCreate(t *testing.T) { - r := require.New(t) - - d := roleGrants(t, "good_name", map[string]interface{}{ - "role_name": "good_name", - "roles": []interface{}{"role1", "role2"}, - "users": []interface{}{"user1", "user2"}, - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT ROLE "good_name" TO ROLE "role2"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`GRANT ROLE "good_name" TO ROLE "role1"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`GRANT ROLE "good_name" TO USER "user1"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`GRANT ROLE "good_name" TO USER "user2"`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadRoleGrants(mock) - err := resources.CreateRoleGrants(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadRoleGrants(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", - "role", - "granted_to", - "grantee_name", - "granted_by", - }). - AddRow("_", "good_name", "ROLE", "role1", ""). - AddRow("_", "good_name", "ROLE", "role2", ""). - AddRow("_", "good_name", "USER", "user1", ""). - AddRow("_", "good_name", "USER", "user2", "") - mock.ExpectQuery(`SHOW GRANTS OF ROLE "good_name"`).WillReturnRows(rows) -} - -func TestRoleGrantsRead(t *testing.T) { - r := require.New(t) - - d := roleGrants(t, "good_name||||role1,role2|false", map[string]interface{}{ - "role_name": "good_name", - "roles": []interface{}{"role1", "role2"}, - "users": []interface{}{"user1", "user2"}, - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - r.NotEmpty(d.State()) - expectReadRoleGrants(mock) - err := resources.ReadRoleGrants(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NotEmpty(d.State()) - r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 2) - r.Len(d.Get("roles").(*schema.Set).List(), 2) - }) -} - -func TestRoleGrantsDelete(t *testing.T) { - r := require.New(t) - - d := roleGrants(t, "drop_it||||role1,role2|false", map[string]interface{}{ - "role_name": "drop_it", - "roles": []interface{}{"role1", "role2"}, - "users": []interface{}{"user1", "user2"}, - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`REVOKE ROLE "drop_it" FROM ROLE "role1"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`REVOKE ROLE "drop_it" FROM ROLE "role2"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`REVOKE ROLE "drop_it" FROM USER "user1"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`REVOKE ROLE "drop_it" FROM USER "user2"`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := resources.DeleteRoleGrants(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadUnhandledRoleGrants(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", - "role", - "granted_to", - "grantee_name", - "granted_by", - }). - AddRow("_", "good_name", "ROLE", "role1", ""). - AddRow("_", "good_name", "ROLE", "role2", ""). - AddRow("_", "good_name", "OTHER", "other1", ""). - AddRow("_", "good_name", "OTHER", "other2", ""). - AddRow("_", "good_name", "USER", "user1", ""). - AddRow("_", "good_name", "USER", "user2", "") - mock.ExpectQuery(`SHOW GRANTS OF ROLE "good_name"`).WillReturnRows(rows) -} - -func TestIgnoreUnknownRoleGrants(t *testing.T) { - r := require.New(t) - - d := roleGrants(t, "good_name||||role1,role2|false", map[string]interface{}{ - "role_name": "good_name", - "roles": []interface{}{"role1", "role2"}, - "users": []interface{}{"user1", "user2"}, - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - // Make sure that extraneous grants are ignored. - expectReadUnhandledRoleGrants(mock) - err := resources.ReadRoleGrants(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - r.Len(d.Get("users").(*schema.Set).List(), 2) - r.Len(d.Get("roles").(*schema.Set).List(), 2) - }) -} diff --git a/pkg/resources/role_ownership_grant.go b/pkg/resources/role_ownership_grant.go deleted file mode 100644 index 861e393bb8..0000000000 --- a/pkg/resources/role_ownership_grant.go +++ /dev/null @@ -1,151 +0,0 @@ -package resources - -import ( - "database/sql" - "errors" - "fmt" - "log" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var roleOwnershipGrantSchema = map[string]*schema.Schema{ - "on_role_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the role ownership is granted on.", - }, - "to_role_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", - }, - "current_grants": { - Type: schema.TypeString, - Optional: true, - Description: "Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role.", - Default: "COPY", - ValidateFunc: validation.StringInSlice([]string{ - "COPY", - "REVOKE", - }, true), - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy.", - Default: "ACCOUNTADMIN", - }, -} - -func RoleOwnershipGrant() *schema.Resource { - return &schema.Resource{ - DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_ownership instead.", - Create: CreateRoleOwnershipGrant, - Read: ReadRoleOwnershipGrant, - Delete: DeleteRoleOwnershipGrant, - Update: UpdateRoleOwnershipGrant, - Schema: roleOwnershipGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - } -} - -func CreateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - onRoleName := d.Get("on_role_name").(string) - toRoleName := d.Get("to_role_name").(string) - currentGrants := d.Get("current_grants").(string) - - g := snowflake.NewRoleOwnershipGrantBuilder(onRoleName, currentGrants) - if err := snowflake.Exec(db, g.Role(toRoleName).Grant()); err != nil { - return err - } - - d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) - - return ReadRoleOwnershipGrant(d, meta) -} - -func ReadRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - onRoleName := strings.Split(d.Id(), "|")[0] - currentGrants := strings.Split(d.Id(), "|")[2] - - stmt := fmt.Sprintf("SHOW ROLES LIKE '%s'", onRoleName) - row := snowflake.QueryRow(db, stmt) - - grant, err := snowflake.ScanRoleOwnershipGrant(row) - if errors.Is(err, sql.ErrNoRows) { - // If not found, mark resource to be removed from state file during apply or refresh - log.Printf("[DEBUG] role (%s) not found", d.Id()) - d.SetId("") - return nil - } - if err != nil { - return err - } - - if onRoleName != grant.Name.String { - return fmt.Errorf("no role found like '%s'", onRoleName) - } - - grant.Name.String = strings.TrimPrefix(grant.Name.String, `"`) - grant.Name.String = strings.TrimSuffix(grant.Name.String, `"`) - if err := d.Set("on_role_name", grant.Name.String); err != nil { - return err - } - - grant.Owner.String = strings.TrimPrefix(grant.Owner.String, `"`) - grant.Owner.String = strings.TrimSuffix(grant.Owner.String, `"`) - if err := d.Set("to_role_name", grant.Owner.String); err != nil { - return err - } - - if err := d.Set("current_grants", currentGrants); err != nil { - return err - } - - return nil -} - -func UpdateRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - onRoleName := d.Get("on_role_name").(string) - toRoleName := d.Get("to_role_name").(string) - currentGrants := d.Get("current_grants").(string) - - d.SetId(fmt.Sprintf(`%s|%s|%s`, onRoleName, toRoleName, currentGrants)) - - g := snowflake.NewRoleOwnershipGrantBuilder(onRoleName, currentGrants) - if err := snowflake.Exec(db, g.Role(toRoleName).Grant()); err != nil { - return err - } - - return ReadRoleOwnershipGrant(d, meta) -} - -func DeleteRoleOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - onRoleName := d.Get("on_role_name").(string) - currentGrants := d.Get("current_grants").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - - g := snowflake.NewRoleOwnershipGrantBuilder(onRoleName, currentGrants) - if err := snowflake.Exec(db, g.Role(reversionRole).Revoke()); err != nil { - return err - } - - d.SetId("") - return nil -} diff --git a/pkg/resources/role_ownership_grant_acceptance_test.go b/pkg/resources/role_ownership_grant_acceptance_test.go deleted file mode 100644 index 94aa7d5086..0000000000 --- a/pkg/resources/role_ownership_grant_acceptance_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_RoleOwnershipGrant_defaults(t *testing.T) { - onRoleName := acc.TestClient().Ids.Alpha() - toRoleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: roleOwnershipGrantConfig(onRoleName, toRoleName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_role_ownership_grant.grant", "on_role_name", onRoleName), - resource.TestCheckResourceAttr("snowflake_role_ownership_grant.grant", "to_role_name", toRoleName), - resource.TestCheckResourceAttr("snowflake_role_ownership_grant.grant", "current_grants", "COPY"), - ), - }, - }, - }) -} - -func roleOwnershipGrantConfig(onRoleName, toRoleName string) string { - return fmt.Sprintf(` - -resource "snowflake_role" "role" { - name = "%v" -} - -resource "snowflake_role" "other_role" { - name = "%v" -} - -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - - roles = [ - "ACCOUNTADMIN", - ] -} - -resource "snowflake_role_ownership_grant" "grant" { - on_role_name = snowflake_role.role.name - - to_role_name = snowflake_role.other_role.name - - current_grants = "COPY" -} -`, onRoleName, toRoleName) -} diff --git a/pkg/resources/role_ownership_grant_test.go b/pkg/resources/role_ownership_grant_test.go deleted file mode 100644 index a142ef8fea..0000000000 --- a/pkg/resources/role_ownership_grant_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/stretchr/testify/require" -) - -func TestRoleOwnershipGrant(t *testing.T) { - r := require.New(t) - err := resources.RoleOwnershipGrant().InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestRoleOwnershipGrantCreate(t *testing.T) { - r := require.New(t) - - d := roleOwnershipGrant(t, "good_name", map[string]interface{}{ - "on_role_name": "good_name", - "to_role_name": "other_good_name", - "current_grants": "COPY", - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "other_good_name" COPY CURRENT GRANTS`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadRoleOwnershipGrant(mock) - err := resources.CreateRoleOwnershipGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestRoleOwnershipGrantRead(t *testing.T) { - r := require.New(t) - - d := roleOwnershipGrant(t, "good_name|other_good_name|COPY", map[string]interface{}{ - "on_role_name": "good_name", - "to_role_name": "other_good_name", - "current_grants": "COPY", - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadRoleOwnershipGrant(mock) - err := resources.ReadRoleOwnershipGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadRoleOwnershipGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", - "name", - "is_default", - "is_current", - "is_inherited", - "assigned_to_users", - "granted_to_roles", - "granted_roles", - "owner", - "comment", - }).AddRow("_", "good_name", "", "", "", "", "", "", "other_good_name", "") - mock.ExpectQuery(`SHOW ROLES LIKE 'good_name'`).WillReturnRows(rows) -} - -func TestRoleOwnershipGrantDelete(t *testing.T) { - r := require.New(t) - - d := roleOwnershipGrant(t, "good_name|other_good_name|COPY", map[string]interface{}{ - "on_role_name": "good_name", - "to_role_name": "other_good_name", - "current_grants": "COPY", - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT OWNERSHIP ON ROLE "good_name" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := resources.DeleteRoleOwnershipGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go deleted file mode 100644 index c412631131..0000000000 --- a/pkg/resources/row_access_policy_grant.go +++ /dev/null @@ -1,218 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validRowAccessPoilcyPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeApply, - privilegeAllPrivileges, -) - -var rowAccessPolicyGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the row access policy on which to grant privileges.", - ForceNew: true, - }, - "row_access_policy_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the row access policy on which to grant privileges immediately.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the row access policy. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "APPLY", - ValidateFunc: validation.StringInSlice(validRowAccessPoilcyPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the schema containing the row access policy on which to grant privileges.", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// RowAccessPolicyGrant returns a pointer to the resource representing a row access policy grant. -func RowAccessPolicyGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateRowAccessPolicyGrant, - 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_account_role instead.", - Schema: rowAccessPolicyGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 6 { - return nil, errors.New("invalid row access policy grant ID format. ID must be in the format database_name|schema_name|row_access_policy_name|privilege|with_grant_option|roles") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if err := d.Set("row_access_policy_name", parts[2]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[5])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validRowAccessPoilcyPrivileges, - } -} - -// CreateRowAccessPolicyGrant implements schema.CreateFunc. -func CreateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { - var rowAccessPolicyName string - if name, ok := d.GetOk("row_access_policy_name"); ok { - rowAccessPolicyName = name.(string) - } - if err := d.Set("row_access_policy_name", rowAccessPolicyName); err != nil { - return err - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.RowAccessPolicyGrant(databaseName, schemaName, rowAccessPolicyName) - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, rowAccessPolicyName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadRowAccessPolicyGrant(d, meta) -} - -// ReadRowAccessPolicyGrant implements schema.ReadFunc. -func ReadRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - rowAccessPolicyName := d.Get("row_access_policy_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.RowAccessPolicyGrant(databaseName, schemaName, rowAccessPolicyName) - - err := readGenericGrant(d, meta, rowAccessPolicyGrantSchema, builder, false, false, validRowAccessPoilcyPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, rowAccessPolicyName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteRowAccessPolicyGrant implements schema.DeleteFunc. -func DeleteRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - rowAccessPolicyName := d.Get("row_access_policy_name").(string) - - builder := snowflake.RowAccessPolicyGrant(databaseName, schemaName, rowAccessPolicyName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateRowAccessPolicyGrant implements schema.UpdateFunc. -func UpdateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - rowAccessPolicyName := d.Get("row_access_policy_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - builder := snowflake.RowAccessPolicyGrant(databaseName, schemaName, rowAccessPolicyName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadRowAccessPolicyGrant(d, meta) -} diff --git a/pkg/resources/row_access_policy_grant_acceptance_test.go b/pkg/resources/row_access_policy_grant_acceptance_test.go deleted file mode 100644 index 03ff6c3ca4..0000000000 --- a/pkg/resources/row_access_policy_grant_acceptance_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_RowAccessPolicyGrant(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: rowAccessPolicyGrantConfig(accName, "APPLY", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "row_access_policy_name", accName), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "privilege", "APPLY"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: rowAccessPolicyGrantConfig(accName, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "row_access_policy_name", accName), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_row_access_policy_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - { - ResourceName: "snowflake_row_access_policy_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func rowAccessPolicyGrantConfig(n string, privilege string, databaseName string, schemaName string) string { - return fmt.Sprintf(` -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_row_access_policy" "test" { - name = "%v" - database = "%s" - schema = "%s" - signature = { - N = "VARCHAR" - V = "VARCHAR", - } - row_access_expression = "case when current_role() in ('ANALYST') then true else false end" - comment = "Terraform acceptance test" -} - -resource "snowflake_row_access_policy_grant" "test" { - row_access_policy_name = snowflake_row_access_policy.test.name - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - privilege = "%s" -} -`, n, n, databaseName, schemaName, databaseName, schemaName, privilege) -} diff --git a/pkg/resources/row_access_policy_grant_test.go b/pkg/resources/row_access_policy_grant_test.go deleted file mode 100644 index 134ac8a7da..0000000000 --- a/pkg/resources/row_access_policy_grant_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestRowAccessPolicyGrant(t *testing.T) { - r := require.New(t) - err := resources.RowAccessPolicyGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestRowAccessPolicyGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "row_access_policy_name": "test-row-access-policy", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "APPLY", - "roles": []interface{}{"test-role-1", "test-role-2"}, - } - d := schema.TestResourceDataRaw(t, resources.RowAccessPolicyGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT APPLY ON ROW ACCESS POLICY "test-db"."PUBLIC"."test-row-access-policy" TO ROLE "test-role-1"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT APPLY ON ROW ACCESS POLICY "test-db"."PUBLIC"."test-row-access-policy" TO ROLE "test-role-2"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadRowAccessPolicyGrant(mock) - err := resources.CreateRowAccessPolicyGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestRowAccessPolicyGrantRead(t *testing.T) { - r := require.New(t) - - d := rowAccessPolicyGrant(t, "test-db|PUBLIC|test-row-access-policy|APPLY||false", map[string]interface{}{ - "row_access_policy_name": "test-row-access-policy", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "APPLY", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadRowAccessPolicyGrant(mock) - err := resources.ReadRowAccessPolicyGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadRowAccessPolicyGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "APPLY", "ROW_ACCESS_POLICY", "test-row-access-policy", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "APPLY", "ROW_ACCESS_POLICY", "test-row-access-policy", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON ROW ACCESS POLICY "test-db"."PUBLIC"."test-row-access-policy"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/schema_grant.go b/pkg/resources/schema_grant.go deleted file mode 100644 index ebabaf7cae..0000000000 --- a/pkg/resources/schema_grant.go +++ /dev/null @@ -1,317 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validSchemaPrivileges = NewPrivilegeSet( - privilegeAddSearchOptimization, - privilegeCreateDynamicTable, - privilegeCreateExternalTable, - privilegeCreateFileFormat, - privilegeCreateFunction, - privilegeCreateMaskingPolicy, - privilegeCreateMaterializedView, - privilegeCreatePipe, - privilegeCreateProcedure, - privilegeCreateRowAccessPolicy, - privilegeCreateSequence, - privilegeCreateSessionPolicy, - privilegeCreateStage, - privilegeCreateStream, - privilegeCreateStreamlit, - privilegeCreateTable, - privilegeCreateTag, - privilegeCreateTask, - privilegeCreateTemporaryTable, - privilegeCreateView, - privilegeModify, - privilegeMonitor, - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, -) - -var schemaGrantSchema = map[string]*schema.Schema{ - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema on which to grant privileges.", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the schema on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future schema. Note that if \"OWNERSHIP\" is specified, ensure that the role that terraform is using is granted access. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validSchemaPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future and on_all are unset).", - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, apply this grant on all future schemas in the given database. The schema_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"schema_name", "shares"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, apply this grant on all schemas in the given database. The schema_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"schema_name", "shares"}, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, - "revert_ownership_to_role_name": { - Optional: true, - Type: schema.TypeString, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// SchemaGrant returns a pointer to the resource representing a view grant. -func SchemaGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateSchemaGrant, - 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_account_role instead.", - Schema: schemaGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 8 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected database_name|schema_name|privilege|with_grant_option|on_future|on_all|roles|shares", d.Id()) - } - - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if parts[1] != "" { - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[2]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[3])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[6])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validSchemaPrivileges, - } -} - -// CreateSchemaGrant implements schema.CreateFunc. -func CreateSchemaGrant(d *schema.ResourceData, meta interface{}) error { - schemaName := d.Get("schema_name").(string) - databaseName := d.Get("database_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - if onFuture && onAll { - return errors.New("on_future and on_all cannot both be true") - } - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSchemaGrant(databaseName) - case onAll: - builder = snowflake.AllSchemaGrant(databaseName) - default: - builder = snowflake.SchemaGrant(databaseName, schemaName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - - return ReadSchemaGrant(d, meta) -} - -// UpdateSchemaGrant implements schema.UpdateFunc. -func UpdateSchemaGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update, and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - // create the builder - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSchemaGrant(databaseName) - case onAll: - builder = snowflake.AllSchemaGrant(databaseName) - default: - builder = snowflake.SchemaGrant(databaseName, schemaName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, - builder, - privilege, - reversionRole, - rolesToRevoke, - sharesToRevoke, - ); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares( - meta, - builder, - privilege, - withGrantOption, - rolesToAdd, - sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadSchemaGrant(d, meta) -} - -// ReadSchemaGrant implements schema.ReadFunc. -func ReadSchemaGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSchemaGrant(databaseName) - case onAll: - builder = snowflake.AllSchemaGrant(databaseName) - default: - builder = snowflake.SchemaGrant(databaseName, schemaName) - } - - err := readGenericGrant(d, meta, schemaGrantSchema, builder, onFuture, onAll, validSchemaPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, privilege, withGrantOption, onFuture, onAll, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteSchemaGrant implements schema.DeleteFunc. -func DeleteSchemaGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSchemaGrant(databaseName) - case onAll: - builder = snowflake.AllSchemaGrant(databaseName) - default: - builder = snowflake.SchemaGrant(databaseName, schemaName) - } - return deleteGenericGrant(d, meta, builder) -} diff --git a/pkg/resources/schema_grant_acceptance_test.go b/pkg/resources/schema_grant_acceptance_test.go deleted file mode 100644 index 998a2d84af..0000000000 --- a/pkg/resources/schema_grant_acceptance_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_SchemaGrant(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: schemaGrantConfig(name, normal, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "schema_name", name), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "on_all", "false"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "on_future", "false"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "privilege", "USAGE"), - ), - }, - // FUTURE SHARES - { - Config: schemaGrantConfig(name, onFuture, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("snowflake_schema_grant.test", "schema_name"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "on_all", "false"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "privilege", "USAGE"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_schema_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_SchemaGrantOnAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: schemaGrantConfig(name, onAll, acc.TestDatabaseName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("snowflake_schema_grant.test", "schema_name"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "on_future", "false"), - resource.TestCheckResourceAttr("snowflake_schema_grant.test", "privilege", "USAGE"), - ), - }, - }, - }) -} - -func schemaGrantConfig(name string, grantType grantType, databaseName string) string { - var schemaNameConfig string - switch grantType { - case normal: - schemaNameConfig = "schema_name = snowflake_schema.test.name" - case onFuture: - schemaNameConfig = "on_future = true" - case onAll: - schemaNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource "snowflake_schema" "test" { - name = "%v" - database = "%s" - comment = "Terraform acceptance test" -} - -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_share" "test" { - name = "%v" -} - -resource "snowflake_database_grant" "test" { - database_name = "%s" - shares = [snowflake_share.test.name] -} - -resource "snowflake_schema_grant" "test" { - database_name = "%s" - %v - roles = [snowflake_role.test.name] -} -`, name, databaseName, name, name, databaseName, databaseName, schemaNameConfig) -} diff --git a/pkg/resources/schema_grant_test.go b/pkg/resources/schema_grant_test.go deleted file mode 100644 index 2165925be0..0000000000 --- a/pkg/resources/schema_grant_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package resources_test - -import ( - "database/sql" - "fmt" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestSchemaGrant(t *testing.T) { - r := require.New(t) - err := resources.SchemaGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestSchemaGrantCreate(t *testing.T) { - r := require.New(t) - - for _, testPriv := range []string{"USAGE", "MODIFY", "CREATE TAG"} { - testPriv := testPriv - in := map[string]interface{}{ - "schema_name": "test-schema", - "database_name": "test-db", - "privilege": testPriv, - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.SchemaGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - fmt.Sprintf(`^GRANT %s ON SCHEMA "test-db"."test-schema" TO ROLE "test-role-1" WITH GRANT OPTION$`, testPriv), - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - fmt.Sprintf(`^GRANT %s ON SCHEMA "test-db"."test-schema" TO ROLE "test-role-2" WITH GRANT OPTION$`, testPriv), - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - fmt.Sprintf(`^GRANT %s ON SCHEMA "test-db"."test-schema" TO SHARE "test-share-1" WITH GRANT OPTION$`, testPriv), - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - fmt.Sprintf(`^GRANT %s ON SCHEMA "test-db"."test-schema" TO SHARE "test-share-2" WITH GRANT OPTION$`, testPriv), - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadSchemaGrant(mock, testPriv) - err := resources.CreateSchemaGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - } -} - -func TestSchemaGrantRead(t *testing.T) { - r := require.New(t) - - d := schemaGrant(t, "test-db|test-schema||USAGE||false", map[string]interface{}{ - "schema_name": "test-schema", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{}, - "shares": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadSchemaGrant(mock, "USAGE") - err := resources.ReadSchemaGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) - - shares := d.Get("shares").(*schema.Set) - r.True(shares.Contains("test-share-1")) - r.True(shares.Contains("test-share-2")) - r.Equal(2, shares.Len()) -} - -func expectReadSchemaGrant(mock sqlmock.Sqlmock, testPriv string) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), testPriv, "SCHEMA", "test-schema", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), testPriv, "SCHEMA", "test-schema", "ROLE", "test-role-2", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), testPriv, "SCHEMA", "test-schema", "SHARE", "test-share-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), testPriv, "SCHEMA", "test-schema", "SHARE", "test-share-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON SCHEMA "test-db"."test-schema"$`).WillReturnRows(rows) -} - -func TestFutureSchemaGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.SchemaGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE SCHEMAS IN DATABASE "test-db" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE SCHEMAS IN DATABASE "test-db" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureSchemaGrant(mock) - err := resources.CreateSchemaGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadFutureSchemaGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SCHEMA", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SCHEMA", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go deleted file mode 100644 index f8efc06562..0000000000 --- a/pkg/resources/sequence_grant.go +++ /dev/null @@ -1,282 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validSequencePrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, -) - -var sequenceGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future sequences on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future sequences in the given schema. When this is true and no schema_name is provided apply this grant on all future sequences in the given database. The sequence_name field must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"sequence_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all sequences in the given schema. When this is true and no schema_name is provided apply this grant on all sequences in the given database. The sequence_name field must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"sequence_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future sequence. To grant all privileges, use the value `ALL PRIVILEGES`", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validSequencePrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future sequences on which to grant privileges.", - ForceNew: true, - }, - "sequence_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the sequence on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// SequenceGrant returns a pointer to the resource representing a sequence grant. -func SequenceGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateSequenceGrant, - 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_account_role instead.", - Schema: sequenceGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 8 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected database_name|schema_name|sequence_name|privilege|with_grant_option|on_future|roles", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("sequence_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validSequencePrivileges, - } -} - -// CreateSequenceGrant implements schema.CreateFunc. -func CreateSequenceGrant(d *schema.ResourceData, meta interface{}) error { - sequenceName := d.Get("sequence_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if (sequenceName == "") && !onFuture && !onAll { - return errors.New("sequence_name must be set unless on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSequenceGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllSequenceGrant(databaseName, schemaName) - default: - builder = snowflake.SequenceGrant(databaseName, schemaName, sequenceName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, sequenceName, privilege, withGrantOption, onFuture, onAll, roles) - d.SetId(grantID) - - return ReadSequenceGrant(d, meta) -} - -// ReadSequenceGrant implements schema.ReadFunc. -func ReadSequenceGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - sequenceName := d.Get("sequence_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSequenceGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllSequenceGrant(databaseName, schemaName) - default: - builder = snowflake.SequenceGrant(databaseName, schemaName, sequenceName) - } - - err := readGenericGrant(d, meta, sequenceGrantSchema, builder, onFuture, onAll, validSequencePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, sequenceName, privilege, withGrantOption, onFuture, onAll, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return err -} - -// DeleteSequenceGrant implements schema.DeleteFunc. -func DeleteSequenceGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - sequenceName := d.Get("sequence_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSequenceGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllSequenceGrant(databaseName, schemaName) - default: - builder = snowflake.SequenceGrant(databaseName, schemaName, sequenceName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateSequenceGrant implements schema.UpdateFunc. -func UpdateSequenceGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - sequenceName := d.Get("sequence_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureSequenceGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllSequenceGrant(databaseName, schemaName) - default: - builder = snowflake.SequenceGrant(databaseName, schemaName, sequenceName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadSequenceGrant(d, meta) -} diff --git a/pkg/resources/sequence_grant_acceptance_test.go b/pkg/resources/sequence_grant_acceptance_test.go deleted file mode 100644 index 0888faad92..0000000000 --- a/pkg/resources/sequence_grant_acceptance_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_SequenceGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: sequenceGrantConfig(name, onFuture, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_sequence_grant.test", "sequence_name"), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "privilege", "USAGE"), - ), - }, - { - ResourceName: "snowflake_sequence_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_SequenceGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: sequenceGrantConfig(name, onAll, "USAGE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_sequence_grant.test", "sequence_name"), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_sequence_grant.test", "privilege", "USAGE"), - ), - }, - { - ResourceName: "snowflake_sequence_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func sequenceGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var sequenceNameConfig string - switch grantType { - case onFuture: - sequenceNameConfig = "on_future = true" - case onAll: - sequenceNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource "snowflake_role" "test" { - name = "%s" -} - -resource "snowflake_sequence_grant" "test" { - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - %s - privilege = "%s" -} -`, name, databaseName, schemaName, sequenceNameConfig, privilege) -} diff --git a/pkg/resources/sequence_grant_test.go b/pkg/resources/sequence_grant_test.go deleted file mode 100644 index dbdc1ade57..0000000000 --- a/pkg/resources/sequence_grant_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestSequenceGrant(t *testing.T) { - r := require.New(t) - err := resources.SequenceGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestSequenceGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "sequence_name": "test-sequence", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.SequenceGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT USAGE ON SEQUENCE "test-db"."PUBLIC"."test-sequence" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON SEQUENCE "test-db"."PUBLIC"."test-sequence" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadSequenceGrant(mock) - err := resources.CreateSequenceGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestSequenceGrantRead(t *testing.T) { - r := require.New(t) - - d := sequenceGrant(t, "test-db|PUBLIC|test-sequence|USAGE||false", map[string]interface{}{ - "sequence_name": "test-sequence", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadSequenceGrant(mock) - err := resources.ReadSequenceGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadSequenceGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SEQUENCE", "test-sequence", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SEQUENCE", "test-sequence", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON SEQUENCE "test-db"."PUBLIC"."test-sequence"$`).WillReturnRows(rows) -} - -func TestFutureSequenceGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.SequenceGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE SEQUENCES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE SEQUENCES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureSequenceGrant(mock) - err := resources.CreateSequenceGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.SequenceGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE SEQUENCES IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE SEQUENCES IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureSequenceDatabaseGrant(mock) - err := resources.CreateSequenceGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureSequenceGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SEQUENCE", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SEQUENCE", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureSequenceDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SEQUENCE", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "SEQUENCE", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go deleted file mode 100644 index c6206e46db..0000000000 --- a/pkg/resources/stage_grant.go +++ /dev/null @@ -1,290 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validStagePrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, - // These privileges are only valid for internal stages - privilegeRead, - privilegeWrite, -) - -var stageGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current stage on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future stages in the given schema. When this is true and no schema_name is provided apply this grant on all future stages in the given database. The stage_name field must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"stage_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all stages in the given schema. When this is true and no schema_name is provided apply this grant on all stages in the given database. The stage_name field must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"stage_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the stage. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validStagePrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current stage on which to grant privileges.", - ForceNew: true, - }, - "stage_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the stage on which to grant privilege (only valid if on_future and on_all are false).", - ForceNew: true, - ConflictsWith: []string{"on_future"}, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// StageGrant returns a pointer to the resource representing a stage grant. -func StageGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateStageGrant, - 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_account_role instead.", - Schema: stageGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 8 { - return nil, errors.New("incorrect ID format (expecting database_name|schema_name|stage_name|privilege|with_grant_option|on_future|on_all|roles") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("stage_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validStagePrivileges, - } -} - -// CreateStageGrant implements schema.CreateFunc. -func CreateStageGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - if onFuture && onAll { - return errors.New("on_future and on_all cannot both be true") - } - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - var schemaName string - if name, ok := d.GetOk("schema_name"); ok { - schemaName = name.(string) - } - stageName := d.Get("stage_name").(string) - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - if (stageName == "") && !onFuture && !onAll { - return errors.New("stage_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureStageGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStageGrant(databaseName, schemaName) - default: - builder = snowflake.StageGrant(databaseName, schemaName, stageName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, stageName, privilege, withGrantOption, onFuture, onAll, roles) - d.SetId(grantID) - - return ReadStageGrant(d, meta) -} - -// ReadStageGrant implements schema.ReadFunc. -func ReadStageGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - stageName := d.Get("stage_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureStageGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStageGrant(databaseName, schemaName) - default: - builder = snowflake.StageGrant(databaseName, schemaName, stageName) - } - - err := readGenericGrant(d, meta, stageGrantSchema, builder, onFuture, onAll, validStagePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, stageName, privilege, withGrantOption, onFuture, onAll, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// UpdateStageGrant implements schema.UpdateFunc. -func UpdateStageGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update, and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - var builder snowflake.GrantBuilder - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - stageName := d.Get("stage_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - switch { - case onFuture: - builder = snowflake.FutureStageGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStageGrant(databaseName, schemaName) - default: - builder = snowflake.StageGrant(databaseName, schemaName, stageName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadStageGrant(d, meta) -} - -// DeleteStageGrant implements schema.DeleteFunc. -func DeleteStageGrant(d *schema.ResourceData, meta interface{}) error { - var builder snowflake.GrantBuilder - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - stageName := d.Get("stage_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - switch { - case onFuture: - builder = snowflake.FutureStageGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStageGrant(databaseName, schemaName) - default: - builder = snowflake.StageGrant(databaseName, schemaName, stageName) - } - - return deleteGenericGrant(d, meta, builder) -} diff --git a/pkg/resources/stage_grant_acceptance_test.go b/pkg/resources/stage_grant_acceptance_test.go deleted file mode 100644 index 10c09c9c8a..0000000000 --- a/pkg/resources/stage_grant_acceptance_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_StageGrant_defaults(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: stageGrantConfig(name, normal, "READ", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_role.r", "name", name), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "privilege", "READ"), - testRolesAndShares(t, "snowflake_stage_grant.g", []string{name}), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: stageGrantConfig(name, normal, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_role.r", "name", name), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "privilege", "ALL PRIVILEGES"), - testRolesAndShares(t, "snowflake_stage_grant.g", []string{name}), - ), - }, - // IMPORT - { - ResourceName: "snowflake_stage_grant.g", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func stageGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var stageNameConfig string - switch grantType { - case normal: - stageNameConfig = "stage_name = snowflake_stage.s.name" - case onFuture: - stageNameConfig = "on_future = true" - case onAll: - stageNameConfig = "on_all = true" - } - - return fmt.Sprintf(` - resource snowflake_stage s { - name = "%s" - database = "%s" - schema = "%s" - comment = "Terraform acceptance test" - } - - resource snowflake_role r { - name = "%s" - } - - resource snowflake_stage_grant g { - database_name = "%s" - schema_name = "%s" - %s - - privilege = "%s" - - roles = [ - snowflake_role.r.name - ] - } -`, name, databaseName, schemaName, name, databaseName, schemaName, stageNameConfig, privilege) -} - -func TestAcc_StageFutureGrant(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: stageGrantConfig(name, onFuture, "READ", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_stage_grant.g", "stage_name"), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "privilege", "READ"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_stage_grant.g", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - "on_all", // not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_StageGrantOnAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: stageGrantConfig(name, onAll, "READ", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_stage_grant.g", "stage_name"), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_stage_grant.g", "privilege", "READ"), - ), - }, - }, - }) -} diff --git a/pkg/resources/stage_grant_test.go b/pkg/resources/stage_grant_test.go deleted file mode 100644 index d6337b5308..0000000000 --- a/pkg/resources/stage_grant_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package resources_test - -import ( - "database/sql" - "fmt" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestStageGrant(t *testing.T) { - r := require.New(t) - err := resources.StageGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestStageGrantCreate(t *testing.T) { - r := require.New(t) - - for _, testPriv := range []string{"USAGE", "READ"} { - testPriv := testPriv - in := map[string]interface{}{ - "stage_name": "test-stage", - "schema_name": "test-schema", - "database_name": "test-db", - "privilege": testPriv, - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.StageGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(fmt.Sprintf(`^GRANT %s ON STAGE "test-db"."test-schema"."test-stage" TO ROLE "test-role-1" WITH GRANT OPTION$`, testPriv)).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(fmt.Sprintf(`^GRANT %s ON STAGE "test-db"."test-schema"."test-stage" TO ROLE "test-role-2" WITH GRANT OPTION$`, testPriv)).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadStageGrant(mock, testPriv) - err := resources.CreateStageGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - } -} - -func TestStageGrantRead(t *testing.T) { - r := require.New(t) - - d := stageGrant(t, "test-db|test-schema|test-stage|USAGE||false", map[string]interface{}{ - "stage_name": "test-stage", - "schema_name": "test-schema", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadStageGrant(mock, "USAGE") - err := resources.ReadStageGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadStageGrant(mock sqlmock.Sqlmock, testPriv string) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), testPriv, "STAGE", "test-stage", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), testPriv, "STAGE", "test-stage", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON STAGE "test-db"."test-schema"."test-stage"$`).WillReturnRows(rows) -} - -func TestFutureStageGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.StageGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE STAGES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE STAGES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureStageGrant(mock) - err := resources.CreateStageGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.StageGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT USAGE ON FUTURE STAGES IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT USAGE ON FUTURE STAGES IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureStageDatabaseGrant(mock) - err := resources.CreateStageGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureStageGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "STAGE", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "STAGE", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureStageDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "STAGE", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "STAGE", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go deleted file mode 100644 index 736cce0293..0000000000 --- a/pkg/resources/stream_grant.go +++ /dev/null @@ -1,282 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validStreamPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeSelect, - privilegeAllPrivileges, -) - -var streamGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future streams on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future streams in the given schema. When this is true and no schema_name is provided apply this grant on all future streams in the given database. The stream_name field must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"stream_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all streams in the given schema. When this is true and no schema_name is provided apply this grant on all streams in the given database. The stream_name field must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"stream_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future stream. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: "SELECT", - ValidateFunc: validation.StringInSlice(validStreamPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future streams on which to grant privileges.", - ForceNew: true, - }, - "stream_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the stream on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// StreamGrant returns a pointer to the resource representing a stream grant. -func StreamGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateStreamGrant, - 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_account_role instead.", - Schema: streamGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 8 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected database_name|schema_name|stream_name|privilege|with_grant_option|on_future|roles", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("stream_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validStreamPrivileges, - } -} - -// CreateStreamGrant implements schema.CreateFunc. -func CreateStreamGrant(d *schema.ResourceData, meta interface{}) error { - streamName := d.Get("stream_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if (streamName == "") && !onFuture && !onAll { - return errors.New("stream_name must be set unless on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureStreamGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStreamGrant(databaseName, schemaName) - default: - builder = snowflake.StreamGrant(databaseName, schemaName, streamName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, streamName, privilege, withGrantOption, onFuture, onAll, roles) - d.SetId(grantID) - - return ReadStreamGrant(d, meta) -} - -// ReadStreamGrant implements schema.ReadFunc. -func ReadStreamGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - streamName := d.Get("stream_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureStreamGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStreamGrant(databaseName, schemaName) - default: - builder = snowflake.StreamGrant(databaseName, schemaName, streamName) - } - - err := readGenericGrant(d, meta, streamGrantSchema, builder, onFuture, onAll, validStreamPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, streamName, privilege, withGrantOption, onFuture, onAll, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteStreamGrant implements schema.DeleteFunc. -func DeleteStreamGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - streamName := d.Get("stream_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureStreamGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStreamGrant(databaseName, schemaName) - default: - builder = snowflake.StreamGrant(databaseName, schemaName, streamName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateStreamGrant implements schema.UpdateFunc. -func UpdateStreamGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - streamName := d.Get("stream_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureStreamGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllStreamGrant(databaseName, schemaName) - default: - builder = snowflake.StreamGrant(databaseName, schemaName, streamName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadStreamGrant(d, meta) -} diff --git a/pkg/resources/stream_grant_acceptance_test.go b/pkg/resources/stream_grant_acceptance_test.go deleted file mode 100644 index ef2e2b234a..0000000000 --- a/pkg/resources/stream_grant_acceptance_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_StreamGrant_basic(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - streamName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: streamGrantConfig(name, streamName, normal, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "stream_name", streamName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "on_future", "false"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "on_all", "false"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "privilege", "SELECT"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: streamGrantConfig(name, streamName, normal, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "stream_name", streamName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - { - ResourceName: "snowflake_stream_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_StreamGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - streamName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: streamGrantConfig(name, streamName, onAll, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_stream_grant.test", "stream_name"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "privilege", "SELECT"), - ), - }, - { - ResourceName: "snowflake_stream_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_StreamGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - streamName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: streamGrantConfig(name, streamName, onFuture, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_stream_grant.test", "stream_name"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_stream_grant.test", "privilege", "SELECT"), - ), - }, - { - ResourceName: "snowflake_stream_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func streamGrantConfig(name string, streamName string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var streamNameConfig string - switch grantType { - case normal: - streamNameConfig = "stream_name = snowflake_stream.test.name" - case onFuture: - streamNameConfig = "on_future = true" - case onAll: - streamNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource "snowflake_role" "test" { - name = "%s" -} -resource "snowflake_table" "test" { - name = "%s" - database = "%s" - schema = "%s" - change_tracking = true - comment = "Terraform acceptance test" - - column { - name = "column1" - type = "VARIANT" - } - column { - name = "column2" - type = "VARCHAR(16777216)" - } -} - -resource "snowflake_stream" "test" { - name = "%s" - database = "%s" - schema = "%s" - comment = "Terraform acceptance test" - on_table = "\"${snowflake_table.test.database}\".\"${snowflake_table.test.schema}\".${snowflake_table.test.name}" -} - -resource "snowflake_stream_grant" "test" { - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - %s - privilege = "%s" -} -`, name, name, databaseName, schemaName, streamName, databaseName, schemaName, databaseName, schemaName, streamNameConfig, privilege) -} diff --git a/pkg/resources/stream_grant_test.go b/pkg/resources/stream_grant_test.go deleted file mode 100644 index f6e64125ac..0000000000 --- a/pkg/resources/stream_grant_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestStreamGrant(t *testing.T) { - r := require.New(t) - err := resources.StreamGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestStreamGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "stream_name": "test-stream", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.StreamGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT SELECT ON STREAM "test-db"."PUBLIC"."test-stream" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON STREAM "test-db"."PUBLIC"."test-stream" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadStreamGrant(mock) - err := resources.CreateStreamGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestStreamGrantRead(t *testing.T) { - r := require.New(t) - - d := streamGrant(t, "test-db|PUBLIC|test-stream|SELECT||false", map[string]interface{}{ - "stream_name": "test-stream", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadStreamGrant(mock) - err := resources.ReadStreamGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadStreamGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "STREAM", "test-stream", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "STREAM", "test-stream", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON STREAM "test-db"."PUBLIC"."test-stream"$`).WillReturnRows(rows) -} - -func TestFutureStreamGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.StreamGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE STREAMS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE STREAMS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureStreamGrant(mock) - err := resources.CreateStreamGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.StreamGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE STREAMS IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE STREAMS IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureStreamDatabaseGrant(mock) - err := resources.CreateStreamGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureStreamGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "STREAM", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "STREAM", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureStreamDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "STREAM", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "STREAM", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/table_grant.go b/pkg/resources/table_grant.go deleted file mode 100644 index d0a1fb3c8e..0000000000 --- a/pkg/resources/table_grant.go +++ /dev/null @@ -1,326 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validTablePrivileges = NewPrivilegeSet( - privilegeSelect, - privilegeInsert, - privilegeUpdate, - privilegeDelete, - privilegeTruncate, - privilegeReferences, - privilegeRebuild, - privilegeOwnership, - privilegeAllPrivileges, -) - -var tableGrantSchema = map[string]*schema.Schema{ - "table_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the table on which to grant privileges immediately (only valid if on_future or on_all are unset).", - ForceNew: true, - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future tables on which to grant privileges.", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future tables on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future table. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: privilegeSelect.String(), - ForceNew: true, - ValidateFunc: validation.StringInSlice(validTablePrivileges.ToList(), true), - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future or on_all are unset).", - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future tables in the given schema. When this is true and no schema_name is provided apply this grant on all future tables in the given database. The table_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"table_name", "shares"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all tables in the given schema. When this is true and no schema_name is provided apply this grant on all tables in the given database. The table_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"table_name", "shares"}, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// TableGrant returns a pointer to the resource representing a Table grant. -func TableGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateTableGrant, - 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_account_role instead.", - Schema: tableGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 9 { - return nil, errors.New("invalid ID specified for Table Grant, should be in format database_name|schema_name|table_name|privilege|with_grant_option|on_future|on_all|roles|shares") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("table_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[8])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validTablePrivileges, - } -} - -// CreateTableGrant implements schema.CreateFunc. -func CreateTableGrant(d *schema.ResourceData, meta interface{}) error { - tableName := d.Get("table_name").(string) - var schemaName string - if _, ok := d.GetOk("schema_name"); ok { - schemaName = d.Get("schema_name").(string) - } - databaseName := d.Get("database_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - if onFuture && onAll { - return errors.New("on_future and on_all cannot both be true") - } - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - if (tableName == "") && !onFuture && !onAll { - return errors.New("table_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTableGrant(databaseName, schemaName) - default: - builder = snowflake.TableGrant(databaseName, schemaName, tableName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, tableName, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - return ReadTableGrant(d, meta) -} - -// ReadTableGrant implements schema.ReadFunc. -func ReadTableGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - tableName := d.Get("table_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTableGrant(databaseName, schemaName) - default: - builder = snowflake.TableGrant(databaseName, schemaName, tableName) - } - err := readGenericGrant(d, meta, tableGrantSchema, builder, onFuture, onAll, validTablePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, tableName, privilege, withGrantOption, onFuture, onAll, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteTableGrant implements schema.DeleteFunc. -func DeleteTableGrant(d *schema.ResourceData, meta interface{}) error { - var builder snowflake.GrantBuilder - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - tableName := d.Get("table_name").(string) - switch { - case onFuture: - builder = snowflake.FutureTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTableGrant(databaseName, schemaName) - default: - builder = snowflake.TableGrant(databaseName, schemaName, tableName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateTableGrant implements schema.UpdateFunc. -func UpdateTableGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update, and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - // difference calculates roles/shares to add/revoke - difference := func(key string) (toAdd []string, toRevoke []string) { - o, n := d.GetChange(key) - oldSet := o.(*schema.Set) - newSet := n.(*schema.Set) - toAdd = expandStringList(newSet.Difference(oldSet).List()) - toRevoke = expandStringList(oldSet.Difference(newSet).List()) - return - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = difference("roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = difference("shares") - } - - // create the builder - var builder snowflake.GrantBuilder - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - tableName := d.Get("table_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - switch { - case onFuture: - builder = snowflake.FutureTableGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTableGrant(databaseName, schemaName) - default: - builder = snowflake.TableGrant(databaseName, schemaName, tableName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, - builder, - privilege, - reversionRole, - rolesToRevoke, - sharesToRevoke, - ); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares( - meta, - builder, - privilege, - withGrantOption, - rolesToAdd, - sharesToAdd, - ); err != nil { - return err - } - - // Done, refresh state - return ReadTableGrant(d, meta) -} diff --git a/pkg/resources/table_grant_acceptance_test.go b/pkg/resources/table_grant_acceptance_test.go deleted file mode 100644 index a6ccd11796..0000000000 --- a/pkg/resources/table_grant_acceptance_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_TableGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: tableGrantConfig(name, onAll, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "privilege", "SELECT"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "roles.#", "1"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "roles.0", name), - - testRolesAndShares(t, "snowflake_table_grant.g", []string{name}), - ), - }, - { - ResourceName: "snowflake_table_grant.g", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_TableGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: tableGrantConfig(name, onFuture, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_table_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "privilege", "SELECT"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "roles.#", "1"), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "roles.0", name), - - testRolesAndShares(t, "snowflake_table_grant.g", []string{name}), - ), - }, - // IMPORT - { - ResourceName: "snowflake_table_grant.g", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_TableGrant_defaults(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: tableGrantConfig(name, normal, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_role.r", "name", name), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "table_name", name), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "privilege", "SELECT"), - testRolesAndShares(t, "snowflake_table_grant.g", []string{name}), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: tableGrantConfig(name, normal, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_role.r", "name", name), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "table_name", name), - resource.TestCheckResourceAttr("snowflake_table_grant.g", "privilege", "ALL PRIVILEGES"), - testRolesAndShares(t, "snowflake_table_grant.g", []string{name}), - ), - }, - // IMPORT - { - ResourceName: "snowflake_table_grant.g", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func tableGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var tableNameConfig string - switch grantType { - case normal: - tableNameConfig = "table_name = snowflake_table.t.name" - case onFuture: - tableNameConfig = "on_future = true" - case onAll: - tableNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource snowflake_role r { - name = "%s" -} - -resource snowflake_table t { - name = "%s" - database = "%s" - schema = "%s" - - column { - name = "id" - type = "NUMBER(38,0)" - } -} - -resource snowflake_table_grant g { - database_name = "%s" - schema_name = "%s" - %s - privilege = "%s" - roles = [ - snowflake_role.r.name - ] -} - -`, name, name, databaseName, schemaName, databaseName, schemaName, tableNameConfig, privilege) -} diff --git a/pkg/resources/table_grant_test.go b/pkg/resources/table_grant_test.go deleted file mode 100644 index 689b547dc1..0000000000 --- a/pkg/resources/table_grant_test.go +++ /dev/null @@ -1,216 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/stretchr/testify/require" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" -) - -func TestTableGrant(t *testing.T) { - r := require.New(t) - err := resources.TableGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestTableGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "table_name": "test-table", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.TableGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO SHARE "test-share-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO SHARE "test-share-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadTableGrant(mock) - err := resources.CreateTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestTableGrantUpdate(t *testing.T) { - r := require.New(t) - - // d := schema.TestResourceDataRaw(t, resources.TableGrant().Resource.Schema, in) - d := tableGrant(t, "test-db|PUBLIC|test-table|SELECT||false", map[string]interface{}{ - "table_name": "test-table", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - }) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO ROLE "test-role-1"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO ROLE "test-role-2"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO SHARE "test-share-1"`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON TABLE "test-db"."PUBLIC"."test-table" TO SHARE "test-share-2"`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadTableGrant(mock) - - err := resources.UpdateTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestTableGrantRead(t *testing.T) { - r := require.New(t) - - d := tableGrant(t, "test-db|PUBLIC|test-table|SELECT||false", map[string]interface{}{ - "table_name": "test-table", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{}, - "shares": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadTableGrant(mock) - err := resources.ReadTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) - - shares := d.Get("shares").(*schema.Set) - r.True(shares.Contains("test-share-1")) - r.True(shares.Contains("test-share-2")) - r.Equal(2, shares.Len()) -} - -func expectReadTableGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-table", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-table", "ROLE", "test-role-2", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-table", "SHARE", "test-share-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-table", "SHARE", "test-share-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON TABLE "test-db"."PUBLIC"."test-table"$`).WillReturnRows(rows) -} - -func TestFutureTableGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.TableGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE TABLES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE TABLES IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureTableGrant(mock) - err := resources.CreateTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - roles := d.Get("roles").(*schema.Set) - // After the CreateTableGrant has been created a ReadTableGrant reads the current grants - // and this read should ignore test-role-3 what is returned by SHOW FUTURE GRANTS ON SCHEMA PUBLIC because - // test-role-3 has been granted to a SELECT on future VIEW and not on future TABLE - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.False(roles.Contains("test-role-3")) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.TableGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE TABLES IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE TABLES IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureTableDatabaseGrant(mock) - err := resources.CreateTableGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureTableGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-db.PUBLIC.
", "ROLE", "test-role-2", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-db.PUBLIC.", "ROLE", "test-role-3", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureTableDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-db.
", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-db.
", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/tag_grant.go b/pkg/resources/tag_grant.go deleted file mode 100644 index 3d023277a6..0000000000 --- a/pkg/resources/tag_grant.go +++ /dev/null @@ -1,216 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validTagPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeApply, - privilegeAllPrivileges, -) - -var tagGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the tag on which to grant privileges.", - ForceNew: true, - }, - "tag_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the tag on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the tag. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: "APPLY", - ValidateFunc: validation.StringInSlice(validTagPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the schema containing the tag on which to grant privileges.", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// TagGrant returns a pointer to the resource representing a tag grant. -func TagGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateTagGrant, - 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_account_role instead.", - Schema: tagGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 6 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected database|schema|tag|privilege|with_grant_option|roles", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if err := d.Set("tag_name", parts[2]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[5])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validTagPrivileges, - } -} - -// CreateTagGrant implements schema.CreateFunc. -func CreateTagGrant(d *schema.ResourceData, meta interface{}) error { - tagName := d.Get("tag_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.TagGrant(databaseName, schemaName, tagName) - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, tagName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadTagGrant(d, meta) -} - -// ReadTagGrant implements schema.ReadFunc. -func ReadTagGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - tagName := d.Get("tag_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.TagGrant(databaseName, schemaName, tagName) - - err := readGenericGrant(d, meta, tagGrantSchema, builder, false, false, validTagPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, tagName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// UpdateTagGrant implements schema.UpdateFunc. -func UpdateTagGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update is roles. if nothing changed, - // nothing to update and we're done. - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - tagName := d.Get("tag_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - builder := snowflake.TagGrant(databaseName, schemaName, tagName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, - builder, - privilege, - reversionRole, - rolesToRevoke, - nil, - ); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares( - meta, - builder, - privilege, - withGrantOption, - rolesToAdd, - nil, - ); err != nil { - return err - } - - return ReadTagGrant(d, meta) -} - -// DeleteTagGrant implements schema.DeleteFunc. -func DeleteTagGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - tagName := d.Get("tag_name").(string) - - builder := snowflake.TagGrant(databaseName, schemaName, tagName) - - return deleteGenericGrant(d, meta, builder) -} diff --git a/pkg/resources/tag_grant_acceptance_test.go b/pkg/resources/tag_grant_acceptance_test.go deleted file mode 100644 index 46de4ab72c..0000000000 --- a/pkg/resources/tag_grant_acceptance_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_TagGrant(t *testing.T) { - accName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: tagGrantConfig(accName, "APPLY", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "tag_name", accName), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "privilege", "APPLY"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: tagGrantConfig(accName, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "tag_name", accName), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_tag_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - { - ResourceName: "snowflake_tag_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func tagGrantConfig(name string, privilege string, databaseName string, schemaName string) string { - return fmt.Sprintf(` - resource "snowflake_role" "test" { - name = "%v" - } - - resource "snowflake_tag" "test" { - name = "%v" - database = "%s" - schema = "%s" - allowed_values = [] - } - - resource "snowflake_tag_grant" "test" { - tag_name = snowflake_tag.test.name - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - privilege = "%s" - - } - `, name, name, databaseName, schemaName, databaseName, schemaName, privilege) -} diff --git a/pkg/resources/tag_grant_test.go b/pkg/resources/tag_grant_test.go deleted file mode 100644 index 2e1b33d1d5..0000000000 --- a/pkg/resources/tag_grant_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestTagGrant(t *testing.T) { - r := require.New(t) - err := resources.TagGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestTagGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "tag_name": "test_tag", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "APPLY", - "roles": []interface{}{"test-role-1", "test-role-2"}, - } - d := schema.TestResourceDataRaw(t, resources.TagGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT APPLY ON TAG "test-db"."PUBLIC"."test_tag" TO ROLE "test-role-1"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT APPLY ON TAG "test-db"."PUBLIC"."test_tag" TO ROLE "test-role-2"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadTagGrant(mock) - err := resources.CreateTagGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestTagGrantRead(t *testing.T) { - r := require.New(t) - - d := tagGrant(t, "test-db|PUBLIC|test_tag|APPLY||false", map[string]interface{}{ - "tag_name": "test_tag", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "APPLY", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadTagGrant(mock) - err := resources.ReadTagGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadTagGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "APPLY", "TAG", "test_tag", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "APPLY", "TAG", "test_tag", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON TAG "test-db"."PUBLIC"."test_tag"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go deleted file mode 100644 index 7db2a0b578..0000000000 --- a/pkg/resources/task_grant.go +++ /dev/null @@ -1,281 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validTaskPrivileges = NewPrivilegeSet( - privilegeMonitor, - privilegeOperate, - privilegeOwnership, - privilegeAllPrivileges, -) - -var taskGrantSchema = map[string]*schema.Schema{ - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future tasks on which to grant privileges.", - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - ForceNew: true, - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future tasks in the given schema. When this is true and no schema_name is provided apply this grant on all future tasks in the given database. The task_name field must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"task_name"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all tasks in the given schema. When this is true and no schema_name is provided apply this grant on all tasks in the given database. The task_name field must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"task_name"}, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future task. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: "USAGE", - ValidateFunc: validation.StringInSlice(validTaskPrivileges.ToList(), true), - ForceNew: true, - }, - "roles": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Description: "Grants privilege to these roles.", - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future tasks on which to grant privileges.", - ForceNew: true, - }, - "task_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the task on which to grant privileges immediately (only valid if on_future is false).", - ForceNew: true, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// TaskGrant returns a pointer to the resource representing a task grant. -func TaskGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateTaskGrant, - 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_account_role instead.", - Schema: taskGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 8 { - return nil, fmt.Errorf("unexpected format of ID (%v), expected database_name|schema_name|task_name|privilege|with_grant_option|on_future|roles", d.Id()) - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("task_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validTaskPrivileges, - } -} - -// CreateTaskGrant implements schema.CreateFunc. -func CreateTaskGrant(d *schema.ResourceData, meta interface{}) error { - taskName := d.Get("task_name").(string) - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if (taskName == "") && !onFuture && !onAll { - return errors.New("task_name must be set unless on_future or on_all is true") - } - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureTaskGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTaskGrant(databaseName, schemaName) - default: - builder = snowflake.TaskGrant(databaseName, schemaName, taskName) - } - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, taskName, privilege, withGrantOption, onFuture, onAll, roles) - d.SetId(grantID) - - return ReadTaskGrant(d, meta) -} - -// ReadTaskGrant implements schema.ReadFunc. -func ReadTaskGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - taskName := d.Get("task_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureTaskGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTaskGrant(databaseName, schemaName) - default: - builder = snowflake.TaskGrant(databaseName, schemaName, taskName) - } - - err := readGenericGrant(d, meta, taskGrantSchema, builder, onFuture, onAll, validTaskPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, taskName, privilege, withGrantOption, onFuture, onAll, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteTaskGrant implements schema.DeleteFunc. -func DeleteTaskGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - taskName := d.Get("task_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureTaskGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTaskGrant(databaseName, schemaName) - default: - builder = snowflake.TaskGrant(databaseName, schemaName, taskName) - } - return deleteGenericGrant(d, meta, builder) -} - -// UpdateTaskGrant implements schema.UpdateFunc. -func UpdateTaskGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update and we're done - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - taskName := d.Get("task_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureTaskGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllTaskGrant(databaseName, schemaName) - default: - builder = snowflake.TaskGrant(databaseName, schemaName, taskName) - } - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, []string{}, - ); err != nil { - return err - } - // then add - if err := createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, []string{}, - ); err != nil { - return err - } - - // Done, refresh state - return ReadTaskGrant(d, meta) -} diff --git a/pkg/resources/task_grant_acceptance_test.go b/pkg/resources/task_grant_acceptance_test.go deleted file mode 100644 index 7b4c54d12e..0000000000 --- a/pkg/resources/task_grant_acceptance_test.go +++ /dev/null @@ -1,274 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_TaskGrant(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: taskGrantConfig(name, 8, normal, "OPERATE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "task_name", name), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "OPERATE"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "max_concurrency_level", "8"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "statement_timeout_in_seconds", "86400"), - ), - }, - // UPDATE MAX_CONCURRENCY_LEVEL - { - Config: taskGrantConfig(name, 10, normal, "OPERATE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "task_name", name), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "OPERATE"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "max_concurrency_level", "10"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "statement_timeout_in_seconds", "86400"), - ), - }, - // UPDATE PRIVILEGE - { - Config: taskGrantConfig(name, 10, normal, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "task_name", name), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_task_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_TaskGrant_onAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: taskGrantConfig(name, 8, onAll, "OPERATE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_task_grant.test", "task_name"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "OPERATE"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "max_concurrency_level", "8"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "statement_timeout_in_seconds", "86400"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_task_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_TaskGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: taskGrantConfig(name, 8, onFuture, "OPERATE", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckNoResourceAttr("snowflake_task_grant.test", "task_name"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "OPERATE"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "max_concurrency_level", "8"), - resource.TestCheckResourceAttr("snowflake_warehouse.test", "statement_timeout_in_seconds", "86400"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_task_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func taskGrantConfig(name string, concurrency int32, grantType grantType, privilege string, databaseName string, schemaName string) string { - var taskNameConfig string - switch grantType { - case normal: - taskNameConfig = "task_name \t= snowflake_task.test.name" - case onFuture: - taskNameConfig = "on_future = true" - case onAll: - taskNameConfig = "on_all = true" - } - - s := ` -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_warehouse" "test" { - name = "%s" - max_concurrency_level = %d - statement_timeout_in_seconds = 86400 - query_acceleration_max_scale_factor = 0 -} - -resource "snowflake_task" "test" { - name = "%s" - database = "%s" - schema = "%s" - warehouse = snowflake_warehouse.test.name - sql_statement = "SHOW FUNCTIONS" - enabled = false - schedule = "15 MINUTES" - lifecycle { - ignore_changes = [session_parameters] - } -} - -resource "snowflake_task_grant" "test" { - %s - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - privilege = "%s" - depends_on = [snowflake_task.test] -} -` - return fmt.Sprintf(s, name, name, concurrency, name, databaseName, schemaName, taskNameConfig, databaseName, schemaName, privilege) -} - -func TestAcc_TaskOwnershipGrant_onFuture(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - newName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - // CREATE SCHEMA level FUTURE ownership grant to role - { - Config: taskOwnershipGrantConfig(name, newName, onFuture, "OWNERSHIP", name, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "OWNERSHIP"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "roles.0", name), - ), - }, - // UPDATE SCHEMA level FUTURE OWNERSHIP grant to role - { - Config: taskOwnershipGrantConfig(name, newName, onFuture, "OWNERSHIP", newName, acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_task_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "privilege", "OWNERSHIP"), - resource.TestCheckResourceAttr("snowflake_task_grant.test", "roles.0", newName), - ), - }, - // IMPORT - { - ResourceName: "snowflake_task_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func taskOwnershipGrantConfig(name string, newName string, grantType grantType, privilege string, rolename string, databaseName string, schemaName string) string { - var taskNameConfig string - switch grantType { - case normal: - taskNameConfig = "task_name \t= snowflake_task.test.name" - case onFuture: - taskNameConfig = "on_future = true" - case onAll: - taskNameConfig = "on_all = true" - } - - s := ` -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_role" "test_new" { - name = "%v" -} - -resource "snowflake_task_grant" "test" { - depends_on = [snowflake_role.test, snowflake_role.test_new] - %s - roles = ["%s"] - database_name = "%s" - schema_name = "%s" - privilege = "%s" - with_grant_option = false -} -` - return fmt.Sprintf(s, name, newName, taskNameConfig, rolename, databaseName, schemaName, privilege) -} diff --git a/pkg/resources/task_grant_test.go b/pkg/resources/task_grant_test.go deleted file mode 100644 index ce6b600dff..0000000000 --- a/pkg/resources/task_grant_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestTaskGrant(t *testing.T) { - r := require.New(t) - err := resources.TaskGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestTaskGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "task_name": "test-task", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "OPERATE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.TaskGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT OPERATE ON TASK "test-db"."PUBLIC"."test-task" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT OPERATE ON TASK "test-db"."PUBLIC"."test-task" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadTaskGrant(mock) - err := resources.CreateTaskGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestTaskGrantRead(t *testing.T) { - r := require.New(t) - - d := taskGrant(t, "test-db|PUBLIC|test-task|OPERATE||false", map[string]interface{}{ - "task_name": "test-task", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "OPERATE", - "roles": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadTaskGrant(mock) - err := resources.ReadTaskGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) -} - -func expectReadTaskGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "TASK", "test-task", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "TASK", "test-task", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON TASK "test-db"."PUBLIC"."test-task"$`).WillReturnRows(rows) -} - -func TestFutureTaskGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "OPERATE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.TaskGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT OPERATE ON FUTURE TASKS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT OPERATE ON FUTURE TASKS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureTaskGrant(mock) - err := resources.CreateTaskGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "OPERATE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.TaskGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT OPERATE ON FUTURE TASKS IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT OPERATE ON FUTURE TASKS IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureTaskDatabaseGrant(mock) - err := resources.CreateTaskGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureTaskGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "TASK", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "TASK", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureTaskDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "TASK", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "OPERATE", "TASK", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/user_grant.go b/pkg/resources/user_grant.go deleted file mode 100644 index a8af8e24a7..0000000000 --- a/pkg/resources/user_grant.go +++ /dev/null @@ -1,180 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validUserPrivileges = NewPrivilegeSet( - privilegeMonitor, - privilegeAllPrivileges, -) - -var userGrantSchema = map[string]*schema.Schema{ - "user_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the user on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Required: true, - Description: "The privilege to grant on the user. To grant all privileges, use the value `ALL PRIVILEGES`.", - ForceNew: true, - ValidateFunc: validation.StringInSlice(validUserPrivileges.ToList(), true), - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, -} - -// UserGrant returns a pointer to the resource representing a user grant. -func UserGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateUserGrant, - 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_account_role instead.", - Schema: userGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 4 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected user-name|privilege|with_grant_option|roles", d.Id()) - } - if err := d.Set("user_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[1]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[2])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validUserPrivileges, - } -} - -// CreateUserGrant implements schema.CreateFunc. -func CreateUserGrant(d *schema.ResourceData, meta interface{}) error { - userName := d.Get("user_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - builder := snowflake.UserGrant(userName) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - if err := createGenericGrant(d, meta, builder); err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(userName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadUserGrant(d, meta) -} - -// ReadUserGrant implements schema.ReadFunc. -func ReadUserGrant(d *schema.ResourceData, meta interface{}) error { - userName := d.Get("user_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.UserGrant(userName) - - err := readGenericGrant(d, meta, userGrantSchema, builder, false, false, validUserPrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(userName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteUserGrant implements schema.DeleteFunc. -func DeleteUserGrant(d *schema.ResourceData, meta interface{}) error { - userName := d.Get("user_name").(string) - - builder := snowflake.UserGrant(userName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateUserGrant implements schema.UpdateFunc. -func UpdateUserGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update is roles. if nothing changed, - // nothing to update and we're done. - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - - userName := d.Get("user_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - builder := snowflake.UserGrant(userName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, - builder, - privilege, - "", - rolesToRevoke, - nil, - ); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares( - meta, - builder, - privilege, - withGrantOption, - rolesToAdd, - nil, - ); err != nil { - return err - } - - // Done, refresh state - return ReadUserGrant(d, meta) -} diff --git a/pkg/resources/user_grant_acceptance_test.go b/pkg/resources/user_grant_acceptance_test.go deleted file mode 100644 index a027c4aa56..0000000000 --- a/pkg/resources/user_grant_acceptance_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_UserGrant(t *testing.T) { - wName := acc.TestClient().Ids.Alpha() - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: userGrantConfig(wName, roleName, "MONITOR"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_user_grant.test", "user_name", wName), - resource.TestCheckResourceAttr("snowflake_user_grant.test", "privilege", "MONITOR"), - ), - }, - // UPDATE - { - Config: userGrantConfig(wName, roleName, "ALL PRIVILEGES"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_user_grant.test", "user_name", wName), - resource.TestCheckResourceAttr("snowflake_user_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_user_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func userGrantConfig(n, role, privilege string) string { - return fmt.Sprintf(` - -resource "snowflake_user" "test" { - name = "%v" -} - -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_user_grant" "test" { - user_name = snowflake_user.test.name - roles = [snowflake_role.test.name] - privilege = "%s" -} -`, n, role, privilege) -} diff --git a/pkg/resources/user_grant_test.go b/pkg/resources/user_grant_test.go deleted file mode 100644 index 821f9545bb..0000000000 --- a/pkg/resources/user_grant_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestUserGrant(t *testing.T) { - r := require.New(t) - err := resources.UserGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestUserGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "user_name": "test-user", - "privilege": "MONITOR", - "roles": []interface{}{"test-role-1", "test-role-2"}, - } - d := schema.TestResourceDataRaw(t, resources.UserGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT MONITOR ON USER "test-user" TO ROLE "test-role-1"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT MONITOR ON USER "test-user" TO ROLE "test-role-2"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadUserGrant(mock) - err := resources.CreateUserGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadUserGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "MONITOR", "USER", "test-user", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "MONITOR", "USER", "test-user", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON USER "test-user"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/user_ownership_grant.go b/pkg/resources/user_ownership_grant.go deleted file mode 100644 index 1da2460463..0000000000 --- a/pkg/resources/user_ownership_grant.go +++ /dev/null @@ -1,158 +0,0 @@ -package resources - -import ( - "database/sql" - "errors" - "fmt" - "log" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var userOwnershipGrantSchema = map[string]*schema.Schema{ - "on_user_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the user ownership is granted on.", - }, - "to_role_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the role to grant ownership. Please ensure that the role that terraform is using is granted access.", - }, - "current_grants": { - Type: schema.TypeString, - Optional: true, - Description: "Specifies whether to remove or transfer all existing outbound privileges on the object when ownership is transferred to a new role.", - Default: "COPY", - ValidateFunc: validation.StringInSlice([]string{ - "COPY", - "REVOKE", - }, true), - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy.", - Default: "ACCOUNTADMIN", - }, -} - -func UserOwnershipGrant() *schema.Resource { - return &schema.Resource{ - DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_grant_ownership instead.", - Create: CreateUserOwnershipGrant, - Read: ReadUserOwnershipGrant, - Delete: DeleteUserOwnershipGrant, - Update: UpdateUserOwnershipGrant, - Schema: userOwnershipGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - } -} - -func CreateUserOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - user := d.Get("on_user_name").(string) - role := d.Get("to_role_name").(string) - currentGrants := d.Get("current_grants").(string) - - g := snowflake.NewUserOwnershipGrantBuilder(user, currentGrants) - err := snowflake.Exec(db, g.Role(role).Grant()) - if err != nil { - return err - } - - d.SetId(fmt.Sprintf(`%s|%s|%s`, user, role, currentGrants)) - - return ReadUserOwnershipGrant(d, meta) -} - -func ReadUserOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - log.Println(d.Id()) - user := strings.Split(d.Id(), "|")[0] - currentGrants := strings.Split(d.Id(), "|")[2] - - stmt := fmt.Sprintf("SHOW USERS LIKE '%s'", user) - row := snowflake.QueryRow(db, stmt) - - grant, err := snowflake.ScanUserOwnershipGrant(row) - if errors.Is(err, sql.ErrNoRows) { - // If not found, mark resource to be removed from state file during apply or refresh - log.Printf("[DEBUG] user (%s) not found", d.Id()) - d.SetId("") - return nil - } - if err != nil { - return err - } - - if user != grant.Name.String { - return fmt.Errorf("no user found like '%s'", user) - } - - grant.Name.String = strings.TrimPrefix(grant.Name.String, `"`) - grant.Name.String = strings.TrimSuffix(grant.Name.String, `"`) - err = d.Set("on_user_name", grant.Name.String) - if err != nil { - return err - } - - grant.Owner.String = strings.TrimPrefix(grant.Owner.String, `"`) - grant.Owner.String = strings.TrimSuffix(grant.Owner.String, `"`) - err = d.Set("to_role_name", grant.Owner.String) - if err != nil { - return err - } - - err = d.Set("current_grants", currentGrants) - if err != nil { - return err - } - - return nil -} - -func UpdateUserOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - user := d.Get("on_user_name").(string) - role := d.Get("to_role_name").(string) - currentGrants := d.Get("current_grants").(string) - - d.SetId(fmt.Sprintf(`%s|%s|%s`, user, role, currentGrants)) - - g := snowflake.NewUserOwnershipGrantBuilder(user, currentGrants) - err := snowflake.Exec(db, g.Role(role).Grant()) - if err != nil { - return err - } - - return ReadUserOwnershipGrant(d, meta) -} - -func DeleteUserOwnershipGrant(d *schema.ResourceData, meta interface{}) error { - client := meta.(*provider.Context).Client - db := client.GetConn().DB - user := d.Get("on_user_name").(string) - currentGrants := d.Get("current_grants").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - - g := snowflake.NewUserOwnershipGrantBuilder(user, currentGrants) - err := snowflake.Exec(db, g.Role(reversionRole).Revoke()) - if err != nil { - return err - } - - d.SetId("") - return nil -} diff --git a/pkg/resources/user_ownership_grant_acceptance_test.go b/pkg/resources/user_ownership_grant_acceptance_test.go deleted file mode 100644 index cdd4ba8bc9..0000000000 --- a/pkg/resources/user_ownership_grant_acceptance_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_UserOwnershipGrant_defaults(t *testing.T) { - user := acc.TestClient().Ids.Alpha() - role := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: userOwnershipGrantConfig(user, role), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_user_ownership_grant.grant", "on_user_name", user), - resource.TestCheckResourceAttr("snowflake_user_ownership_grant.grant", "to_role_name", role), - resource.TestCheckResourceAttr("snowflake_user_ownership_grant.grant", "current_grants", "COPY"), - ), - }, - }, - }) -} - -func userOwnershipGrantConfig(user, role string) string { - return fmt.Sprintf(` - -resource "snowflake_user" "user" { - name = "%v" -} - -resource "snowflake_role" "role" { - name = "%v" -} - -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - - roles = [ - "ACCOUNTADMIN", - ] -} - -resource "snowflake_user_ownership_grant" "grant" { - on_user_name = snowflake_user.user.name - - to_role_name = snowflake_role.role.name - - current_grants = "COPY" -} -`, user, role) -} diff --git a/pkg/resources/user_ownership_grant_test.go b/pkg/resources/user_ownership_grant_test.go deleted file mode 100644 index 75cc6b0416..0000000000 --- a/pkg/resources/user_ownership_grant_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/stretchr/testify/require" -) - -func TestUserOwnershipGrant(t *testing.T) { - r := require.New(t) - err := resources.UserOwnershipGrant().InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestUserOwnershipGrantCreate(t *testing.T) { - r := require.New(t) - - d := userOwnershipGrant(t, "user1", map[string]interface{}{ - "on_user_name": "user1", - "to_role_name": "role1", - "current_grants": "COPY", - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT OWNERSHIP ON USER "user1" TO ROLE "role1" COPY CURRENT GRANTS`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadUserOwnershipGrant(mock) - err := resources.CreateUserOwnershipGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestUserOwnershipGrantRead(t *testing.T) { - r := require.New(t) - - d := userOwnershipGrant(t, "user1|role1|COPY", map[string]interface{}{ - "on_user_name": "user1", - "to_role_name": "role1", - "current_grants": "COPY", - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadUserOwnershipGrant(mock) - err := resources.ReadUserOwnershipGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadUserOwnershipGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "name", - "created_on", - "login_name", - "display_name", - "first_name", - "last_name", - "email", - "mins_to_unlock", - "days_to_expiry", - "comment", - "disabled", - "must_change_password", - "snowflake_lock", - "default_warehouse", - "default_namespace", - "default_role", - "default_secondary_roles", - "ext_authn_duo", - "ext_authn_uid", - "mins_to_bypass_mfa", - "owner", - "last_success_login", - "expires_at_time", - "locked_until_time", - "has_password", - "has_rsa_public_key", - }).AddRow("user1", "_", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "role1", "", "", "", "", "") - mock.ExpectQuery(`SHOW USERS LIKE 'user1'`).WillReturnRows(rows) -} - -func TestUserOwnershipGrantDelete(t *testing.T) { - r := require.New(t) - - d := userOwnershipGrant(t, "user1|role1|COPY", map[string]interface{}{ - "on_user_name": "user1", - "to_role_name": "role1", - "current_grants": "COPY", - }) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`GRANT OWNERSHIP ON USER "user1" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`).WillReturnResult(sqlmock.NewResult(1, 1)) - err := resources.DeleteUserOwnershipGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} diff --git a/pkg/resources/view_grant.go b/pkg/resources/view_grant.go deleted file mode 100644 index 8e53a40997..0000000000 --- a/pkg/resources/view_grant.go +++ /dev/null @@ -1,303 +0,0 @@ -package resources - -import ( - "context" - "errors" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validViewPrivileges = NewPrivilegeSet( - privilegeOwnership, - privilegeReferences, - privilegeSelect, - privilegeAllPrivileges, -) - -var viewGrantSchema = map[string]*schema.Schema{ - "view_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the view on which to grant privileges immediately (only valid if on_future and on_all are unset).", - ForceNew: true, - }, - "schema_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the schema containing the current or future views on which to grant privileges.", - ForceNew: true, - }, - "database_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the database containing the current or future views on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the current or future view. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: privilegeSelect.String(), - ForceNew: true, - ValidateFunc: validation.StringInSlice(validViewPrivileges.ToList(), true), - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "shares": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these shares (only valid if on_future and on_all are unset).", - }, - "on_future": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all future views in the given schema. When this is true and no schema_name is provided apply this grant on all future views in the given database. The view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"view_name", "shares"}, - }, - "on_all": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true and a schema_name is provided, apply this grant on all views in the given schema. When this is true and no schema_name is provided apply this grant on all views in the given database. The view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future.", - Default: false, - ForceNew: true, - ConflictsWith: []string{"view_name", "shares"}, - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// ViewGrant returns a pointer to the resource representing a view grant. -func ViewGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateViewGrant, - 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_account_role instead.", - Schema: viewGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 9 { - return nil, errors.New("invalid ID specified, should be in format database_name|schema_name|view_name|privilege|with_grant_option|on_future|on_all|roles|shares") - } - if err := d.Set("database_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("schema_name", parts[1]); err != nil { - return nil, err - } - if parts[2] != "" { - if err := d.Set("view_name", parts[2]); err != nil { - return nil, err - } - } - if err := d.Set("privilege", parts[3]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[4])); err != nil { - return nil, err - } - if err := d.Set("on_future", helpers.StringToBool(parts[5])); err != nil { - return nil, err - } - if err := d.Set("on_all", helpers.StringToBool(parts[6])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[7])); err != nil { - return nil, err - } - if err := d.Set("shares", helpers.StringListToList(parts[8])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validViewPrivileges, - } -} - -// CreateViewGrant implements schema.CreateFunc. -func CreateViewGrant(d *schema.ResourceData, meta interface{}) error { - viewName := d.Get("view_name").(string) - var schemaName string - if _, ok := d.GetOk("schema_name"); ok { - schemaName = d.Get("schema_name").(string) - } - databaseName := d.Get("database_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - if onFuture && onAll { - return errors.New("on_future and on_all cannot both be true") - } - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - if (schemaName == "") && !onFuture && !onAll { - return errors.New("schema_name must be set unless on_future or on_all is true") - } - if (viewName == "") && !onFuture && !onAll { - return errors.New("view_name must be set unless on_future or on_all is true") - } - if (viewName != "") && onFuture && onAll { - return errors.New("view_name must be empty if on_future and on_all are true") - } - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllViewGrant(databaseName, schemaName) - default: - builder = snowflake.ViewGrant(databaseName, schemaName, viewName) - } - - err := createGenericGrant(d, meta, builder) - if err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, viewName, privilege, withGrantOption, onFuture, onAll, roles, shares) - d.SetId(grantID) - return ReadViewGrant(d, meta) -} - -// ReadViewGrant implements schema.ReadFunc. -func ReadViewGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - viewName := d.Get("view_name").(string) - privilege := d.Get("privilege").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - shares := expandStringList(d.Get("shares").(*schema.Set).List()) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllViewGrant(databaseName, schemaName) - default: - builder = snowflake.ViewGrant(databaseName, schemaName, viewName) - } - - err := readGenericGrant(d, meta, viewGrantSchema, builder, onFuture, onAll, validViewPrivileges) - if err != nil { - return err - } - grantID := helpers.EncodeSnowflakeID(databaseName, schemaName, viewName, privilege, withGrantOption, onFuture, onAll, roles, shares) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteViewGrant implements schema.DeleteFunc. -func DeleteViewGrant(d *schema.ResourceData, meta interface{}) error { - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - viewName := d.Get("view_name").(string) - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - - var builder snowflake.GrantBuilder - switch { - case onFuture: - builder = snowflake.FutureViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllViewGrant(databaseName, schemaName) - default: - builder = snowflake.ViewGrant(databaseName, schemaName, viewName) - } - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateViewGrant implements schema.UpdateFunc. -func UpdateViewGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update are roles or shares - // if nothing changed, nothing to update, and we're done - if !d.HasChanges("roles", "shares") { - return nil - } - - rolesToAdd := []string{} - rolesToRevoke := []string{} - sharesToAdd := []string{} - sharesToRevoke := []string{} - if d.HasChange("roles") { - rolesToAdd, rolesToRevoke = changeDiff(d, "roles") - } - if d.HasChange("shares") { - sharesToAdd, sharesToRevoke = changeDiff(d, "shares") - } - databaseName := d.Get("database_name").(string) - schemaName := d.Get("schema_name").(string) - viewName := d.Get("view_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - var builder snowflake.GrantBuilder - onFuture := d.Get("on_future").(bool) - onAll := d.Get("on_all").(bool) - switch { - case onFuture: - builder = snowflake.FutureViewGrant(databaseName, schemaName) - case onAll: - builder = snowflake.AllViewGrant(databaseName, schemaName) - default: - builder = snowflake.ViewGrant(databaseName, schemaName, viewName) - } - - // first revoke - err := deleteGenericGrantRolesAndShares( - meta, builder, privilege, reversionRole, rolesToRevoke, sharesToRevoke) - if err != nil { - return err - } - // then add - err = createGenericGrantRolesAndShares( - meta, builder, privilege, withGrantOption, rolesToAdd, sharesToAdd) - if err != nil { - return err - } - - // Done, refresh state - return ReadViewGrant(d, meta) -} diff --git a/pkg/resources/view_grant_acceptance_test.go b/pkg/resources/view_grant_acceptance_test.go deleted file mode 100644 index fb21ddddbd..0000000000 --- a/pkg/resources/view_grant_acceptance_test.go +++ /dev/null @@ -1,242 +0,0 @@ -package resources_test - -import ( - "bytes" - "fmt" - "testing" - "text/template" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" - "github.com/stretchr/testify/require" -) - -func TestAcc_ViewGrantBasic(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: viewGrantConfig(name, normal, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_view_grant.test", "view_name", name), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "privilege", "SELECT"), - ), - }, - // UPDATE ALL PRIVILEGES - { - Config: viewGrantConfig(name, normal, "ALL PRIVILEGES", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_view_grant.test", "view_name", name), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - { - ResourceName: "snowflake_view_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_ViewGrantShares(t *testing.T) { - viewName := acc.TestClient().Ids.Alpha() - roleName := acc.TestClient().Ids.Alpha() - shareName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: viewGrantConfigShares(t, viewName, roleName, shareName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_view_grant.test", "view_name", viewName), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "privilege", "SELECT"), - ), - }, - { - ResourceName: "snowflake_view_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func TestAcc_ViewGrantChange(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: viewGrantConfig(name, normal, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_view_grant.test", "view_name", name), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "on_future", "false"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "privilege", "SELECT"), - ), - }, - // CHANGE FROM CURRENT TO FUTURE VIEWS - { - Config: viewGrantConfig(name, onFuture, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("snowflake_view_grant.test", "view_name"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "on_future", "true"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "privilege", "SELECT"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_view_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func viewGrantConfigShares(t *testing.T, viewName, role, shareName string) string { - t.Helper() - r := require.New(t) - - tmpl := template.Must(template.New("shares").Parse(` -resource "snowflake_view" "test" { - name = "{{.view_name}}" - database = "{{.database_name}}" - schema = "{{ .schema_name }}" - statement = "SELECT ROLE_NAME, ROLE_OWNER FROM INFORMATION_SCHEMA.APPLICABLE_ROLES" - is_secure = true -} - -resource "snowflake_role" "test" { - name = "{{.role_name}}" -} - -resource "snowflake_share" "test" { - name = "{{.share_name}}" -} - -resource "snowflake_database_grant" "test" { - database_name = "{{ .database_name }}" - shares = ["{{ .share_name }}"] - - depends_on = [snowflake_share.test] -} - -resource "snowflake_view_grant" "test" { - view_name = "{{ .view_name }}" - database_name = "{{ .database_name }}" - roles = ["{{ .role_name }}"] - shares = ["{{ .share_name }}"] - schema_name = "{{ .schema_name }}" - - // HACK(el): There is a problem with the provider where - // in older versions of terraform referencing role.name will - // trick the provider into thinking there are no roles inputted - // so I hard-code the references. - depends_on = [snowflake_database_grant.test, snowflake_role.test, snowflake_share.test, snowflake_view.test] -}`)) - - out := bytes.NewBuffer(nil) - err := tmpl.Execute(out, map[string]string{ - "share_name": shareName, - "database_name": acc.TestDatabaseName, - "schema_name": acc.TestSchemaName, - "role_name": role, - "view_name": viewName, - }) - r.NoError(err) - - return out.String() -} - -func viewGrantConfig(name string, grantType grantType, privilege string, databaseName string, schemaName string) string { - var viewNameConfig string - switch grantType { - case normal: - viewNameConfig = "view_name = \"${snowflake_view.test.name}\"" - case onFuture: - viewNameConfig = "on_future = true" - case onAll: - viewNameConfig = "on_all = true" - } - - return fmt.Sprintf(` -resource "snowflake_view" "test" { - name = "%s" - database = "%s" - schema = "%s" - statement = "SELECT ROLE_NAME, ROLE_OWNER FROM INFORMATION_SCHEMA.APPLICABLE_ROLES" - is_secure = true -} - -resource "snowflake_role" "test" { - name = "%s" -} - -resource "snowflake_view_grant" "test" { - %s - database_name = "%s" - roles = [snowflake_role.test.name] - schema_name = "%s" - privilege = "%s" -} -`, name, databaseName, schemaName, name, viewNameConfig, databaseName, schemaName, privilege) -} - -func TestAcc_ViewGrantOnAll(t *testing.T) { - name := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - PreCheck: func() { acc.TestAccPreCheck(t) }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: viewGrantConfig(name, onAll, "SELECT", acc.TestDatabaseName, acc.TestSchemaName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_view_grant.test", "database_name", acc.TestDatabaseName), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "schema_name", acc.TestSchemaName), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "on_all", "true"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "privilege", "SELECT"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "with_grant_option", "false"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "roles.#", "1"), - resource.TestCheckResourceAttr("snowflake_view_grant.test", "roles.0", name), - testRolesAndShares(t, "snowflake_view_grant.test", []string{name}), - ), - }, - }, - }) -} diff --git a/pkg/resources/view_grant_test.go b/pkg/resources/view_grant_test.go deleted file mode 100644 index c81cb3e211..0000000000 --- a/pkg/resources/view_grant_test.go +++ /dev/null @@ -1,187 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestViewGrant(t *testing.T) { - r := require.New(t) - err := resources.ViewGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestViewGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "view_name": "test-view", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "shares": []interface{}{"test-share-1", "test-share-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.ViewGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-view" TO ROLE "test-role-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-view" TO ROLE "test-role-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-view" TO SHARE "test-share-1" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT SELECT ON VIEW "test-db"."PUBLIC"."test-view" TO SHARE "test-share-2" WITH GRANT OPTION$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadViewGrant(mock) - err := resources.CreateViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func TestViewGrantRead(t *testing.T) { - r := require.New(t) - - d := viewGrant(t, "test-db|PUBLIC|test-view|SELECT||false", map[string]interface{}{ - "view_name": "test-view", - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{}, - "shares": []interface{}{}, - "with_grant_option": false, - }) - - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - expectReadViewGrant(mock) - err := resources.ReadViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) - - roles := d.Get("roles").(*schema.Set) - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.Equal(2, roles.Len()) - - shares := d.Get("shares").(*schema.Set) - r.True(shares.Contains("test-share-1")) - r.True(shares.Contains("test-share-2")) - r.Equal(2, shares.Len()) -} - -func expectReadViewGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-view", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-view", "ROLE", "test-role-2", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-view", "SHARE", "test-share-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-view", "SHARE", "test-share-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON VIEW "test-db"."PUBLIC"."test-view"$`).WillReturnRows(rows) -} - -func TestFutureViewGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "on_future": true, - "schema_name": "PUBLIC", - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": true, - } - d := schema.TestResourceDataRaw(t, resources.ViewGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE VIEWS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-1" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE VIEWS IN SCHEMA "test-db"."PUBLIC" TO ROLE "test-role-2" WITH GRANT OPTION$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureViewGrant(mock) - err := resources.CreateViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - - roles := d.Get("roles").(*schema.Set) - // After the CreateFutureViewGrant has been created a ReadViewGrant reads the current grants - // and this read should ignore test-role-3 what is returned by SHOW FUTURE GRANTS ON SCHEMA PUBLIC because - // test-role-3 has been granted to a SELECT on future TABLE and not on future VIEW - r.True(roles.Contains("test-role-1")) - r.True(roles.Contains("test-role-2")) - r.False(roles.Contains("test-role-3")) - }) - - b := require.New(t) - - in = map[string]interface{}{ - "on_future": true, - "database_name": "test-db", - "privilege": "SELECT", - "roles": []interface{}{"test-role-1", "test-role-2"}, - "with_grant_option": false, - } - d = schema.TestResourceDataRaw(t, resources.ViewGrant().Resource.Schema, in) - b.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec( - `^GRANT SELECT ON FUTURE VIEWS IN DATABASE "test-db" TO ROLE "test-role-1"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec( - `^GRANT SELECT ON FUTURE VIEWS IN DATABASE "test-db" TO ROLE "test-role-2"$`, - ).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadFutureViewDatabaseGrant(mock) - err := resources.CreateViewGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - b.NoError(err) - }) -} - -func expectReadFutureViewGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-db.PUBLIC.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-db.PUBLIC.", "ROLE", "test-role-2", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "TABLE", "test-db.PUBLIC.
", "ROLE", "test-role-3", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN SCHEMA "test-db"."PUBLIC"$`).WillReturnRows(rows) -} - -func expectReadFutureViewDatabaseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "grant_on", "name", "grant_to", "grantee_name", "grant_option", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-db.", "ROLE", "test-role-1", false, - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "SELECT", "VIEW", "test-db.", "ROLE", "test-role-2", false, - ) - mock.ExpectQuery(`^SHOW FUTURE GRANTS IN DATABASE "test-db"$`).WillReturnRows(rows) -} diff --git a/pkg/resources/warehouse_grant.go b/pkg/resources/warehouse_grant.go deleted file mode 100644 index f34394b13b..0000000000 --- a/pkg/resources/warehouse_grant.go +++ /dev/null @@ -1,193 +0,0 @@ -package resources - -import ( - "context" - "fmt" - "strings" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -var validWarehousePrivileges = NewPrivilegeSet( - privilegeModify, - privilegeMonitor, - privilegeOperate, - privilegeOwnership, - privilegeUsage, - privilegeAllPrivileges, -) - -var warehouseGrantSchema = map[string]*schema.Schema{ - "warehouse_name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the warehouse on which to grant privileges.", - ForceNew: true, - }, - "privilege": { - Type: schema.TypeString, - Optional: true, - Description: "The privilege to grant on the warehouse. To grant all privileges, use the value `ALL PRIVILEGES`.", - Default: privilegeUsage.String(), - ForceNew: true, - ValidateFunc: validation.StringInSlice(validWarehousePrivileges.ToList(), true), - }, - "roles": { - Type: schema.TypeSet, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - Description: "Grants privilege to these roles.", - }, - "with_grant_option": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, allows the recipient role to grant the privileges to other roles.", - Default: false, - ForceNew: true, - }, - "enable_multiple_grants": { - Type: schema.TypeBool, - Optional: true, - Description: "When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.", - Default: false, - }, - "revert_ownership_to_role_name": { - Type: schema.TypeString, - Optional: true, - Description: "The name of the role to revert ownership to on destroy. Has no effect unless `privilege` is set to `OWNERSHIP`", - Default: "", - }, -} - -// WarehouseGrant returns a pointer to the resource representing a warehouse grant. -func WarehouseGrant() *TerraformGrantResource { - return &TerraformGrantResource{ - Resource: &schema.Resource{ - Create: CreateWarehouseGrant, - 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_account_role instead.", - Schema: warehouseGrantSchema, - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), helpers.IDDelimiter) - if len(parts) != 4 { - return nil, fmt.Errorf("unexpected format of ID (%q), expected warehouse-name|privilege|with_grant_option|roles", d.Id()) - } - if err := d.Set("warehouse_name", parts[0]); err != nil { - return nil, err - } - if err := d.Set("privilege", parts[1]); err != nil { - return nil, err - } - if err := d.Set("with_grant_option", helpers.StringToBool(parts[2])); err != nil { - return nil, err - } - if err := d.Set("roles", helpers.StringListToList(parts[3])); err != nil { - return nil, err - } - return []*schema.ResourceData{d}, nil - }, - }, - }, - ValidPrivs: validWarehousePrivileges, - } -} - -// CreateWarehouseGrant implements schema.CreateFunc. -func CreateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - warehouseName := d.Get("warehouse_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - builder := snowflake.WarehouseGrant(warehouseName) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - err := createGenericGrant(d, meta, builder) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(warehouseName, privilege, withGrantOption, roles) - d.SetId(grantID) - - return ReadWarehouseGrant(d, meta) -} - -// ReadWarehouseGrant implements schema.ReadFunc. -func ReadWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - warehouseName := d.Get("warehouse_name").(string) - privilege := d.Get("privilege").(string) - withGrantOption := d.Get("with_grant_option").(bool) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - - builder := snowflake.WarehouseGrant(warehouseName) - - err := readGenericGrant(d, meta, warehouseGrantSchema, builder, false, false, validWarehousePrivileges) - if err != nil { - return err - } - - grantID := helpers.EncodeSnowflakeID(warehouseName, privilege, withGrantOption, roles) - if grantID != d.Id() { - d.SetId(grantID) - } - return nil -} - -// DeleteWarehouseGrant implements schema.DeleteFunc. -func DeleteWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - warehouseName := d.Get("warehouse_name").(string) - builder := snowflake.WarehouseGrant(warehouseName) - - return deleteGenericGrant(d, meta, builder) -} - -// UpdateWarehouseGrant implements schema.UpdateFunc. -func UpdateWarehouseGrant(d *schema.ResourceData, meta interface{}) error { - // for now the only thing we can update is roles. if nothing changed, - // nothing to update and we're done. - if !d.HasChanges("roles") { - return nil - } - - rolesToAdd, rolesToRevoke := changeDiff(d, "roles") - - warehouseName := d.Get("warehouse_name").(string) - privilege := d.Get("privilege").(string) - reversionRole := d.Get("revert_ownership_to_role_name").(string) - withGrantOption := d.Get("with_grant_option").(bool) - - // create the builder - builder := snowflake.WarehouseGrant(warehouseName) - - // first revoke - if err := deleteGenericGrantRolesAndShares( - meta, - builder, - privilege, - reversionRole, - rolesToRevoke, - nil, - ); err != nil { - return err - } - - // then add - if err := createGenericGrantRolesAndShares( - meta, - builder, - privilege, - withGrantOption, - rolesToAdd, - nil, - ); err != nil { - return err - } - - // Done, refresh state - return ReadWarehouseGrant(d, meta) -} diff --git a/pkg/resources/warehouse_grant_acceptance_test.go b/pkg/resources/warehouse_grant_acceptance_test.go deleted file mode 100644 index 27664f0a95..0000000000 --- a/pkg/resources/warehouse_grant_acceptance_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package resources_test - -import ( - "fmt" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/tfversion" -) - -func TestAcc_WarehouseGrant(t *testing.T) { - wName := acc.TestClient().Ids.Alpha() - roleName := acc.TestClient().Ids.Alpha() - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: warehouseGrantConfig(wName, roleName, "USAGE"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_warehouse_grant.test", "warehouse_name", wName), - resource.TestCheckResourceAttr("snowflake_warehouse_grant.test", "privilege", "USAGE"), - ), - }, - // UPDATE - { - Config: warehouseGrantConfig(wName, roleName, "ALL PRIVILEGES"), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("snowflake_warehouse_grant.test", "warehouse_name", wName), - resource.TestCheckResourceAttr("snowflake_warehouse_grant.test", "privilege", "ALL PRIVILEGES"), - ), - }, - // IMPORT - { - ResourceName: "snowflake_warehouse_grant.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "enable_multiple_grants", // feature flag attribute not defined in Snowflake, can't be imported - }, - }, - }, - }) -} - -func warehouseGrantConfig(n, role, privilege string) string { - return fmt.Sprintf(` - -resource "snowflake_warehouse" "test" { - name = "%v" -} - -resource "snowflake_role" "test" { - name = "%v" -} - -resource "snowflake_warehouse_grant" "test" { - warehouse_name = snowflake_warehouse.test.name - roles = [snowflake_role.test.name] - privilege = "%s" -} -`, n, role, privilege) -} diff --git a/pkg/resources/warehouse_grant_test.go b/pkg/resources/warehouse_grant_test.go deleted file mode 100644 index b7e97eb038..0000000000 --- a/pkg/resources/warehouse_grant_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package resources_test - -import ( - "database/sql" - "testing" - "time" - - internalprovider "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" - . "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/testhelpers" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/stretchr/testify/require" -) - -func TestWarehouseGrant(t *testing.T) { - r := require.New(t) - err := resources.WarehouseGrant().Resource.InternalValidate(provider.Provider().Schema, true) - r.NoError(err) -} - -func TestWarehouseGrantCreate(t *testing.T) { - r := require.New(t) - - in := map[string]interface{}{ - "warehouse_name": "test-warehouse", - "privilege": "USAGE", - "roles": []interface{}{"test-role-1", "test-role-2"}, - } - d := schema.TestResourceDataRaw(t, resources.WarehouseGrant().Resource.Schema, in) - r.NotNil(d) - - WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) { - mock.ExpectExec(`^GRANT USAGE ON WAREHOUSE "test-warehouse" TO ROLE "test-role-1"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectExec(`^GRANT USAGE ON WAREHOUSE "test-warehouse" TO ROLE "test-role-2"$`).WillReturnResult(sqlmock.NewResult(1, 1)) - expectReadWarehouseGrant(mock) - err := resources.CreateWarehouseGrant(d, &internalprovider.Context{ - Client: sdk.NewClientFromDB(db), - }) - r.NoError(err) - }) -} - -func expectReadWarehouseGrant(mock sqlmock.Sqlmock) { - rows := sqlmock.NewRows([]string{ - "created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name", "grant_option", "granted_by", - }).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "WAREHOUSE", "test-warehouse", "ROLE", "test-role-1", false, "bob", - ).AddRow( - time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), "USAGE", "WAREHOUSE", "test-warehouse", "ROLE", "test-role-2", false, "bob", - ) - mock.ExpectQuery(`^SHOW GRANTS ON WAREHOUSE "test-warehouse"$`).WillReturnRows(rows) -} diff --git a/templates/resources/grant_ownership.md.tmpl b/templates/resources/grant_ownership.md.tmpl index a2249ebb3a..13c31d562a 100644 --- a/templates/resources/grant_ownership.md.tmpl +++ b/templates/resources/grant_ownership.md.tmpl @@ -10,7 +10,6 @@ description: |- {{- end }} --- -~> **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. ~> **Note** For more details about granting ownership, please visit [`GRANT OWNERSHIP` Snowflake documentation page](https://docs.snowflake.com/en/sql-reference/sql/grant-ownership). !> **Warning** Grant ownership resource still has some limitations. Delete operation is not implemented for on_future grants (you have to remove the config and then revoke ownership grant on future X manually). diff --git a/templates/resources/grant_privileges_to_account_role.md.tmpl b/templates/resources/grant_privileges_to_account_role.md.tmpl index e12d772e80..ceb22643b2 100644 --- a/templates/resources/grant_privileges_to_account_role.md.tmpl +++ b/templates/resources/grant_privileges_to_account_role.md.tmpl @@ -10,8 +10,6 @@ description: |- {{- end }} --- -~> **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). diff --git a/templates/resources/grant_privileges_to_database_role.md.tmpl b/templates/resources/grant_privileges_to_database_role.md.tmpl index 1f31f6ac18..1980f5c3ea 100644 --- a/templates/resources/grant_privileges_to_database_role.md.tmpl +++ b/templates/resources/grant_privileges_to_database_role.md.tmpl @@ -10,8 +10,6 @@ description: |- {{- end }} --- -~> **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). diff --git a/templates/resources/grant_privileges_to_share.md.tmpl b/templates/resources/grant_privileges_to_share.md.tmpl index 2132602c86..d47f0a4ef9 100644 --- a/templates/resources/grant_privileges_to_share.md.tmpl +++ b/templates/resources/grant_privileges_to_share.md.tmpl @@ -10,8 +10,6 @@ description: |- {{- end }} --- -~> **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. - # {{.Name}} ({{.Type}}) {{ .Description | trimspace }} From 7057a14a1f9a72cb2b06f77afb563a538e99c57e Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 13:34:54 +0200 Subject: [PATCH 05/10] Remove from snowflake package --- pkg/snowflake/all_grant.go | 261 ------------- pkg/snowflake/all_grant_test.go | 22 -- pkg/snowflake/escaping.go | 24 -- pkg/snowflake/escaping_test.go | 42 --- pkg/snowflake/future_grant.go | 268 -------------- pkg/snowflake/future_grant_test.go | 246 ------------- pkg/snowflake/grant.go | 405 --------------------- pkg/snowflake/grant_test.go | 366 ------------------- pkg/snowflake/role.go | 128 ------- pkg/snowflake/role_grant.go | 41 --- pkg/snowflake/role_grant_test.go | 25 -- pkg/snowflake/role_ownership_grant.go | 60 --- pkg/snowflake/role_ownership_grant_test.go | 26 -- pkg/snowflake/user_ownership_grant.go | 76 ---- pkg/snowflake/user_ownership_grant_test.go | 26 -- 15 files changed, 2016 deletions(-) delete mode 100644 pkg/snowflake/all_grant.go delete mode 100644 pkg/snowflake/all_grant_test.go delete mode 100644 pkg/snowflake/future_grant.go delete mode 100644 pkg/snowflake/future_grant_test.go delete mode 100644 pkg/snowflake/grant.go delete mode 100644 pkg/snowflake/grant_test.go delete mode 100644 pkg/snowflake/role.go delete mode 100644 pkg/snowflake/role_grant.go delete mode 100644 pkg/snowflake/role_grant_test.go delete mode 100644 pkg/snowflake/role_ownership_grant.go delete mode 100644 pkg/snowflake/role_ownership_grant_test.go delete mode 100644 pkg/snowflake/user_ownership_grant.go delete mode 100644 pkg/snowflake/user_ownership_grant_test.go diff --git a/pkg/snowflake/all_grant.go b/pkg/snowflake/all_grant.go deleted file mode 100644 index 7ad100fde9..0000000000 --- a/pkg/snowflake/all_grant.go +++ /dev/null @@ -1,261 +0,0 @@ -package snowflake - -import ( - "fmt" -) - -type ( - AllGrantType string - AllGrantTarget string -) - -const ( - AllAccountGrantAccount AllGrantType = "ACCOUNT" - AllGrantTypeSchema AllGrantType = "SCHEMA" - AllGrantTypeTable AllGrantType = "TABLE" - AllGrantTypeView AllGrantType = "VIEW" - AllGrantTypeMaterializedView AllGrantType = "MATERIALIZED VIEW" - AllGrantTypeStage AllGrantType = "STAGE" - AllGrantTypeExternalTable AllGrantType = "EXTERNAL TABLE" - AllGrantTypeFileFormat AllGrantType = "FILE FORMAT" - AllGrantTypeFunction AllGrantType = "FUNCTION" - AllGrantTypeProcedure AllGrantType = "PROCEDURE" - AllGrantTypeSequence AllGrantType = "SEQUENCE" - AllGrantTypeStream AllGrantType = "STREAM" - AllGrantTypeTask AllGrantType = "TASK" - // AllPipeGrants are not allowed by snowflake ("Note that bulk grants on pipes are not allowed.", see https://docs.snowflake.com/en/sql-reference/sql/grant-privilege#required-parameters) - // AllGrantTypePipe AllGrantType = "PIPE". -) - -const ( - AllGrantTargetSchema AllGrantTarget = "SCHEMA" - AllGrantTargetDatabase AllGrantTarget = "DATABASE" -) - -// AllGrantBuilder abstracts the creation of ExistingGrantExecutables. -type AllGrantBuilder struct { - name string - qualifiedName string - allGrantType AllGrantType - allGrantTarget AllGrantTarget -} - -func getNameAndQualifiedNameForAllGrants(db, schema string) (string, string, AllGrantTarget) { - name := schema - AllGrantTarget := AllGrantTargetSchema - qualifiedName := fmt.Sprintf(`"%v"."%v"`, db, schema) - - if schema == "" { - name = db - AllGrantTarget = AllGrantTargetDatabase - qualifiedName = fmt.Sprintf(`"%v"`, db) - } - - return name, qualifiedName, AllGrantTarget -} - -// Name returns the object name for this FutureGrantBuilder. -func (agb *AllGrantBuilder) Name() string { - return agb.name -} - -func (agb *AllGrantBuilder) GrantType() string { - return string(agb.allGrantType) -} - -// AllSchemaGrant returns a pointer to a AllGrantBuilder for a schema. -func AllSchemaGrant(db string) GrantBuilder { - return &AllGrantBuilder{ - name: db, - qualifiedName: fmt.Sprintf(`"%v"`, db), - allGrantType: AllGrantTypeSchema, - allGrantTarget: AllGrantTargetDatabase, - } -} - -// AllTableGrant returns a pointer to a AllGrantBuilder for a table. -func AllTableGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeTable, - allGrantTarget: target, - } -} - -// AllViewGrant returns a pointer to a AllGrantBuilder for a view. -func AllViewGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeView, - allGrantTarget: target, - } -} - -// AllMaterializedViewGrant returns a pointer to a AllGrantBuilder for a view. -func AllMaterializedViewGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeMaterializedView, - allGrantTarget: target, - } -} - -// AllStageGrant returns a pointer to a AllGrantBuilder for a stage. -func AllStageGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeStage, - allGrantTarget: target, - } -} - -// AllExternalTableGrant returns a pointer to a AllGrantBuilder for a external table. -func AllExternalTableGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeExternalTable, - allGrantTarget: target, - } -} - -// AllFileFormatGrant returns a pointer to a AllGrantBuilder for a file format. -func AllFileFormatGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeFileFormat, - allGrantTarget: target, - } -} - -// AllFunctionGrant returns a pointer to a AllGrantBuilder for a function. -func AllFunctionGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeFunction, - allGrantTarget: target, - } -} - -// AllProcedureGrant returns a pointer to a AllGrantBuilder for a procedure. -func AllProcedureGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeProcedure, - allGrantTarget: target, - } -} - -// AllSequenceGrant returns a pointer to a AllGrantBuilder for a sequence. -func AllSequenceGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeSequence, - allGrantTarget: target, - } -} - -// AllStreamGrant returns a pointer to a AllGrantBuilder for a stream. -func AllStreamGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeStream, - allGrantTarget: target, - } -} - -// AllTaskGrant returns a pointer to a AllGrantBuilder for a task. -func AllTaskGrant(db, schema string) GrantBuilder { - name, qualifiedName, target := getNameAndQualifiedNameForAllGrants(db, schema) - return &AllGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - allGrantType: AllGrantTypeTask, - allGrantTarget: target, - } -} - -// Show returns the SQL that will show all privileges on the grant. -func (agb *AllGrantBuilder) Show() string { - return fmt.Sprintf(`SHOW ALL GRANTS IN %v %v`, agb.allGrantTarget, agb.qualifiedName) -} - -// Role returns a pointer to a AllGrantExecutable for a role. -func (agb *AllGrantBuilder) Role(n string) GrantExecutable { - return &AllGrantExecutable{ - granteeName: n, - grantName: agb.qualifiedName, - allGrantType: agb.allGrantType, - allGrantTarget: agb.allGrantTarget, - } -} - -// Share is not implemented because all objects cannot be granted to shares. -func (agb *AllGrantBuilder) Share(_ string) GrantExecutable { - return nil -} - -// AllGrantExecutable abstracts the creation of SQL queries to build all grants for -// different all grant types. -type AllGrantExecutable struct { - grantName string - granteeName string - allGrantType AllGrantType - allGrantTarget AllGrantTarget -} - -// Grant returns the SQL that will grant all privileges on the grant to the grantee. -func (ege *AllGrantExecutable) Grant(p string, w bool) string { - var template string - if w { - template = `GRANT %v ON ALL %vS IN %v %v TO ROLE "%v" WITH GRANT OPTION` - } else { - template = `GRANT %v ON ALL %vS IN %v %v TO ROLE "%v"` - } - return fmt.Sprintf(template, - p, ege.allGrantType, ege.allGrantTarget, ege.grantName, ege.granteeName) -} - -// Revoke returns the SQL that will revoke all privileges on the grant from the grantee. -func (ege *AllGrantExecutable) Revoke(p string) []string { - // Note: has no effect for ALL GRANTS - return []string{ - fmt.Sprintf(`REVOKE %v ON ALL %vS IN %v %v FROM ROLE "%v"`, - p, ege.allGrantType, ege.allGrantTarget, ege.grantName, ege.granteeName), - } -} - -// Revoke returns the SQL that will revoke ownership privileges on the grant from the grantee. -// Note: returns the same SQL as Revoke. -func (ege *AllGrantExecutable) RevokeOwnership(r string) []string { - // Note: has no effect for ALL GRANTS - return []string{ - fmt.Sprintf(`REVOKE OWNERSHIP ON ALL %vS IN %v %v FROM ROLE "%v"`, - ege.allGrantType, ege.allGrantTarget, ege.grantName, ege.granteeName), - } -} - -// Show returns the SQL that will show all grants on the schema. -func (ege *AllGrantExecutable) Show() string { - // Note: There is no `SHOW ALL GRANTS IN \"test_db\"`, therefore changed the query to `SHOW ALL GRANTS IN \"test_db\"` to have a command, which runs in snowflake. - return fmt.Sprintf(`SHOW GRANTS ON %v %v`, ege.allGrantTarget, ege.grantName) -} diff --git a/pkg/snowflake/all_grant_test.go b/pkg/snowflake/all_grant_test.go deleted file mode 100644 index 84fd341b4d..0000000000 --- a/pkg/snowflake/all_grant_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package snowflake_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/stretchr/testify/require" -) - -func TestExistingSchemaGrant(t *testing.T) { - r := require.New(t) - builder := snowflake.AllSchemaGrant("test_db") - - r.Equal("test_db", builder.Name()) - - r.Equal(string(snowflake.AllGrantTypeSchema), builder.GrantType()) - - eb := builder.Role("bob") - r.Equal("SHOW GRANTS ON DATABASE \"test_db\"", eb.Show()) - r.Equal(`GRANT USAGE ON ALL SCHEMAS IN DATABASE "test_db" TO ROLE "bob"`, eb.Grant("USAGE", false)) - r.Equal([]string{`REVOKE USAGE ON ALL SCHEMAS IN DATABASE "test_db" FROM ROLE "bob"`}, eb.Revoke("USAGE")) -} diff --git a/pkg/snowflake/escaping.go b/pkg/snowflake/escaping.go index 42e1883832..9394d3d96b 100644 --- a/pkg/snowflake/escaping.go +++ b/pkg/snowflake/escaping.go @@ -2,7 +2,6 @@ package snowflake import ( "fmt" - "regexp" "strings" ) @@ -14,13 +13,6 @@ func EscapeString(in string) string { return out } -// UnescapeString reverses EscapeString. -func UnescapeString(in string) string { - out := strings.ReplaceAll(in, `\\`, `\`) - out = strings.ReplaceAll(out, `\'`, `'`) - return out -} - // EscapeSnowflakeString will escape single quotes with the SQL native double single quote. func EscapeSnowflakeString(in string) string { out := strings.ReplaceAll(in, `'`, `''`) @@ -34,19 +26,3 @@ func UnescapeSnowflakeString(in string) string { out = strings.ReplaceAll(out, `''`, `'`) return out } - -// AddressEscape wraps a name inside double quotes only if required by Snowflake. -func AddressEscape(in ...string) string { - quoteCheck := regexp.MustCompile(`[^A-Z0-9_]`) - address := make([]string, len(in)) - - for i, n := range in { - if quoteCheck.MatchString(n) { - address[i] = fmt.Sprintf(`"%s"`, strings.ReplaceAll(n, `"`, `\"`)) - } else { - address[i] = n - } - } - - return strings.Join(address, ".") -} diff --git a/pkg/snowflake/escaping_test.go b/pkg/snowflake/escaping_test.go index 93ad9d31e2..441985b02a 100644 --- a/pkg/snowflake/escaping_test.go +++ b/pkg/snowflake/escaping_test.go @@ -23,45 +23,3 @@ func TestUnescapeSnowflakeString(t *testing.T) { r := require.New(t) r.Equal(`table's quoted`, snowflake.UnescapeSnowflakeString(`'table''s quoted'`)) } - -func TestAddressEscape(t *testing.T) { - testCases := []struct { - id string - name []string - expected string - }{ - { - id: "single no escape", - name: []string{"HELLO"}, - expected: "HELLO", - }, - { - id: "multiple no escape", - name: []string{"HELLO", "WORLD"}, - expected: "HELLO.WORLD", - }, - { - id: "single escape", - name: []string{"hello"}, - expected: `"hello"`, - }, - { - id: "multiple escape", - name: []string{"hello", "world"}, - expected: `"hello"."world"`, - }, - { - id: "mixed escape", - name: []string{"hello", "world", "NOTHERE"}, - expected: `"hello"."world".NOTHERE`, - }, - } - - for _, tc := range testCases { - tc := tc - t.Run(tc.id, func(t *testing.T) { - r := require.New(t) - r.Equal(tc.expected, snowflake.AddressEscape(tc.name...)) - }) - } -} diff --git a/pkg/snowflake/future_grant.go b/pkg/snowflake/future_grant.go deleted file mode 100644 index eb121de143..0000000000 --- a/pkg/snowflake/future_grant.go +++ /dev/null @@ -1,268 +0,0 @@ -package snowflake - -import ( - "fmt" -) - -type ( - futureGrantType string - futureGrantTarget string -) - -const ( - futureSchemaType futureGrantType = "SCHEMA" - futureTableType futureGrantType = "TABLE" - futureViewType futureGrantType = "VIEW" - futureMaterializedViewType futureGrantType = "MATERIALIZED VIEW" - futureStageType futureGrantType = "STAGE" - futureExternalTableType futureGrantType = "EXTERNAL TABLE" - futureFileFormatType futureGrantType = "FILE FORMAT" - futureFunctionType futureGrantType = "FUNCTION" - futureProcedureType futureGrantType = "PROCEDURE" - futureSequenceType futureGrantType = "SEQUENCE" - futureStreamType futureGrantType = "STREAM" - futurePipeType futureGrantType = "PIPE" - futureTaskType futureGrantType = "TASK" -) - -const ( - futureSchemaTarget futureGrantTarget = "SCHEMA" - futureDatabaseTarget futureGrantTarget = "DATABASE" -) - -// FutureGrantBuilder abstracts the creation of FutureGrantExecutables. -type FutureGrantBuilder struct { - name string - qualifiedName string - futureGrantType futureGrantType - futureGrantTarget futureGrantTarget -} - -func getNameAndQualifiedNameForFutureGrants(db, schema string) (string, string, futureGrantTarget) { - name := schema - futureTarget := futureSchemaTarget - qualifiedName := fmt.Sprintf(`"%v"."%v"`, db, schema) - - if schema == "" { - name = db - futureTarget = futureDatabaseTarget - qualifiedName = fmt.Sprintf(`"%v"`, db) - } - - return name, qualifiedName, futureTarget -} - -// Name returns the object name for this FutureGrantBuilder. -func (fgb *FutureGrantBuilder) Name() string { - return fgb.name -} - -func (fgb *FutureGrantBuilder) GrantType() string { - return string(fgb.futureGrantType) -} - -// FutureSchemaGrant returns a pointer to a FutureGrantBuilder for a schema. -func FutureSchemaGrant(db string) GrantBuilder { - return &FutureGrantBuilder{ - name: db, - qualifiedName: fmt.Sprintf(`"%v"`, db), - futureGrantType: futureSchemaType, - futureGrantTarget: futureDatabaseTarget, - } -} - -// FutureTableGrant returns a pointer to a FutureGrantBuilder for a table. -func FutureTableGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureTableType, - futureGrantTarget: futureTarget, - } -} - -// FutureViewGrant returns a pointer to a FutureGrantBuilder for a view. -func FutureViewGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureViewType, - futureGrantTarget: futureTarget, - } -} - -// FutureMaterializedViewGrant returns a pointer to a FutureGrantBuilder for a view. -func FutureMaterializedViewGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureMaterializedViewType, - futureGrantTarget: futureTarget, - } -} - -// FutureStageGrant returns a pointer to a FutureGrantBuilder for a stage. -func FutureStageGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureStageType, - futureGrantTarget: futureTarget, - } -} - -// FutureExternalTableGrant returns a pointer to a FutureGrantBuilder for a external table. -func FutureExternalTableGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureExternalTableType, - futureGrantTarget: futureTarget, - } -} - -// FutureFileFormatGrant returns a pointer to a FutureGrantBuilder for a file format. -func FutureFileFormatGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureFileFormatType, - futureGrantTarget: futureTarget, - } -} - -// FutureFunctionGrant returns a pointer to a FutureGrantBuilder for a function. -func FutureFunctionGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureFunctionType, - futureGrantTarget: futureTarget, - } -} - -// FutureProcedureGrant returns a pointer to a FutureGrantBuilder for a procedure. -func FutureProcedureGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureProcedureType, - futureGrantTarget: futureTarget, - } -} - -// FutureSequenceGrant returns a pointer to a FutureGrantBuilder for a sequence. -func FutureSequenceGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureSequenceType, - futureGrantTarget: futureTarget, - } -} - -// FutureStreamGrant returns a pointer to a FutureGrantBuilder for a stream. -func FutureStreamGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureStreamType, - futureGrantTarget: futureTarget, - } -} - -// FuturePipeGrant returns a pointer to a FutureGrantBuilder for a pipe. -func FuturePipeGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futurePipeType, - futureGrantTarget: futureTarget, - } -} - -// FutureTaskGrant returns a pointer to a FutureGrantBuilder for a task. -func FutureTaskGrant(db, schema string) GrantBuilder { - name, qualifiedName, futureTarget := getNameAndQualifiedNameForFutureGrants(db, schema) - return &FutureGrantBuilder{ - name: name, - qualifiedName: qualifiedName, - futureGrantType: futureTaskType, - futureGrantTarget: futureTarget, - } -} - -// Show returns the SQL that will show all privileges on the grant. -func (fgb *FutureGrantBuilder) Show() string { - return fmt.Sprintf(`SHOW FUTURE GRANTS IN %v %v`, fgb.futureGrantTarget, fgb.qualifiedName) -} - -// FutureGrantExecutable abstracts the creation of SQL queries to build future grants for -// different future grant types. -type FutureGrantExecutable struct { - grantName string - granteeName string - futureGrantType futureGrantType - futureGrantTarget futureGrantTarget -} - -// Role returns a pointer to a FutureGrantExecutable for a role. -func (fgb *FutureGrantBuilder) Role(n string) GrantExecutable { - return &FutureGrantExecutable{ - granteeName: n, - grantName: fgb.qualifiedName, - futureGrantType: fgb.futureGrantType, - futureGrantTarget: fgb.futureGrantTarget, - } -} - -// Share is not implemented because future objects cannot be granted to shares. -func (fgb *FutureGrantBuilder) Share(_ string) GrantExecutable { - return nil -} - -// Grant returns the SQL that will grant future privileges on the grant to the grantee. -func (fge *FutureGrantExecutable) Grant(p string, w bool) string { - var template string - if w { - template = `GRANT %v ON FUTURE %vS IN %v %v TO ROLE "%v" WITH GRANT OPTION` - } else { - template = `GRANT %v ON FUTURE %vS IN %v %v TO ROLE "%v"` - } - return fmt.Sprintf(template, - p, fge.futureGrantType, fge.futureGrantTarget, fge.grantName, fge.granteeName) -} - -// Revoke returns the SQL that will revoke future privileges on the grant from the grantee. -func (fge *FutureGrantExecutable) Revoke(p string) []string { - return []string{ - fmt.Sprintf(`REVOKE %v ON FUTURE %vS IN %v %v FROM ROLE "%v"`, - p, fge.futureGrantType, fge.futureGrantTarget, fge.grantName, fge.granteeName), - } -} - -// Revoke returns the SQL that will revoke ownership privileges on the grant from the grantee. -// Note: returns the same SQL as Revoke. -func (fge *FutureGrantExecutable) RevokeOwnership(r string) []string { - // Note: has no effect for ALL GRANTS - return []string{ - fmt.Sprintf(`REVOKE OWNERSHIP ON FUTURE %vS IN %v %v FROM ROLE "%v"`, - fge.futureGrantType, fge.futureGrantTarget, fge.grantName, fge.granteeName), - } -} - -// Show returns the SQL that will show all future grants on the schema. -func (fge *FutureGrantExecutable) Show() string { - return fmt.Sprintf(`SHOW FUTURE GRANTS IN %v %v`, fge.futureGrantTarget, fge.grantName) -} diff --git a/pkg/snowflake/future_grant_test.go b/pkg/snowflake/future_grant_test.go deleted file mode 100644 index 135c3e3710..0000000000 --- a/pkg/snowflake/future_grant_test.go +++ /dev/null @@ -1,246 +0,0 @@ -package snowflake_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/stretchr/testify/require" -) - -func TestFutureSchemaGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureSchemaGrant("test_db") - r.Equal("test_db", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUTURE SCHEMAS IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUTURE SCHEMAS IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestFutureTableGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureTableGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUTURE TABLES IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUTURE TABLES IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureTableGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("USAGE", false) - b.Equal(`GRANT USAGE ON FUTURE TABLES IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("USAGE") - b.Equal([]string{`REVOKE USAGE ON FUTURE TABLES IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestFutureMaterializedViewGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureMaterializedViewGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("SELECT", false) - r.Equal(`GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("SELECT") - r.Equal([]string{`REVOKE SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureMaterializedViewGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("SELECT", false) - b.Equal(`GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("SELECT") - b.Equal([]string{`REVOKE SELECT ON FUTURE MATERIALIZED VIEWS IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestFutureViewGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureViewGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUTURE VIEWS IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUTURE VIEWS IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureViewGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("USAGE", false) - b.Equal(`GRANT USAGE ON FUTURE VIEWS IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("USAGE") - b.Equal([]string{`REVOKE USAGE ON FUTURE VIEWS IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestFutureStageGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureStageGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUTURE STAGES IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUTURE STAGES IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureStageGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("USAGE", false) - b.Equal(`GRANT USAGE ON FUTURE STAGES IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("USAGE") - b.Equal([]string{`REVOKE USAGE ON FUTURE STAGES IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestShowFutureGrantsInSchema(t *testing.T) { - r := require.New(t) - s := snowflake.FutureTableGrant("test_db", "PUBLIC").Role("testRole").Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = snowflake.FutureTableGrant("test_db", "").Role("testRole").Show() - r.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = snowflake.FutureViewGrant("test_db", "PUBLIC").Role("testRole").Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = snowflake.FutureViewGrant("test_db", "").Role("testRole").Show() - r.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) -} - -func TestFutureExternalTableGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureExternalTableGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("SELECT", false) - r.Equal(`GRANT SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("SELECT") - r.Equal([]string{`REVOKE SELECT ON FUTURE EXTERNAL TABLES IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureExternalTableGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("SELECT", false) - b.Equal(`GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("SELECT") - b.Equal([]string{`REVOKE SELECT ON FUTURE EXTERNAL TABLES IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestFutureFileFormatGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureFileFormatGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUTURE FILE FORMATS IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUTURE FILE FORMATS IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureFileFormatGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("USAGE", false) - b.Equal(`GRANT USAGE ON FUTURE FILE FORMATS IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("USAGE") - b.Equal([]string{`REVOKE USAGE ON FUTURE FILE FORMATS IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} - -func TestFutureTaskGrant(t *testing.T) { - r := require.New(t) - fvg := snowflake.FutureTaskGrant("test_db", "PUBLIC") - r.Equal("PUBLIC", fvg.Name()) - - s := fvg.Show() - r.Equal(`SHOW FUTURE GRANTS IN SCHEMA "test_db"."PUBLIC"`, s) - - s = fvg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUTURE TASKS IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke := fvg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUTURE TASKS IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - s = fvg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON FUTURE TASKS IN SCHEMA "test_db"."PUBLIC" TO ROLE "bob"`, s) - - revoke = fvg.Role("bob").RevokeOwnership("OWNERSHIP") - r.Equal([]string{`REVOKE OWNERSHIP ON FUTURE TASKS IN SCHEMA "test_db"."PUBLIC" FROM ROLE "bob"`}, revoke) - - b := require.New(t) - fvgd := snowflake.FutureTaskGrant("test_db", "") - b.Equal("test_db", fvgd.Name()) - - s = fvgd.Show() - b.Equal(`SHOW FUTURE GRANTS IN DATABASE "test_db"`, s) - - s = fvgd.Role("bob").Grant("USAGE", false) - b.Equal(`GRANT USAGE ON FUTURE TASKS IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").Revoke("USAGE") - b.Equal([]string{`REVOKE USAGE ON FUTURE TASKS IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) - - s = fvgd.Role("bob").Grant("OWNERSHIP", false) - b.Equal(`GRANT OWNERSHIP ON FUTURE TASKS IN DATABASE "test_db" TO ROLE "bob"`, s) - - revoke = fvgd.Role("bob").RevokeOwnership("OWNERSHIP") - b.Equal([]string{`REVOKE OWNERSHIP ON FUTURE TASKS IN DATABASE "test_db" FROM ROLE "bob"`}, revoke) -} diff --git a/pkg/snowflake/grant.go b/pkg/snowflake/grant.go deleted file mode 100644 index 92f4596d5d..0000000000 --- a/pkg/snowflake/grant.go +++ /dev/null @@ -1,405 +0,0 @@ -package snowflake - -import ( - "fmt" - "strings" -) - -type grantType string - -const ( - accountType grantType = "ACCOUNT" - - resourceMonitorType grantType = "RESOURCE MONITOR" - integrationType grantType = "INTEGRATION" - - databaseType grantType = "DATABASE" - schemaType grantType = "SCHEMA" - stageType grantType = "STAGE" - viewType grantType = "VIEW" - materializedViewType grantType = "MATERIALIZED VIEW" - tableType grantType = "TABLE" - warehouseType grantType = "WAREHOUSE" - externalTableType grantType = "EXTERNAL TABLE" - failoverGroupType grantType = "FAILOVER GROUP" - fileFormatType grantType = "FILE FORMAT" - functionType grantType = "FUNCTION" - procedureType grantType = "PROCEDURE" - sequenceType grantType = "SEQUENCE" - streamType grantType = "STREAM" - maskingPolicyType grantType = "MASKING POLICY" - pipeType grantType = "PIPE" - taskType grantType = "TASK" - rowAccessPolicyType grantType = "ROW ACCESS POLICY" - tagType grantType = "TAG" - userGrantType grantType = "USER" -) - -type GrantExecutable interface { - Grant(p string, w bool) string - Revoke(p string) []string - RevokeOwnership(r string) []string - Show() string -} - -type GrantBuilder interface { - Name() string - GrantType() string - Role(string) GrantExecutable - Share(string) GrantExecutable - Show() string -} - -// CurrentGrantBuilder abstracts the creation of GrantExecutables. -type CurrentGrantBuilder struct { - name string - qualifiedName string - grantType grantType -} - -// Name returns the object name for this CurrentGrantBuilder. -func (gb *CurrentGrantBuilder) Name() string { - return gb.name -} - -func (gb *CurrentGrantBuilder) GrantType() string { - return string(gb.grantType) -} - -// Show returns the SQL that will show all privileges on the grant. -func (gb *CurrentGrantBuilder) Show() string { - return fmt.Sprintf(`SHOW GRANTS ON %v %v`, gb.grantType, gb.qualifiedName) -} - -// ///////////////////////////////////////////// -// START CurrentMaterializedViewGrantBuilder // -// /////////////////////////////////////////////. -type CurrentMaterializedViewGrantBuilder struct { - name string - qualifiedName string - grantType grantType -} - -// Name returns the object name for this CurrentGrantBuilder. -func (gb *CurrentMaterializedViewGrantBuilder) Name() string { - return gb.name -} - -func (gb *CurrentMaterializedViewGrantBuilder) GrantType() string { - return string(gb.grantType) -} - -// Show returns the SQL that will show all privileges on the grant. -func (gb *CurrentMaterializedViewGrantBuilder) Show() string { - return fmt.Sprintf(`SHOW GRANTS ON %v %v`, gb.grantType, gb.qualifiedName) -} - -// Role returns a pointer to a CurrentGrantExecutable for a role. -func (gb *CurrentMaterializedViewGrantBuilder) Role(n string) GrantExecutable { - return &CurrentGrantExecutable{ - grantName: gb.qualifiedName, - grantType: viewType, - granteeName: n, - granteeType: roleType, - } -} - -// Share returns a pointer to a CurrentGrantExecutable for a share. -func (gb *CurrentMaterializedViewGrantBuilder) Share(n string) GrantExecutable { - return &CurrentGrantExecutable{ - grantName: gb.qualifiedName, - grantType: viewType, - granteeName: n, - granteeType: shareType, - } -} - -/////////////////////////////////////////////// -/// END CurrentMaterializedViewGrantBuilder /// -/////////////////////////////////////////////// - -// AccountGrant returns a pointer to a CurrentGrantBuilder for an account. -func AccountGrant() GrantBuilder { - return &CurrentGrantBuilder{ - grantType: accountType, - } -} - -// DatabaseGrant returns a pointer to a CurrentGrantBuilder for a database. -func DatabaseGrant(name string) GrantBuilder { - return &CurrentGrantBuilder{ - name: name, - qualifiedName: fmt.Sprintf(`"%v"`, name), - grantType: databaseType, - } -} - -// SchemaGrant returns a pointer to a CurrentGrantBuilder for a schema. -func SchemaGrant(db, schema string) GrantBuilder { - return &CurrentGrantBuilder{ - name: schema, - qualifiedName: fmt.Sprintf(`"%v"."%v"`, db, schema), - grantType: schemaType, - } -} - -// StageGrant returns a pointer to a CurrentGrantBuilder for a stage. -func StageGrant(db, schema, stage string) GrantBuilder { - return &CurrentGrantBuilder{ - name: stage, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, stage), - grantType: stageType, - } -} - -// ViewGrant returns a pointer to a CurrentGrantBuilder for a view. -func ViewGrant(db, schema, view string) GrantBuilder { - return &CurrentGrantBuilder{ - name: view, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, view), - grantType: viewType, - } -} - -// MaterializedViewGrant returns a pointer to a CurrentGrantBuilder for a materialized view. -func MaterializedViewGrant(db, schema, view string) GrantBuilder { - return &CurrentMaterializedViewGrantBuilder{ - name: view, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, view), - grantType: materializedViewType, - } -} - -// TableGrant returns a pointer to a CurrentGrantBuilder for a table. -func TableGrant(db, schema, table string) GrantBuilder { - return &CurrentGrantBuilder{ - name: table, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, table), - grantType: tableType, - } -} - -// ResourceMonitorGrant returns a pointer to a CurrentGrantBuilder for a resource monitor. -func ResourceMonitorGrant(w string) GrantBuilder { - return &CurrentGrantBuilder{ - name: w, - qualifiedName: fmt.Sprintf(`"%v"`, w), - grantType: resourceMonitorType, - } -} - -// IntegrationGrant returns a pointer to a CurrentGrantBuilder for an integration. -func IntegrationGrant(w string) GrantBuilder { - return &CurrentGrantBuilder{ - name: w, - qualifiedName: fmt.Sprintf(`"%v"`, w), - grantType: integrationType, - } -} - -// WarehouseGrant returns a pointer to a CurrentGrantBuilder for a warehouse. -func WarehouseGrant(w string) GrantBuilder { - return &CurrentGrantBuilder{ - name: w, - qualifiedName: fmt.Sprintf(`"%v"`, w), - grantType: warehouseType, - } -} - -// UserGrant returns a pointer to a CurrentGrantBuilder for a user. -func UserGrant(w string) GrantBuilder { - return &CurrentGrantBuilder{ - name: w, - qualifiedName: fmt.Sprintf(`"%v"`, w), - grantType: userGrantType, - } -} - -// ExternalTableGrant returns a pointer to a CurrentGrantBuilder for an external table. -func ExternalTableGrant(db, schema, externalTable string) GrantBuilder { - return &CurrentGrantBuilder{ - name: externalTable, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, externalTable), - grantType: externalTableType, - } -} - -// FailoverGroupGrant returns a pointer to a CurrentGrantBuilder for a failover group. -func FailoverGroupGrant(failoverGroup string) GrantBuilder { - return &CurrentGrantBuilder{ - name: failoverGroup, - qualifiedName: fmt.Sprintf(`"%v"`, failoverGroup), - grantType: failoverGroupType, - } -} - -// FileFormatGrant returns a pointer to a CurrentGrantBuilder for a file format. -func FileFormatGrant(db, schema, fileFormat string) GrantBuilder { - return &CurrentGrantBuilder{ - name: fileFormat, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, fileFormat), - grantType: fileFormatType, - } -} - -// FunctionGrant returns a pointer to a CurrentGrantBuilder for a view. -func FunctionGrant(db, schema, function string, argumentTypes []string) GrantBuilder { - return &CurrentGrantBuilder{ - name: function, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"(%v)`, db, schema, function, strings.Join(argumentTypes, ", ")), - grantType: functionType, - } -} - -// ProcedureGrant returns a pointer to a CurrentGrantBuilder for a procedure. -func ProcedureGrant(db, schema, procedure string, argumentTypes []string) GrantBuilder { - return &CurrentGrantBuilder{ - name: procedure, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"(%v)`, db, schema, procedure, strings.Join(argumentTypes, ", ")), - grantType: procedureType, - } -} - -// SequenceGrant returns a pointer to a CurrentGrantBuilder for a sequence. -func SequenceGrant(db, schema, sequence string) GrantBuilder { - return &CurrentGrantBuilder{ - name: sequence, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, sequence), - grantType: sequenceType, - } -} - -// StreamGrant returns a pointer to a CurrentGrantBuilder for a stream. -func StreamGrant(db, schema, stream string) GrantBuilder { - return &CurrentGrantBuilder{ - name: stream, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, stream), - grantType: streamType, - } -} - -// MaskingPolicyGrant returns a pointer to a CurrentGrantBuilder for a masking policy. -func MaskingPolicyGrant(db, schema, maskingPolicy string) GrantBuilder { - return &CurrentGrantBuilder{ - name: maskingPolicy, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, maskingPolicy), - grantType: maskingPolicyType, - } -} - -// PipeGrant returns a pointer to a CurrentGrantBuilder for a pipe. -func PipeGrant(db, schema, pipe string) GrantBuilder { - return &CurrentGrantBuilder{ - name: pipe, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, pipe), - grantType: pipeType, - } -} - -// TaskGrant returns a pointer to a CurrentGrantBuilder for a task. -func TaskGrant(db, schema, task string) GrantBuilder { - return &CurrentGrantBuilder{ - name: task, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, task), - grantType: taskType, - } -} - -// RowAccessPolicyGrant returns a pointer to a CurrentGrantBuilder for a masking policy. -func RowAccessPolicyGrant(db, schema, rowAccessPolicy string) GrantBuilder { - return &CurrentGrantBuilder{ - name: rowAccessPolicy, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, rowAccessPolicy), - grantType: rowAccessPolicyType, - } -} - -// TagGrant returns a pointer to a CurrentGrantBuilder for a tag grant. -func TagGrant(db, schema, tag string) GrantBuilder { - return &CurrentGrantBuilder{ - name: tag, - qualifiedName: fmt.Sprintf(`"%v"."%v"."%v"`, db, schema, tag), - grantType: tagType, - } -} - -type granteeType string - -const ( - roleType granteeType = "ROLE" - shareType granteeType = "SHARE" - userType granteeType = "USER" // user is only supported for RoleGrants. -) - -// CurrentGrantExecutable abstracts the creation of SQL queries to build grants for -// different resources. -type CurrentGrantExecutable struct { - grantName string - grantType grantType - granteeName string - granteeType granteeType -} - -// Role returns a pointer to a CurrentGrantExecutable for a role. -func (gb *CurrentGrantBuilder) Role(n string) GrantExecutable { - return &CurrentGrantExecutable{ - grantName: gb.qualifiedName, - grantType: gb.grantType, - granteeName: n, - granteeType: roleType, - } -} - -// Share returns a pointer to a CurrentGrantExecutable for a share. -func (gb *CurrentGrantBuilder) Share(n string) GrantExecutable { - return &CurrentGrantExecutable{ - grantName: gb.qualifiedName, - grantType: gb.grantType, - granteeName: n, - granteeType: shareType, - } -} - -// Grant returns the SQL that will grant privileges on the grant to the grantee. -func (ge *CurrentGrantExecutable) Grant(p string, w bool) string { - var template string - if p == `OWNERSHIP` { //nolint:gocritic // todo: please fix this - template = `GRANT %v ON %v %v TO %v "%v" COPY CURRENT GRANTS` - } else if w { - template = `GRANT %v ON %v %v TO %v "%v" WITH GRANT OPTION` - } else { - template = `GRANT %v ON %v %v TO %v "%v"` - } - return fmt.Sprintf(template, - p, ge.grantType, ge.grantName, ge.granteeType, ge.granteeName) -} - -// Revoke returns the SQL that will revoke privileges on the grant from the grantee. -func (ge *CurrentGrantExecutable) Revoke(p string) []string { - return []string{ - fmt.Sprintf(`REVOKE %v ON %v %v FROM %v "%v"`, - p, ge.grantType, ge.grantName, ge.granteeType, ge.granteeName), - } -} - -// Revoke returns the SQL that will revoke ownership privileges on the grant from the grantee. -// Since 10/2020 Snowflake dropped support for REVOKE OWNERSHIP. -// It's only possible to transfer it to another role now, so we grant it to role r. -func (ge *CurrentGrantExecutable) RevokeOwnership(r string) []string { - // early return in the event reversion owner is left blank (default) - // default to Terraform's role in this case - if r == "" { - return []string{ - "SET currentRole=CURRENT_ROLE()", - fmt.Sprintf(`GRANT OWNERSHIP ON %v %v TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`, ge.grantType, ge.grantName), - } - } - return []string{ - fmt.Sprintf(`GRANT OWNERSHIP ON %v %v TO ROLE "%v" COPY CURRENT GRANTS`, ge.grantType, ge.grantName, r), - } -} - -// Show returns the SQL that will show all grants of the grantee. -func (ge *CurrentGrantExecutable) Show() string { - return fmt.Sprintf(`SHOW GRANTS OF %v "%v"`, ge.granteeType, ge.granteeName) -} diff --git a/pkg/snowflake/grant_test.go b/pkg/snowflake/grant_test.go deleted file mode 100644 index e92ffe3e40..0000000000 --- a/pkg/snowflake/grant_test.go +++ /dev/null @@ -1,366 +0,0 @@ -package snowflake_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/stretchr/testify/require" -) - -func TestDatabaseGrant(t *testing.T) { - r := require.New(t) - dg := snowflake.DatabaseGrant("testDB") - r.Equal("testDB", dg.Name()) - - s := dg.Show() - r.Equal(`SHOW GRANTS ON DATABASE "testDB"`, s) - - s = dg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON DATABASE "testDB" TO ROLE "bob"`, s) - - revoke := dg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON DATABASE "testDB" FROM ROLE "bob"`}, revoke) - - s = dg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON DATABASE "testDB" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = dg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON DATABASE "testDB" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = dg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON DATABASE "testDB" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) - - s = dg.Share("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON DATABASE "testDB" TO SHARE "bob"`, s) - - revoke = dg.Share("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON DATABASE "testDB" FROM SHARE "bob"`}, revoke) -} - -func TestSchemaGrant(t *testing.T) { - r := require.New(t) - sg := snowflake.SchemaGrant("test_db", "testSchema") - r.Equal("testSchema", sg.Name()) - - s := sg.Show() - r.Equal(`SHOW GRANTS ON SCHEMA "test_db"."testSchema"`, s) - - s = sg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON SCHEMA "test_db"."testSchema" TO ROLE "bob"`, s) - - revoke := sg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON SCHEMA "test_db"."testSchema" FROM ROLE "bob"`}, revoke) - - s = sg.Share("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON SCHEMA "test_db"."testSchema" TO SHARE "bob"`, s) - - revoke = sg.Share("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON SCHEMA "test_db"."testSchema" FROM SHARE "bob"`}, revoke) - - s = sg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON SCHEMA "test_db"."testSchema" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = sg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON SCHEMA "test_db"."testSchema" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = sg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON SCHEMA "test_db"."testSchema" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestViewGrant(t *testing.T) { - r := require.New(t) - vg := snowflake.ViewGrant("test_db", "PUBLIC", "testView") - r.Equal("testView", vg.Name()) - - s := vg.Show() - r.Equal(`SHOW GRANTS ON VIEW "test_db"."PUBLIC"."testView"`, s) - - s = vg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON VIEW "test_db"."PUBLIC"."testView" TO ROLE "bob"`, s) - - revoke := vg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON VIEW "test_db"."PUBLIC"."testView" FROM ROLE "bob"`}, revoke) - - s = vg.Share("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON VIEW "test_db"."PUBLIC"."testView" TO SHARE "bob"`, s) - - revoke = vg.Share("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON VIEW "test_db"."PUBLIC"."testView" FROM SHARE "bob"`}, revoke) - - s = vg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON VIEW "test_db"."PUBLIC"."testView" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = vg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON VIEW "test_db"."PUBLIC"."testView" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = vg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON VIEW "test_db"."PUBLIC"."testView" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestMaterializedViewGrant(t *testing.T) { - r := require.New(t) - vg := snowflake.MaterializedViewGrant("test_db", "PUBLIC", "testMaterializedView") - r.Equal("testMaterializedView", vg.Name()) - - s := vg.Show() - r.Equal(`SHOW GRANTS ON MATERIALIZED VIEW "test_db"."PUBLIC"."testMaterializedView"`, s) - - s = vg.Role("bob").Grant("SELECT", false) - r.Equal(`GRANT SELECT ON VIEW "test_db"."PUBLIC"."testMaterializedView" TO ROLE "bob"`, s) - - revoke := vg.Role("bob").Revoke("SELECT") - r.Equal([]string{`REVOKE SELECT ON VIEW "test_db"."PUBLIC"."testMaterializedView" FROM ROLE "bob"`}, revoke) - - s = vg.Share("bob").Grant("SELECT", false) - r.Equal(`GRANT SELECT ON VIEW "test_db"."PUBLIC"."testMaterializedView" TO SHARE "bob"`, s) - - revoke = vg.Share("bob").Revoke("SELECT") - r.Equal([]string{`REVOKE SELECT ON VIEW "test_db"."PUBLIC"."testMaterializedView" FROM SHARE "bob"`}, revoke) - - s = vg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON VIEW "test_db"."PUBLIC"."testMaterializedView" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = vg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON VIEW "test_db"."PUBLIC"."testMaterializedView" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = vg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON VIEW "test_db"."PUBLIC"."testMaterializedView" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestExternalTableGrant(t *testing.T) { - r := require.New(t) - vg := snowflake.ExternalTableGrant("test_db", "PUBLIC", "testExternalTable") - r.Equal("testExternalTable", vg.Name()) - - s := vg.Show() - r.Equal(`SHOW GRANTS ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable"`, s) - - s = vg.Role("bob").Grant("SELECT", false) - r.Equal(`GRANT SELECT ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" TO ROLE "bob"`, s) - - revoke := vg.Role("bob").Revoke("SELECT") - r.Equal([]string{`REVOKE SELECT ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" FROM ROLE "bob"`}, revoke) - - s = vg.Share("bob").Grant("SELECT", false) - r.Equal(`GRANT SELECT ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" TO SHARE "bob"`, s) - - revoke = vg.Share("bob").Revoke("SELECT") - r.Equal([]string{`REVOKE SELECT ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" FROM SHARE "bob"`}, revoke) - - s = vg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = vg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = vg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON EXTERNAL TABLE "test_db"."PUBLIC"."testExternalTable" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestFileFormatGrant(t *testing.T) { - r := require.New(t) - vg := snowflake.FileFormatGrant("test_db", "PUBLIC", "testFileFormat") - r.Equal("testFileFormat", vg.Name()) - - s := vg.Show() - r.Equal(`SHOW GRANTS ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat"`, s) - - s = vg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" TO ROLE "bob"`, s) - - revoke := vg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" FROM ROLE "bob"`}, revoke) - - s = vg.Share("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" TO SHARE "bob"`, s) - - revoke = vg.Share("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" FROM SHARE "bob"`}, revoke) - - s = vg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = vg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = vg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON FILE FORMAT "test_db"."PUBLIC"."testFileFormat" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestFunctionGrant(t *testing.T) { - r := require.New(t) - vg := snowflake.FunctionGrant("test_db", "PUBLIC", "testFunction", []string{"ARRAY", "STRING"}) - r.Equal("testFunction", vg.Name()) - - s := vg.Show() - r.Equal(`SHOW GRANTS ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING)`, s) - - s = vg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) TO ROLE "bob"`, s) - - revoke := vg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) FROM ROLE "bob"`}, revoke) - - s = vg.Share("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) TO SHARE "bob"`, s) - - revoke = vg.Share("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) FROM SHARE "bob"`}, revoke) - - s = vg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = vg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = vg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON FUNCTION "test_db"."PUBLIC"."testFunction"(ARRAY, STRING) TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestProcedureGrant(t *testing.T) { - r := require.New(t) - vg := snowflake.ProcedureGrant("test_db", "PUBLIC", "testProcedure", []string{"ARRAY", "STRING"}) - r.Equal("testProcedure", vg.Name()) - - s := vg.Show() - r.Equal(`SHOW GRANTS ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING)`, s) - - s = vg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) TO ROLE "bob"`, s) - - revoke := vg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) FROM ROLE "bob"`}, revoke) - - s = vg.Share("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) TO SHARE "bob"`, s) - - revoke = vg.Share("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) FROM SHARE "bob"`}, revoke) - - s = vg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = vg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = vg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON PROCEDURE "test_db"."PUBLIC"."testProcedure"(ARRAY, STRING) TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestWarehouseGrant(t *testing.T) { - r := require.New(t) - wg := snowflake.WarehouseGrant("test_warehouse") - r.Equal("test_warehouse", wg.Name()) - - s := wg.Show() - r.Equal(`SHOW GRANTS ON WAREHOUSE "test_warehouse"`, s) - - s = wg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON WAREHOUSE "test_warehouse" TO ROLE "bob"`, s) - - revoke := wg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON WAREHOUSE "test_warehouse" FROM ROLE "bob"`}, revoke) - - s = wg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON WAREHOUSE "test_warehouse" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = wg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON WAREHOUSE "test_warehouse" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = wg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON WAREHOUSE "test_warehouse" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -// lintignore:AT003 -func TestAccountGrant(t *testing.T) { - r := require.New(t) - wg := snowflake.AccountGrant() - r.Equal("", wg.Name()) - - // There's an extra space after "ACCOUNT" - // because accounts don't have names - - s := wg.Show() - r.Equal("SHOW GRANTS ON ACCOUNT ", s) - - s = wg.Role("bob").Grant("MANAGE GRANTS", false) - r.Equal(`GRANT MANAGE GRANTS ON ACCOUNT TO ROLE "bob"`, s) - - revoke := wg.Role("bob").Revoke("MONITOR USAGE") - r.Equal([]string{`REVOKE MONITOR USAGE ON ACCOUNT FROM ROLE "bob"`}, revoke) - - s = wg.Role("bob").Grant("APPLY MASKING POLICY", false) - r.Equal(`GRANT APPLY MASKING POLICY ON ACCOUNT TO ROLE "bob"`, s) -} - -func TestIntegrationGrant(t *testing.T) { - r := require.New(t) - wg := snowflake.IntegrationGrant("test_integration") - r.Equal("test_integration", wg.Name()) - - s := wg.Show() - r.Equal(`SHOW GRANTS ON INTEGRATION "test_integration"`, s) - - s = wg.Role("bob").Grant("USAGE", false) - r.Equal(`GRANT USAGE ON INTEGRATION "test_integration" TO ROLE "bob"`, s) - - revoke := wg.Role("bob").Revoke("USAGE") - r.Equal([]string{`REVOKE USAGE ON INTEGRATION "test_integration" FROM ROLE "bob"`}, revoke) - - s = wg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON INTEGRATION "test_integration" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = wg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON INTEGRATION "test_integration" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = wg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON INTEGRATION "test_integration" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestResourceMonitorGrant(t *testing.T) { - r := require.New(t) - wg := snowflake.ResourceMonitorGrant("test_monitor") - r.Equal("test_monitor", wg.Name()) - - s := wg.Show() - r.Equal(`SHOW GRANTS ON RESOURCE MONITOR "test_monitor"`, s) - - s = wg.Role("bob").Grant("MONITOR", false) - r.Equal(`GRANT MONITOR ON RESOURCE MONITOR "test_monitor" TO ROLE "bob"`, s) - - revoke := wg.Role("bob").Revoke("MODIFY") - r.Equal([]string{`REVOKE MODIFY ON RESOURCE MONITOR "test_monitor" FROM ROLE "bob"`}, revoke) - - s = wg.Role("bob").Grant("OWNERSHIP", false) - r.Equal(`GRANT OWNERSHIP ON RESOURCE MONITOR "test_monitor" TO ROLE "bob" COPY CURRENT GRANTS`, s) - - revoke = wg.Role("bob").RevokeOwnership("revertBob") - r.Equal([]string{`GRANT OWNERSHIP ON RESOURCE MONITOR "test_monitor" TO ROLE "revertBob" COPY CURRENT GRANTS`}, revoke) - - revoke = wg.Role("bob").RevokeOwnership("") - r.Equal([]string{`SET currentRole=CURRENT_ROLE()`, `GRANT OWNERSHIP ON RESOURCE MONITOR "test_monitor" TO ROLE IDENTIFIER($currentRole) COPY CURRENT GRANTS`}, revoke) -} - -func TestMaskingPolicyGrant(t *testing.T) { - r := require.New(t) - mg := snowflake.MaskingPolicyGrant("test_db", "PUBLIC", "testMaskingPolicy") - r.Equal("testMaskingPolicy", mg.Name()) - - s := mg.Show() - r.Equal(`SHOW GRANTS ON MASKING POLICY "test_db"."PUBLIC"."testMaskingPolicy"`, s) - - s = mg.Role("bob").Grant("APPLY", false) - r.Equal(`GRANT APPLY ON MASKING POLICY "test_db"."PUBLIC"."testMaskingPolicy" TO ROLE "bob"`, s) - - revoke := mg.Role("bob").Revoke("APPLY") - r.Equal([]string{`REVOKE APPLY ON MASKING POLICY "test_db"."PUBLIC"."testMaskingPolicy" FROM ROLE "bob"`}, revoke) -} - -func TestShowGrantsOf(t *testing.T) { - r := require.New(t) - s := snowflake.ViewGrant("test_db", "PUBLIC", "testView").Role("testRole").Show() - r.Equal(`SHOW GRANTS OF ROLE "testRole"`, s) - - s = snowflake.ViewGrant("test_db", "PUBLIC", "testView").Share("testShare").Show() - r.Equal(`SHOW GRANTS OF SHARE "testShare"`, s) -} diff --git a/pkg/snowflake/role.go b/pkg/snowflake/role.go deleted file mode 100644 index 9d465886a7..0000000000 --- a/pkg/snowflake/role.go +++ /dev/null @@ -1,128 +0,0 @@ -package snowflake - -import ( - "database/sql" - "errors" - "fmt" - "log" - "strings" - - "github.com/jmoiron/sqlx" -) - -func NewRoleBuilder(db *sql.DB, name string) *RoleBuilder { - return &RoleBuilder{ - db: db, - name: name, - } -} - -type RoleBuilder struct { - name string - comment string - tags []TagValue - db *sql.DB -} - -func (b *RoleBuilder) WithName(name string) *RoleBuilder { - b.name = name - return b -} - -func (b *RoleBuilder) WithComment(comment string) *RoleBuilder { - b.comment = comment - return b -} - -func (b *RoleBuilder) Create() error { - q := strings.Builder{} - q.WriteString(fmt.Sprintf(`CREATE ROLE "%v"`, b.name)) - if b.comment != "" { - q.WriteString(fmt.Sprintf(" COMMENT = '%v'", b.comment)) - } - if len(b.tags) > 0 { - q.WriteString(" TAG (") - for i, tag := range b.tags { - q.WriteString(fmt.Sprintf(`"%v"."%v"."%v" = "%v"`, tag.Database, tag.Schema, tag.Name, tag.Value)) - if i < len(b.tags)-1 { - q.WriteString(", ") - } - } - q.WriteString(")") - } - _, err := b.db.Exec(q.String()) - return err -} - -func (b *RoleBuilder) SetComment(comment string) error { - q := fmt.Sprintf(`ALTER ROLE "%s" SET COMMENT = '%v'`, b.name, comment) - _, err := b.db.Exec(q) - return err -} - -func (b *RoleBuilder) UnsetComment() error { - q := fmt.Sprintf(`ALTER ROLE "%v" UNSET COMMENT`, b.name) - _, err := b.db.Exec(q) - return err -} - -func (b *RoleBuilder) UnsetTag(tag TagValue) error { - q := fmt.Sprintf(`ALTER ROLE %s UNSET TAG "%v"."%v"."%v"`, b.name, tag.Database, tag.Schema, tag.Name) - _, err := b.db.Exec(q) - return err -} - -func (b *RoleBuilder) SetTag(tag TagValue) error { - q := fmt.Sprintf(`ALTER ROLE %s SET TAG "%v"."%v"."%v" = "%v"`, b.name, tag.Database, tag.Schema, tag.Name, tag.Value) - _, err := b.db.Exec(q) - return err -} - -func (b *RoleBuilder) Drop() error { - q := fmt.Sprintf(`DROP ROLE "%s"`, b.name) - _, err := b.db.Exec(q) - return err -} - -func (b *RoleBuilder) Show() (*Role, error) { - stmt := fmt.Sprintf(`SHOW ROLES LIKE '%s'`, b.name) - row := QueryRow(b.db, stmt) - r := &Role{} - err := row.StructScan(r) - return r, err -} - -func (b *RoleBuilder) Rename(newName string) error { - stmt := fmt.Sprintf(`ALTER ROLE "%s" RENAME TO "%s"`, b.name, newName) - _, err := b.db.Exec(stmt) - return err -} - -type Role struct { - Name sql.NullString `db:"name"` - Comment sql.NullString `db:"comment"` - Owner sql.NullString `db:"owner"` -} - -func ListRoles(db *sql.DB, rolePattern string) ([]*Role, error) { - stmt := strings.Builder{} - stmt.WriteString("SHOW ROLES") - if rolePattern != "" { - stmt.WriteString(fmt.Sprintf(` LIKE '%v'`, rolePattern)) - } - rows, err := Query(db, stmt.String()) - if err != nil { - return nil, err - } - defer rows.Close() - - roles := []*Role{} - if err := sqlx.StructScan(rows, &roles); err != nil { - if errors.Is(err, sql.ErrNoRows) { - log.Println("[DEBUG] no roles found") - return nil, nil - } - return nil, fmt.Errorf("failed to scan stmt = %v err = %w", stmt, err) - } - return roles, nil -} diff --git a/pkg/snowflake/role_grant.go b/pkg/snowflake/role_grant.go deleted file mode 100644 index 375443f6d3..0000000000 --- a/pkg/snowflake/role_grant.go +++ /dev/null @@ -1,41 +0,0 @@ -package snowflake - -import "fmt" - -type RoleGrantBuilder struct { - name string -} - -type RoleGrantExecutable struct { - name string - granteeType granteeType - grantee string -} - -func RoleGrant(name string) *RoleGrantBuilder { - return &RoleGrantBuilder{name: name} -} - -func (gb *RoleGrantBuilder) User(user string) *RoleGrantExecutable { - return &RoleGrantExecutable{ - name: gb.name, - granteeType: userType, - grantee: user, - } -} - -func (gb *RoleGrantBuilder) Role(role string) *RoleGrantExecutable { - return &RoleGrantExecutable{ - name: gb.name, - granteeType: roleType, - grantee: role, - } -} - -func (gr *RoleGrantExecutable) Grant() string { - return fmt.Sprintf(`GRANT ROLE "%s" TO %s "%s"`, gr.name, gr.granteeType, gr.grantee) // nolint: gosec -} - -func (gr *RoleGrantExecutable) Revoke() string { - return fmt.Sprintf(`REVOKE ROLE "%s" FROM %s "%s"`, gr.name, gr.granteeType, gr.grantee) // nolint: gosec -} diff --git a/pkg/snowflake/role_grant_test.go b/pkg/snowflake/role_grant_test.go deleted file mode 100644 index 4488ff1c9c..0000000000 --- a/pkg/snowflake/role_grant_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package snowflake_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/stretchr/testify/require" -) - -func TestRoleGrant(t *testing.T) { - r := require.New(t) - rg := snowflake.RoleGrant("role1") - - u := rg.User("user1").Grant() - r.Equal(`GRANT ROLE "role1" TO USER "user1"`, u) - - role := rg.Role("role2").Grant() - r.Equal(`GRANT ROLE "role1" TO ROLE "role2"`, role) - - u2 := rg.User("user1").Revoke() - r.Equal(`REVOKE ROLE "role1" FROM USER "user1"`, u2) - - r2 := rg.Role("role2").Revoke() - r.Equal(`REVOKE ROLE "role1" FROM ROLE "role2"`, r2) -} diff --git a/pkg/snowflake/role_ownership_grant.go b/pkg/snowflake/role_ownership_grant.go deleted file mode 100644 index 7679501b09..0000000000 --- a/pkg/snowflake/role_ownership_grant.go +++ /dev/null @@ -1,60 +0,0 @@ -package snowflake - -import ( - "database/sql" - "fmt" - - "github.com/jmoiron/sqlx" -) - -type RoleOwnershipGrantBuilder struct { - role string - currentGrants string -} - -type RoleOwnershipGrantExecutable struct { - role string - granteeType granteeType - grantee string - currentGrants string -} - -func NewRoleOwnershipGrantBuilder(role string, currentGrants string) *RoleOwnershipGrantBuilder { - return &RoleOwnershipGrantBuilder{role: role, currentGrants: currentGrants} -} - -func (gb *RoleOwnershipGrantBuilder) Role(role string) *RoleOwnershipGrantExecutable { - return &RoleOwnershipGrantExecutable{ - role: role, - granteeType: "ROLE", - grantee: gb.role, - currentGrants: gb.currentGrants, - } -} - -func (gr *RoleOwnershipGrantExecutable) Grant() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec -} - -func (gr *RoleOwnershipGrantExecutable) Revoke() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec -} - -type RoleOwnershipGrant struct { - CreatedOn sql.NullString `db:"created_on"` - Name sql.NullString `db:"name"` - IsDefault sql.NullString `db:"is_default"` - IsCurrent sql.NullString `db:"is_current"` - IsInherited sql.NullString `db:"is_inherited"` - AssignedToUsers sql.NullString `db:"assigned_to_users"` - GrantedToRoles sql.NullString `db:"granted_to_roles"` - GrantedRoles sql.NullString `db:"granted_roles"` - Owner sql.NullString `db:"owner"` - Comment sql.NullString `db:"comment"` -} - -func ScanRoleOwnershipGrant(row *sqlx.Row) (*RoleOwnershipGrant, error) { - rog := &RoleOwnershipGrant{} - err := row.StructScan(rog) - return rog, err -} diff --git a/pkg/snowflake/role_ownership_grant_test.go b/pkg/snowflake/role_ownership_grant_test.go deleted file mode 100644 index f932bfd4bd..0000000000 --- a/pkg/snowflake/role_ownership_grant_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package snowflake_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/stretchr/testify/require" -) - -func TestRoleOwnershipGrantQuery(t *testing.T) { - r := require.New(t) - copyBuilder := snowflake.NewRoleOwnershipGrantBuilder("role1", "COPY") - revokeBuilder := snowflake.NewRoleOwnershipGrantBuilder("role1", "REVOKE") - - g1 := copyBuilder.Role("role2").Grant() - r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "role2" COPY CURRENT GRANTS`, g1) - - r1 := copyBuilder.Role("ACCOUNTADMIN").Revoke() - r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`, r1) - - g2 := revokeBuilder.Role("role2").Grant() - r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "role2" REVOKE CURRENT GRANTS`, g2) - - r2 := revokeBuilder.Role("ACCOUNTADMIN").Revoke() - r.Equal(`GRANT OWNERSHIP ON ROLE "role1" TO ROLE "ACCOUNTADMIN" REVOKE CURRENT GRANTS`, r2) -} diff --git a/pkg/snowflake/user_ownership_grant.go b/pkg/snowflake/user_ownership_grant.go deleted file mode 100644 index 4e54a86562..0000000000 --- a/pkg/snowflake/user_ownership_grant.go +++ /dev/null @@ -1,76 +0,0 @@ -package snowflake - -import ( - "database/sql" - "fmt" - - "github.com/jmoiron/sqlx" -) - -type UserOwnershipGrantBuilder struct { - user string - currentGrants string -} - -type UserOwnershipGrantExecutable struct { - role string - granteeType granteeType - grantee string - currentGrants string -} - -func NewUserOwnershipGrantBuilder(user string, currentGrants string) *UserOwnershipGrantBuilder { - return &UserOwnershipGrantBuilder{user: user, currentGrants: currentGrants} -} - -func (gb *UserOwnershipGrantBuilder) Role(role string) *UserOwnershipGrantExecutable { - return &UserOwnershipGrantExecutable{ - role: role, - granteeType: "USER", - grantee: gb.user, - currentGrants: gb.currentGrants, - } -} - -func (gr *UserOwnershipGrantExecutable) Grant() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec -} - -func (gr *UserOwnershipGrantExecutable) Revoke() string { - return fmt.Sprintf(`GRANT OWNERSHIP ON %s "%s" TO ROLE "%s" %s CURRENT GRANTS`, gr.granteeType, gr.grantee, gr.role, gr.currentGrants) // nolint: gosec -} - -type UserOwnershipGrant struct { - Name sql.NullString `db:"name"` - CreatedOn sql.NullString `db:"created_on"` - LoginName sql.NullString `db:"login_name"` - DisplayName sql.NullString `db:"display_name"` - FirstName sql.NullString `db:"first_name"` - LastName sql.NullString `db:"last_name"` - Email sql.NullString `db:"email"` - MinsToUnlock sql.NullString `db:"mins_to_unlock"` - DaysToExpiry sql.NullString `db:"days_to_expiry"` - Comment sql.NullString `db:"comment"` - Disabled sql.NullString `db:"disabled"` - MustChangePassword sql.NullString `db:"must_change_password"` - SnowflakeLock sql.NullString `db:"snowflake_lock"` - DefaultWarehouse sql.NullString `db:"default_warehouse"` - DefaultNamespace sql.NullString `db:"default_namespace"` - DefaultRole sql.NullString `db:"default_role"` - DefaultSecondaryRoles sql.NullString `db:"default_secondary_roles"` - ExtAuthnDuo sql.NullString `db:"ext_authn_duo"` - ExtAuthnUID sql.NullString `db:"ext_authn_uid"` - MinsToBypassMFA sql.NullString `db:"mins_to_bypass_mfa"` - Owner sql.NullString `db:"owner"` - LastSuccessLogin sql.NullString `db:"last_success_login"` - ExpiresAtTime sql.NullString `db:"expires_at_time"` - LockedUntilTime sql.NullString `db:"locked_until_time"` - HasPassword sql.NullString `db:"has_password"` - HasRsaPublicKey sql.NullString `db:"has_rsa_public_key"` -} - -func ScanUserOwnershipGrant(row *sqlx.Row) (*UserOwnershipGrant, error) { - uog := &UserOwnershipGrant{} - err := row.StructScan(uog) - return uog, err -} diff --git a/pkg/snowflake/user_ownership_grant_test.go b/pkg/snowflake/user_ownership_grant_test.go deleted file mode 100644 index 3750d45c6d..0000000000 --- a/pkg/snowflake/user_ownership_grant_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package snowflake_test - -import ( - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" - "github.com/stretchr/testify/require" -) - -func TestUserOwnershipGrantQuery(t *testing.T) { - r := require.New(t) - copyBuilder := snowflake.NewUserOwnershipGrantBuilder("user1", "COPY") - revokeBuilder := snowflake.NewUserOwnershipGrantBuilder("user1", "REVOKE") - - g1 := copyBuilder.Role("role1").Grant() - r.Equal(`GRANT OWNERSHIP ON USER "user1" TO ROLE "role1" COPY CURRENT GRANTS`, g1) - - r1 := copyBuilder.Role("ACCOUNTADMIN").Revoke() - r.Equal(`GRANT OWNERSHIP ON USER "user1" TO ROLE "ACCOUNTADMIN" COPY CURRENT GRANTS`, r1) - - g2 := revokeBuilder.Role("role1").Grant() - r.Equal(`GRANT OWNERSHIP ON USER "user1" TO ROLE "role1" REVOKE CURRENT GRANTS`, g2) - - r2 := revokeBuilder.Role("ACCOUNTADMIN").Revoke() - r.Equal(`GRANT OWNERSHIP ON USER "user1" TO ROLE "ACCOUNTADMIN" REVOKE CURRENT GRANTS`, r2) -} From ba16c65dc8f5f5a2682b118bce72febfca1d01ae Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 13:38:18 +0200 Subject: [PATCH 06/10] Add note in the migration guide --- MIGRATION_GUIDE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 0326d84de8..37a152c3d9 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -5,6 +5,9 @@ describe deprecations or breaking changes and help you to change your configurat across different versions. ## v0.92.0 ➞ v0.93.0 +### old grant resources removal +Following the [announcement](https://github.com/Snowflake-Labs/terraform-provider-snowflake/discussions/2736) we have removed the old grant resources. The two resources [snowflake_role_ownership_grant](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/role_ownership_grant) and [snowflake_user_ownership_grant](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/user_ownership_grant) were not listed in the announcement, but they were also marked as deprecated ones. We are removing them too to conclude the grants redesign saga. + ### snowflake_scim_integration resource changes #### *(behavior change)* Renamed fields From 8bd225a15fd84280221197096112c56c6d627545 Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 14:55:09 +0200 Subject: [PATCH 07/10] Add new account identifier validator --- pkg/helpers/helpers.go | 53 +++++-------- pkg/helpers/helpers_test.go | 42 +++++++++- pkg/helpers/identifier_string_parser.go | 24 ++++++ pkg/helpers/identifier_string_parser_test.go | 83 ++++++++++++++++++++ pkg/resources/validators.go | 38 +++++++++ pkg/resources/validators_test.go | 48 +++++++++++ 6 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 pkg/helpers/identifier_string_parser.go create mode 100644 pkg/helpers/identifier_string_parser_test.go diff --git a/pkg/helpers/helpers.go b/pkg/helpers/helpers.go index d5a04ac4ba..8bc8d2cc18 100644 --- a/pkg/helpers/helpers.go +++ b/pkg/helpers/helpers.go @@ -1,7 +1,6 @@ package helpers import ( - "encoding/csv" "fmt" "log" "reflect" @@ -14,38 +13,15 @@ import ( ) const ( - IDDelimiter = "|" - ParameterIDDelimiter = '.' + IDDelimiter = "|" ) -// ToDo: We can merge these two functions together and also add more functions here with similar functionality - -// This function converts list of string into snowflake formated string like 'ele1', 'ele2'. -func ListToSnowflakeString(list []string) string { - for index, element := range list { - list[index] = fmt.Sprintf(`'%v'`, strings.ReplaceAll(element, "'", "\\'")) - } - - return fmt.Sprintf("%v", strings.Join(list, ", ")) -} - // ListContentToString strips list elements of double quotes or brackets. func ListContentToString(listString string) string { re := regexp.MustCompile(`[\"\[\]]`) return re.ReplaceAllString(listString, "") } -// StringListToList splits a string into a slice of strings, separated by a separator. It also removes empty strings and trims whitespace. -func StringListToList(s string) []string { - var v []string - for _, elem := range strings.Split(s, ",") { - if strings.TrimSpace(elem) != "" { - v = append(v, strings.TrimSpace(elem)) - } - } - return v -} - // StringToBool converts a string to a bool. func StringToBool(s string) bool { return strings.ToLower(s) == "true" @@ -128,16 +104,10 @@ func DecodeSnowflakeID(id string) sdk.ObjectIdentifier { // The following configuration { "some_identifier": "db.name" } will be parsed as an object called "name" that lives // inside database called "db", not a database called "db.name". In this case quotes should be used. func DecodeSnowflakeParameterID(identifier string) (sdk.ObjectIdentifier, error) { - reader := csv.NewReader(strings.NewReader(identifier)) - reader.Comma = ParameterIDDelimiter - lines, err := reader.ReadAll() + parts, err := ParseIdentifierString(identifier) if err != nil { - return nil, fmt.Errorf("unable to read identifier: %s, err = %w", identifier, err) - } - if len(lines) != 1 { - return nil, fmt.Errorf("incompatible identifier: %s", identifier) + return nil, err } - parts := lines[0] switch len(parts) { case 1: return sdk.NewAccountObjectIdentifier(parts[0]), nil @@ -152,6 +122,23 @@ func DecodeSnowflakeParameterID(identifier string) (sdk.ObjectIdentifier, error) } } +// DecodeSnowflakeAccountIdentifier decodes account identifier (usually passed as one of the parameter in tf configuration) into sdk.AccountIdentifier. +// Check more in https://docs.snowflake.com/en/sql-reference/sql/create-account#required-parameters. +func DecodeSnowflakeAccountIdentifier(identifier string) (sdk.AccountIdentifier, error) { + parts, err := ParseIdentifierString(identifier) + if err != nil { + return sdk.AccountIdentifier{}, err + } + switch len(parts) { + case 1: + return sdk.AccountIdentifier{}, fmt.Errorf("identifier: %s seems to be account locator and these are not allowed - please use ", identifier) + case 2: + return sdk.NewAccountIdentifier(parts[0], parts[1]), nil + default: + return sdk.AccountIdentifier{}, fmt.Errorf("unable to classify account identifier: %s", identifier) + } +} + func Retry(attempts int, sleepDuration time.Duration, f func() (error, bool)) error { for i := 0; i < attempts; i++ { err, done := f() diff --git a/pkg/helpers/helpers_test.go b/pkg/helpers/helpers_test.go index 7122c9962e..10bb3bd5b3 100644 --- a/pkg/helpers/helpers_test.go +++ b/pkg/helpers/helpers_test.go @@ -58,19 +58,19 @@ func TestDecodeSnowflakeParameterID(t *testing.T) { t.Run("identifier with too many parts", func(t *testing.T) { id := `this.identifier.is.too.long.to.be.decoded` _, err := DecodeSnowflakeParameterID(id) - require.Errorf(t, err, "unable to classify identifier: %s", id) + require.ErrorContains(t, err, fmt.Sprintf("unable to classify identifier: %s", id)) }) t.Run("incompatible empty identifier", func(t *testing.T) { id := "" _, err := DecodeSnowflakeParameterID(id) - require.Errorf(t, err, "incompatible identifier: %s", id) + require.ErrorContains(t, err, fmt.Sprintf("incompatible identifier: %s", id)) }) t.Run("incompatible multiline identifier", func(t *testing.T) { id := "db.\nname" _, err := DecodeSnowflakeParameterID(id) - require.Errorf(t, err, "incompatible identifier: %s", id) + require.ErrorContains(t, err, fmt.Sprintf("unable to read identifier: %s", id)) }) } @@ -185,3 +185,39 @@ func (i unsupportedObjectIdentifier) Name() string { func (i unsupportedObjectIdentifier) FullyQualifiedName() string { return "fully qualified name" } + +func Test_DecodeSnowflakeAccountIdentifier(t *testing.T) { + t.Run("decodes account identifier", func(t *testing.T) { + id, err := DecodeSnowflakeAccountIdentifier("abc.def") + + require.NoError(t, err) + require.Equal(t, sdk.NewAccountIdentifier("abc", "def"), id) + }) + + t.Run("does not accept account locator", func(t *testing.T) { + _, err := DecodeSnowflakeAccountIdentifier("ABC12345") + + require.ErrorContains(t, err, "identifier: ABC12345 seems to be account locator and these are not allowed - please use ") + }) + + t.Run("identifier with too many parts", func(t *testing.T) { + id := `this.identifier.is.too.long.to.be.decoded` + _, err := DecodeSnowflakeAccountIdentifier(id) + + require.ErrorContains(t, err, fmt.Sprintf("unable to classify account identifier: %s", id)) + }) + + t.Run("empty identifier", func(t *testing.T) { + id := "" + _, err := DecodeSnowflakeAccountIdentifier(id) + + require.ErrorContains(t, err, fmt.Sprintf("incompatible identifier: %s", id)) + }) + + t.Run("multiline identifier", func(t *testing.T) { + id := "db.\nname" + _, err := DecodeSnowflakeAccountIdentifier(id) + + require.ErrorContains(t, err, fmt.Sprintf("unable to read identifier: %s", id)) + }) +} diff --git a/pkg/helpers/identifier_string_parser.go b/pkg/helpers/identifier_string_parser.go new file mode 100644 index 0000000000..c9a2113b6a --- /dev/null +++ b/pkg/helpers/identifier_string_parser.go @@ -0,0 +1,24 @@ +package helpers + +import ( + "encoding/csv" + "fmt" + "strings" +) + +const ( + ParameterIDDelimiter = '.' +) + +func ParseIdentifierString(identifier string) ([]string, error) { + reader := csv.NewReader(strings.NewReader(identifier)) + reader.Comma = ParameterIDDelimiter + lines, err := reader.ReadAll() + if err != nil { + return nil, fmt.Errorf("unable to read identifier: %s, err = %w", identifier, err) + } + if len(lines) != 1 { + return nil, fmt.Errorf("incompatible identifier: %s", identifier) + } + return lines[0], nil +} diff --git a/pkg/helpers/identifier_string_parser_test.go b/pkg/helpers/identifier_string_parser_test.go new file mode 100644 index 0000000000..31a9d6c0ec --- /dev/null +++ b/pkg/helpers/identifier_string_parser_test.go @@ -0,0 +1,83 @@ +package helpers + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_ParseIdentifierString(t *testing.T) { + + containsAll := func(t *testing.T, parts, expectedParts []string) { + require.Len(t, parts, len(expectedParts)) + for _, part := range expectedParts { + require.Contains(t, parts, part) + } + } + + t.Run("returns read error", func(t *testing.T) { + input := `ab"c` + + _, err := ParseIdentifierString(input) + + require.ErrorContains(t, err, "unable to read identifier") + require.ErrorContains(t, err, `bare " in non-quoted-field`) + }) + + t.Run("returns error for empty input", func(t *testing.T) { + input := "" + + _, err := ParseIdentifierString(input) + + require.ErrorContains(t, err, "incompatible identifier") + }) + + t.Run("returns error for multiple lines", func(t *testing.T) { + input := "abc\ndef" + + _, err := ParseIdentifierString(input) + + require.ErrorContains(t, err, "incompatible identifier") + }) + + t.Run("returns parts correctly without quoting", func(t *testing.T) { + input := "abc.def" + expected := []string{"abc", "def"} + + parts, err := ParseIdentifierString(input) + + require.NoError(t, err) + containsAll(t, parts, expected) + }) + + t.Run("returns parts correctly with quoting", func(t *testing.T) { + input := `"abc"."def"` + expected := []string{"abc", "def"} + + parts, err := ParseIdentifierString(input) + + require.NoError(t, err) + containsAll(t, parts, expected) + }) + + t.Run("returns parts correctly with mixed quoting", func(t *testing.T) { + input := `"abc".def."ghi"` + expected := []string{"abc", "def", "ghi"} + + parts, err := ParseIdentifierString(input) + + require.NoError(t, err) + containsAll(t, parts, expected) + }) + + // Quote inside must have a preceding quote (https://docs.snowflake.com/en/sql-reference/identifiers-syntax). + t.Run("returns parts correctly with quote inside", func(t *testing.T) { + input := `"ab""c".def` + expected := []string{`ab"c`, "def"} + + parts, err := ParseIdentifierString(input) + + require.NoError(t, err) + containsAll(t, parts, expected) + }) +} diff --git a/pkg/resources/validators.go b/pkg/resources/validators.go index 51ebe489d8..d719de90de 100644 --- a/pkg/resources/validators.go +++ b/pkg/resources/validators.go @@ -117,6 +117,44 @@ func getExpectedIdentifierForm(id any) string { return "" } +// IsValidAccountIdentifier is a validator that can be used for validating account identifiers passed in resources and data sources. +// +// Provider supported both account locators and organization name + account name pairs. +// The account locators are deprecated, so this function accepts only the new format. +func IsValidAccountIdentifier() schema.SchemaValidateDiagFunc { + return func(value any, path cty.Path) diag.Diagnostics { + if _, ok := value.(string); !ok { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Invalid schema identifier type", + Detail: fmt.Sprintf("Expected schema string type, but got: %T. This is a provider error please file a report: https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/new/choose", value), + AttributePath: path, + }, + } + } + + stringValue := value.(string) + _, err := helpers.DecodeSnowflakeAccountIdentifier(stringValue) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Unable to parse the account identifier", + Detail: fmt.Sprintf( + "Unable to parse the account identifier: %s. Make sure you are using the correct form of the fully qualified account name: ..\nOriginal Error: %s", + stringValue, + err.Error(), + ), + AttributePath: path, + }, + } + } + + return nil + } +} + // 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/validators_test.go b/pkg/resources/validators_test.go index e59d62cf83..adb17f18b4 100644 --- a/pkg/resources/validators_test.go +++ b/pkg/resources/validators_test.go @@ -255,3 +255,51 @@ func Test_sdkValidation(t *testing.T) { assert.Contains(t, diag[0].Summary, fmt.Sprintf("invalid warehouse size: %s", invalid)) }) } + +func Test_IsValidAccountIdentifier(t *testing.T) { + testCases := []struct { + Name string + Value any + Error string + }{ + { + Name: "validation: invalid value type", + Value: 123, + Error: "Expected schema string type, but got: int", + }, + { + Name: "validation: account locator", + Value: "ABC12345", + Error: "Unable to parse the account identifier: ABC12345. Make sure you are using the correct form of the fully qualified account name: ..", + }, + { + Name: "validation: identifier too long", + Value: "a.b.c", + Error: "Unable to parse the account identifier: a.b.c. Make sure you are using the correct form of the fully qualified account name: ..", + }, + { + Name: "correct account object identifier", + Value: "a.b", + }, + { + Name: "correct account object identifier - quoted", + Value: `"a"."b"`, + }, + { + Name: "correct account object identifier - mixed quotes", + Value: `a."b"`, + }, + } + + for _, tt := range testCases { + t.Run(tt.Name, func(t *testing.T) { + diag := IsValidAccountIdentifier()(tt.Value, cty.IndexStringPath("path")) + if tt.Error != "" { + assert.Len(t, diag, 1) + assert.Contains(t, diag[0].Detail, tt.Error) + } else { + assert.Len(t, diag, 0) + } + }) + } +} From ad6036147301f29d228c1ded618b74401d753cfc Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 15:13:29 +0200 Subject: [PATCH 08/10] Use validators --- pkg/helpers/identifier_string_parser_test.go | 2 +- pkg/resources/account.go | 1 + pkg/resources/share.go | 5 ++- pkg/resources/share_acceptance_test.go | 32 +++++++++++++++--- pkg/validation/validation.go | 35 -------------------- pkg/validation/validation_test.go | 31 ----------------- 6 files changed, 32 insertions(+), 74 deletions(-) delete mode 100644 pkg/validation/validation_test.go diff --git a/pkg/helpers/identifier_string_parser_test.go b/pkg/helpers/identifier_string_parser_test.go index 31a9d6c0ec..4b68a73ac1 100644 --- a/pkg/helpers/identifier_string_parser_test.go +++ b/pkg/helpers/identifier_string_parser_test.go @@ -7,8 +7,8 @@ import ( ) func Test_ParseIdentifierString(t *testing.T) { - containsAll := func(t *testing.T, parts, expectedParts []string) { + t.Helper() require.Len(t, parts, len(expectedParts)) for _, part := range expectedParts { require.Contains(t, parts, part) diff --git a/pkg/resources/account.go b/pkg/resources/account.go index 643d983709..ac156df9fc 100644 --- a/pkg/resources/account.go +++ b/pkg/resources/account.go @@ -26,6 +26,7 @@ var accountSchema = map[string]*schema.Schema{ StateFunc: func(val interface{}) string { return strings.ToUpper(val.(string)) }, + ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), }, "admin_name": { Type: schema.TypeString, diff --git a/pkg/resources/share.go b/pkg/resources/share.go index a1f13c2f4d..f0fbcf8c3a 100644 --- a/pkg/resources/share.go +++ b/pkg/resources/share.go @@ -10,7 +10,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -30,8 +29,8 @@ var shareSchema = map[string]*schema.Schema{ // Changed from Set to List to use DiffSuppressFunc: https://github.com/hashicorp/terraform-plugin-sdk/issues/160 Type: schema.TypeList, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.ValidateIsNotAccountLocator, + Type: schema.TypeString, + ValidateDiagFunc: IsValidAccountIdentifier(), }, Optional: true, Description: "A list of accounts to be added to the share. Values should not be the account locator, but " + diff --git a/pkg/resources/share_acceptance_test.go b/pkg/resources/share_acceptance_test.go index 51983bb51f..7af1a7d3e7 100644 --- a/pkg/resources/share_acceptance_test.go +++ b/pkg/resources/share_acceptance_test.go @@ -2,6 +2,7 @@ package resources_test import ( "fmt" + "regexp" "testing" acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" @@ -67,6 +68,29 @@ func TestAcc_Share(t *testing.T) { }) } +func TestAcc_Share_validateAccounts(t *testing.T) { + name := acc.TestClient().Ids.Alpha() + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.Share), + Steps: []resource.TestStep{ + { + Config: shareConfigOneAccount(name, "any comment", "incorrect"), + ExpectError: regexp.MustCompile("Unable to parse the account identifier"), + }, + { + Config: shareConfigTwoAccounts(name, "any comment", "correct.one", "incorrect"), + ExpectError: regexp.MustCompile("Unable to parse the account identifier"), + }, + }, + }) +} + func shareConfig(name string, comment string) string { return fmt.Sprintf(` resource "snowflake_share" "test" { @@ -76,22 +100,22 @@ resource "snowflake_share" "test" { `, name, comment) } -func shareConfigOneAccount(name string, comment string, account2 string) string { +func shareConfigOneAccount(name string, comment string, account string) string { return fmt.Sprintf(` resource "snowflake_share" "test" { name = "%v" comment = "%v" accounts = ["%v"] } -`, name, comment, account2) +`, name, comment, account) } -func shareConfigTwoAccounts(name string, comment string, account2 string, account3 string) string { +func shareConfigTwoAccounts(name string, comment string, account string, account2 string) string { return fmt.Sprintf(` resource "snowflake_share" "test" { name = "%v" comment = "%v" accounts = ["%v", "%v"] } -`, name, comment, account2, account3) +`, name, comment, account, account2) } diff --git a/pkg/validation/validation.go b/pkg/validation/validation.go index 81b9f8a183..ac0cef0fa3 100644 --- a/pkg/validation/validation.go +++ b/pkg/validation/validation.go @@ -3,43 +3,8 @@ package validation import ( "fmt" "strings" - "unicode" ) -// ValidateIsNotAccountLocator validates that the account value is not an account locator. Account locators have the -// following format: 8 characters where the first 3 characters are letters and the last 5 are digits. ex: ABC12345 -// The desired format should be 'organization_name.account_name' ex: testOrgName.testAccName. -func ValidateIsNotAccountLocator(i interface{}, k string) (s []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) - return - } - if !strings.Contains(v, ".") { - errors = append(errors, fmt.Errorf("account locators are not allowed - please use 'organization_name.account_name")) - return - } - if len(v) == 8 { - isAccountLocator := true - firstHalf := v[0:3] - for _, r := range firstHalf { - if !unicode.IsLetter(r) { - isAccountLocator = false - } - } - secondHalf := v[3:] - for _, r := range secondHalf { - if !unicode.IsDigit(r) { - isAccountLocator = false - } - } - if isAccountLocator { - errors = append(errors, fmt.Errorf("account locators are not allowed - please use 'organization_name.account_name")) - } - } - return -} - func FormatFullyQualifiedObjectID(dbName, schemaName, objectName string) string { var n strings.Builder diff --git a/pkg/validation/validation_test.go b/pkg/validation/validation_test.go deleted file mode 100644 index e9f8815a51..0000000000 --- a/pkg/validation/validation_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package validation - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -var validAccounts = []string{ - "testOrg.testAcc", - "testingOrg2.testingAcc2", - "abc.12345", -} - -var invalidAccounts = []interface{}{ - "abc12345", - "xyz56789", -} - -func TestValidateIsNotAccountLocator(t *testing.T) { - r := require.New(t) - for _, p := range validAccounts { - _, errs := ValidateIsNotAccountLocator(p, "test_valid_accounts") - r.Len(errs, 0, "account locators are not allowed - please use 'organization_name.account_name]", p, errs) - } - - for _, p := range invalidAccounts { - _, errs := ValidateIsNotAccountLocator(p, "test_invalid_accounts") - r.NotZero(len(errs), "account locators are not allowed - please use 'organization_name.account_name]", p, errs) - } -} From 18008e631808322ff66e6ac5f32c9fea1a4eccfd Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 16:14:06 +0200 Subject: [PATCH 09/10] Fix after review --- .../deprecated_identifier_helpers.go} | 4 +++- pkg/resources/object_parameter.go | 5 ++--- pkg/resources/tag_association.go | 3 +-- pkg/resources/view_acceptance_test.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename pkg/{validation/validation.go => resources/deprecated_identifier_helpers.go} (90%) diff --git a/pkg/validation/validation.go b/pkg/resources/deprecated_identifier_helpers.go similarity index 90% rename from pkg/validation/validation.go rename to pkg/resources/deprecated_identifier_helpers.go index ac0cef0fa3..c8b61236b1 100644 --- a/pkg/validation/validation.go +++ b/pkg/resources/deprecated_identifier_helpers.go @@ -1,10 +1,11 @@ -package validation +package resources import ( "fmt" "strings" ) +// TODO [SNOW-999049]: replace during identifiers rework func FormatFullyQualifiedObjectID(dbName, schemaName, objectName string) string { var n strings.Builder @@ -39,6 +40,7 @@ func FormatFullyQualifiedObjectID(dbName, schemaName, objectName string) string return n.String() } +// TODO [SNOW-999049]: replace during identifiers rework func ParseFullyQualifiedObjectID(s string) (dbName, schemaName, objectName string) { parsedString := strings.ReplaceAll(s, "\"", "") diff --git a/pkg/resources/object_parameter.go b/pkg/resources/object_parameter.go index f4870dcd43..ab5dbc0ecc 100644 --- a/pkg/resources/object_parameter.go +++ b/pkg/resources/object_parameter.go @@ -8,7 +8,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - snowflakeValidation "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/validation" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -93,7 +92,7 @@ func CreateObjectParameter(d *schema.ResourceData, meta interface{}) error { o := sdk.Object{} if v, ok := d.GetOk("object_identifier"); ok { objectDatabase, objectSchema, objectName := expandObjectIdentifier(v.([]interface{})) - fullyQualifierObjectIdentifier := snowflakeValidation.FormatFullyQualifiedObjectID(objectDatabase, objectSchema, objectName) + fullyQualifierObjectIdentifier := FormatFullyQualifiedObjectID(objectDatabase, objectSchema, objectName) fullyQualifierObjectIdentifier = strings.Trim(fullyQualifierObjectIdentifier, "\"") o.Name = sdk.NewObjectIdentifierFromFullyQualifiedName(fullyQualifierObjectIdentifier) o.ObjectType = sdk.ObjectType(d.Get("object_type").(string)) @@ -197,7 +196,7 @@ func DeleteObjectParameter(d *schema.ResourceData, meta interface{}) error { } else { v := d.Get("object_identifier") objectDatabase, objectSchema, objectName := expandObjectIdentifier(v.([]interface{})) - fullyQualifierObjectIdentifier := snowflakeValidation.FormatFullyQualifiedObjectID(objectDatabase, objectSchema, objectName) + fullyQualifierObjectIdentifier := FormatFullyQualifiedObjectID(objectDatabase, objectSchema, objectName) fullyQualifierObjectIdentifier = strings.Trim(fullyQualifierObjectIdentifier, "\"") o := sdk.Object{ ObjectType: sdk.ObjectType(d.Get("object_type").(string)), diff --git a/pkg/resources/tag_association.go b/pkg/resources/tag_association.go index b8a0cb8271..629aa234f9 100644 --- a/pkg/resources/tag_association.go +++ b/pkg/resources/tag_association.go @@ -16,7 +16,6 @@ import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - snowflakeValidation "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/validation" ) var tagAssociationSchema = map[string]*schema.Schema{ @@ -104,7 +103,7 @@ func TagIdentifierAndObjectIdentifier(d *schema.ResourceData) (sdk.SchemaObjectI tag := d.Get("tag_id").(string) objectType := sdk.ObjectType(d.Get("object_type").(string)) - tagDatabase, tagSchema, tagName := snowflakeValidation.ParseFullyQualifiedObjectID(tag) + tagDatabase, tagSchema, tagName := ParseFullyQualifiedObjectID(tag) tid := sdk.NewSchemaObjectIdentifier(tagDatabase, tagSchema, tagName) var identifiers []sdk.ObjectIdentifier diff --git a/pkg/resources/view_acceptance_test.go b/pkg/resources/view_acceptance_test.go index 6d6cd20003..3a28a4126b 100644 --- a/pkg/resources/view_acceptance_test.go +++ b/pkg/resources/view_acceptance_test.go @@ -460,7 +460,7 @@ func TestAcc_View_Issue2640(t *testing.T) { ResourceName: "snowflake_view.test", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"or_replace"}, + ImportStateVerifyIgnore: []string{"or_replace", "created_on"}, }, }, }) From 726f6c0d3487b1869453ee9f2dadb8865d6e97fb Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Fri, 21 Jun 2024 16:49:53 +0200 Subject: [PATCH 10/10] Fix after review 2 --- .../snowflake_role_ownership_grant/import.sh | 1 - .../resource.tf | 24 ------------------- pkg/helpers/helpers.go | 4 ++-- pkg/helpers/helpers_test.go | 2 +- pkg/helpers/identifier_string_parser_test.go | 11 +++++++++ pkg/resources/validators_test.go | 4 ++++ 6 files changed, 18 insertions(+), 28 deletions(-) delete mode 100644 examples/resources/snowflake_role_ownership_grant/import.sh delete mode 100644 examples/resources/snowflake_role_ownership_grant/resource.tf diff --git a/examples/resources/snowflake_role_ownership_grant/import.sh b/examples/resources/snowflake_role_ownership_grant/import.sh deleted file mode 100644 index 99492eac57..0000000000 --- a/examples/resources/snowflake_role_ownership_grant/import.sh +++ /dev/null @@ -1 +0,0 @@ -terraform import snowflake_role_ownership_grant.example "||" diff --git a/examples/resources/snowflake_role_ownership_grant/resource.tf b/examples/resources/snowflake_role_ownership_grant/resource.tf deleted file mode 100644 index c8de4c8e66..0000000000 --- a/examples/resources/snowflake_role_ownership_grant/resource.tf +++ /dev/null @@ -1,24 +0,0 @@ -resource "snowflake_role" "role" { - name = "rking_test_role" - comment = "for testing" -} - -resource "snowflake_role" "other_role" { - name = "rking_test_role2" -} - -# ensure the Terraform user inherits ownership privileges for the rking_test_role role -# otherwise Terraform will fail to destroy the rking_test_role2 role due to insufficient privileges -resource "snowflake_role_grants" "grants" { - role_name = snowflake_role.role.name - - roles = [ - "ACCOUNTADMIN", - ] -} - -resource "snowflake_role_ownership_grant" "grant" { - on_role_name = snowflake_role.role.name - to_role_name = snowflake_role.other_role.name - current_grants = "COPY" -} \ No newline at end of file diff --git a/pkg/helpers/helpers.go b/pkg/helpers/helpers.go index 8bc8d2cc18..69178128f1 100644 --- a/pkg/helpers/helpers.go +++ b/pkg/helpers/helpers.go @@ -131,11 +131,11 @@ func DecodeSnowflakeAccountIdentifier(identifier string) (sdk.AccountIdentifier, } switch len(parts) { case 1: - return sdk.AccountIdentifier{}, fmt.Errorf("identifier: %s seems to be account locator and these are not allowed - please use ", identifier) + return sdk.AccountIdentifier{}, fmt.Errorf("identifier: %s seems to be account locator and these are not allowed - please use .", identifier) case 2: return sdk.NewAccountIdentifier(parts[0], parts[1]), nil default: - return sdk.AccountIdentifier{}, fmt.Errorf("unable to classify account identifier: %s", identifier) + return sdk.AccountIdentifier{}, fmt.Errorf("unable to classify account identifier: %s, expected format: .", identifier) } } diff --git a/pkg/helpers/helpers_test.go b/pkg/helpers/helpers_test.go index 10bb3bd5b3..f6198b6fb6 100644 --- a/pkg/helpers/helpers_test.go +++ b/pkg/helpers/helpers_test.go @@ -197,7 +197,7 @@ func Test_DecodeSnowflakeAccountIdentifier(t *testing.T) { t.Run("does not accept account locator", func(t *testing.T) { _, err := DecodeSnowflakeAccountIdentifier("ABC12345") - require.ErrorContains(t, err, "identifier: ABC12345 seems to be account locator and these are not allowed - please use ") + require.ErrorContains(t, err, "identifier: ABC12345 seems to be account locator and these are not allowed - please use .") }) t.Run("identifier with too many parts", func(t *testing.T) { diff --git a/pkg/helpers/identifier_string_parser_test.go b/pkg/helpers/identifier_string_parser_test.go index 4b68a73ac1..1635808290 100644 --- a/pkg/helpers/identifier_string_parser_test.go +++ b/pkg/helpers/identifier_string_parser_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" ) +// TODO [SNOW-999049]: add more fancy cases func Test_ParseIdentifierString(t *testing.T) { containsAll := func(t *testing.T, parts, expectedParts []string) { t.Helper() @@ -80,4 +81,14 @@ func Test_ParseIdentifierString(t *testing.T) { require.NoError(t, err) containsAll(t, parts, expected) }) + + t.Run("returns parts correctly with dots inside", func(t *testing.T) { + input := `"ab.c".def` + expected := []string{`ab.c`, "def"} + + parts, err := ParseIdentifierString(input) + + require.NoError(t, err) + containsAll(t, parts, expected) + }) } diff --git a/pkg/resources/validators_test.go b/pkg/resources/validators_test.go index adb17f18b4..f10226e30d 100644 --- a/pkg/resources/validators_test.go +++ b/pkg/resources/validators_test.go @@ -289,6 +289,10 @@ func Test_IsValidAccountIdentifier(t *testing.T) { Name: "correct account object identifier - mixed quotes", Value: `a."b"`, }, + { + Name: "correct account object identifier - dot inside", + Value: `a."b.c"`, + }, } for _, tt := range testCases {