diff --git a/docs/resources/account_password_policy_attachment.md b/docs/resources/account_password_policy_attachment.md new file mode 100644 index 0000000000..864b2cad2b --- /dev/null +++ b/docs/resources/account_password_policy_attachment.md @@ -0,0 +1,38 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "snowflake_account_password_policy_attachment Resource - terraform-provider-snowflake" +subcategory: "" +description: |- + Specifies the password policy to use for the current account. To set the password policy of a different account, use a provider alias. +--- + +# snowflake_account_password_policy_attachment (Resource) + +Specifies the password policy to use for the current account. To set the password policy of a different account, use a provider alias. + +## Example Usage + +```terraform +resource "snowflake_password_policy" "default" { + database = "prod" + schema = "security" + name = "default_policy" +} + +resource "snowflake_account_password_policy_attachment" "attachment" { + password_policy = snowflake_password_policy.default.qualified_name +} +``` + + +## Schema + +### Required + +- `password_policy` (String) Qualified name (`"db"."schema"."policy_name"`) of the password policy to apply to the current account. + +### Read-Only + +- `id` (String) The ID of this resource. + + diff --git a/docs/resources/password_policy.md b/docs/resources/password_policy.md index 49a3c00e8a..3ee4cdaa8c 100644 --- a/docs/resources/password_policy.md +++ b/docs/resources/password_policy.md @@ -39,5 +39,6 @@ A password policy specifies the requirements that must be met to create and rese ### Read-Only - `id` (String) The ID of this resource. +- `qualified_name` (String) The qualified name for the password policy. diff --git a/examples/resources/snowflake_account_password_policy_attachment/resource.tf b/examples/resources/snowflake_account_password_policy_attachment/resource.tf new file mode 100644 index 0000000000..ed7ed7a5ab --- /dev/null +++ b/examples/resources/snowflake_account_password_policy_attachment/resource.tf @@ -0,0 +1,9 @@ +resource "snowflake_password_policy" "default" { + database = "prod" + schema = "security" + name = "default_policy" +} + +resource "snowflake_account_password_policy_attachment" "attachment" { + password_policy = snowflake_password_policy.default.qualified_name +} diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 4bc8571f90..4edcda64e0 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -225,6 +225,7 @@ func getResources() map[string]*schema.Resource { // NOTE(): do not add grant resources here others := map[string]*schema.Resource{ "snowflake_account": resources.Account(), + "snowflake_account_password_policy_attachment": resources.AccountPasswordPolicyAttachment(), "snowflake_account_parameter": resources.AccountParameter(), "snowflake_alert": resources.Alert(), "snowflake_api_integration": resources.APIIntegration(), diff --git a/pkg/resources/account_password_policy_attachment.go b/pkg/resources/account_password_policy_attachment.go new file mode 100644 index 0000000000..594790a59e --- /dev/null +++ b/pkg/resources/account_password_policy_attachment.go @@ -0,0 +1,89 @@ +package resources + +import ( + "context" + "database/sql" + "fmt" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var accountPasswordPolicyAttachmentSchema = map[string]*schema.Schema{ + "password_policy": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Qualified name (`\"db\".\"schema\".\"policy_name\"`) of the password policy to apply to the current account.", + }, +} + +// AccountPasswordPolicyAttachment returns a pointer to the resource representing an api integration. +func AccountPasswordPolicyAttachment() *schema.Resource { + return &schema.Resource{ + Description: "Specifies the password policy to use for the current account. To set the password policy of a different account, use a provider alias.", + + Create: CreateAccountPasswordPolicyAttachment, + Read: ReadAccountPasswordPolicyAttachment, + Delete: DeleteAccountPasswordPolicyAttachment, + + Schema: accountPasswordPolicyAttachmentSchema, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + } +} + +// CreateAccountPasswordPolicyAttachment implements schema.CreateFunc. +func CreateAccountPasswordPolicyAttachment(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + ctx := context.Background() + + passwordPolicy, ok := sdk.NewObjectIdentifierFromFullyQualifiedName(d.Get("password_policy").(string)).(sdk.SchemaObjectIdentifier) + if !ok { + return fmt.Errorf("password_policy %s is not a valid password policy qualified name, expected format: `\"db\".\"schema\".\"policy\"`", d.Get("password_policy")) + } + // passwordPolicy := sdk.NewAccountObjectIdentifier(d.Get("password_policy").(string)) + + err := client.Accounts.Alter(ctx, &sdk.AlterAccountOptions{ + Set: &sdk.AccountSet{ + PasswordPolicy: passwordPolicy, + }, + }) + if err != nil { + return err + } + + d.SetId(helpers.EncodeSnowflakeID(passwordPolicy)) + + return nil +} + +func ReadAccountPasswordPolicyAttachment(d *schema.ResourceData, meta interface{}) error { + passwordPolicy := helpers.DecodeSnowflakeID(d.Id()) + if err := d.Set("password_policy", passwordPolicy.FullyQualifiedName()); err != nil { + return err + } + + return nil +} + +// DeleteAccountPasswordPolicyAttachment implements schema.DeleteFunc. +func DeleteAccountPasswordPolicyAttachment(d *schema.ResourceData, meta interface{}) error { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + ctx := context.Background() + + err := client.Accounts.Alter(ctx, &sdk.AlterAccountOptions{ + Unset: &sdk.AccountUnset{ + PasswordPolicy: sdk.Bool(true), + }, + }) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/resources/account_password_policy_attachment_acceptance_test.go b/pkg/resources/account_password_policy_attachment_acceptance_test.go new file mode 100644 index 0000000000..a808ad6e1b --- /dev/null +++ b/pkg/resources/account_password_policy_attachment_acceptance_test.go @@ -0,0 +1,66 @@ +package resources_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAcc_AccountPasswordPolicyAttachment(t *testing.T) { + prefix := "tst-terraform" + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + + resource.ParallelTest(t, resource.TestCase{ + Providers: providers(), + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: accountPasswordPolicyAttachmentConfig(prefix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("snowflake_account_password_policy_attachment.att", "id"), + ), + }, + { + ResourceName: "snowflake_account_password_policy_attachment.att", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "initially_suspended", + "wait_for_provisioning", + "query_acceleration_max_scale_factor", + "max_concurrency_level", + "statement_queued_timeout_in_seconds", + "statement_timeout_in_seconds", + }, + }, + }, + }) +} + +func accountPasswordPolicyAttachmentConfig(prefix string) string { + s := ` +resource "snowflake_database" "test" { + name = "%v" + comment = "Terraform acceptance test" +} + +resource "snowflake_schema" "test" { + name = "%v" + database = snowflake_database.test.name + comment = "Terraform acceptance test" + } + +resource "snowflake_password_policy" "pa" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "%v" +} + +resource "snowflake_account_password_policy_attachment" "att" { + password_policy = snowflake_password_policy.pa.qualified_name +} +` + return fmt.Sprintf(s, prefix, prefix, prefix) +} diff --git a/pkg/resources/password_policy.go b/pkg/resources/password_policy.go index deb8b31de2..839944a5ca 100644 --- a/pkg/resources/password_policy.go +++ b/pkg/resources/password_policy.go @@ -116,6 +116,11 @@ var passwordPolicySchema = map[string]*schema.Schema{ Optional: true, Description: "Adds a comment or overwrites an existing comment for the password policy.", }, + "qualified_name": { + Type: schema.TypeString, + Computed: true, + Description: "The qualified name for the password policy.", + }, } func PasswordPolicy() *schema.Resource { @@ -175,6 +180,11 @@ func ReadPasswordPolicy(d *schema.ResourceData, meta interface{}) error { client := sdk.NewClientFromDB(db) ctx := context.Background() objectIdentifier := helpers.DecodeSnowflakeID(d.Id()).(sdk.SchemaObjectIdentifier) + + if err := d.Set("qualified_name", objectIdentifier.FullyQualifiedName()); err != nil { + return err + } + passwordPolicy, err := client.PasswordPolicies.ShowByID(ctx, objectIdentifier) if err != nil { return err