From 003a6f2f7e700cb1d3f601d5a7a41c791d756df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Thu, 25 Jan 2024 12:58:05 +0100 Subject: [PATCH] changes after review --- docs/data-sources/account_roles.md | 43 --- docs/resources/account_role.md | 57 ---- .../snowflake_account_roles/data-source.tf | 6 - .../snowflake_account_role/import.sh | 1 - .../snowflake_account_role/resource.tf | 4 - pkg/datasources/account_roles.go | 94 ------- .../account_roles_acceptance_test.go | 86 ------ pkg/datasources/role.go | 2 +- pkg/datasources/roles.go | 87 +++++- pkg/datasources/roles_acceptance_test.go | 80 ++++++ .../TestAcc_AccountRoles_basic/test.tf | 14 +- pkg/provider/provider.go | 2 - pkg/resources/account_role.go | 253 ------------------ pkg/resources/account_role_acceptance_test.go | 127 --------- pkg/resources/role.go | 233 +++++++++++++++- pkg/resources/role_acceptance_test.go | 116 ++++++++ .../TestAcc_AccountRole_basic/test.tf | 2 +- .../TestAcc_AccountRole_updates/test.tf | 2 +- 18 files changed, 518 insertions(+), 691 deletions(-) delete mode 100644 docs/data-sources/account_roles.md delete mode 100644 docs/resources/account_role.md delete mode 100644 examples/data-sources/snowflake_account_roles/data-source.tf delete mode 100644 examples/resources/snowflake_account_role/import.sh delete mode 100644 examples/resources/snowflake_account_role/resource.tf delete mode 100644 pkg/datasources/account_roles.go delete mode 100644 pkg/datasources/account_roles_acceptance_test.go delete mode 100644 pkg/resources/account_role.go delete mode 100644 pkg/resources/account_role_acceptance_test.go diff --git a/docs/data-sources/account_roles.md b/docs/data-sources/account_roles.md deleted file mode 100644 index 3eca8fb8cd..0000000000 --- a/docs/data-sources/account_roles.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -# generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "snowflake_account_roles Data Source - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_account_roles (Data Source) - - - -## Example Usage - -```terraform -data "snowflake_account_roles" "all" { -} - -data "snowflake_account_roles" "by_pattern" { - pattern = "some_prefix_%" -} -``` - - -## Schema - -### Optional - -- `pattern` (String) Filters the command output by object name. - -### Read-Only - -- `id` (String) The ID of this resource. -- `roles` (List of Object) List of all the roles which you can view across your entire account, including the system-defined roles and any custom roles that exist. (see [below for nested schema](#nestedatt--roles)) - - -### Nested Schema for `roles` - -Read-Only: - -- `comment` (String) -- `name` (String) -- `owner` (String) diff --git a/docs/resources/account_role.md b/docs/resources/account_role.md deleted file mode 100644 index 631a9e9b58..0000000000 --- a/docs/resources/account_role.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -# generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "snowflake_account_role Resource - terraform-provider-snowflake" -subcategory: "" -description: |- - ---- - -# snowflake_account_role (Resource) - - - -## Example Usage - -```terraform -resource "snowflake_account_role" "role" { - name = "role_name" - comment = "comment" -} -``` - - -## Schema - -### Required - -- `name` (String) - -### Optional - -- `comment` (String) -- `tag` (Block List, Deprecated) Definitions of a tag to associate with the resource. (see [below for nested schema](#nestedblock--tag)) - -### Read-Only - -- `id` (String) The ID of this resource. - - -### Nested Schema for `tag` - -Required: - -- `name` (String) Tag name, e.g. department. -- `value` (String) Tag value, e.g. marketing_info. - -Optional: - -- `database` (String) Name of the database that the tag was created in. -- `schema` (String) Name of the schema that the tag was created in. - -## Import - -Import is supported using the following syntax: - -```shell -terraform import snowflake_account_role.example roleName -``` diff --git a/examples/data-sources/snowflake_account_roles/data-source.tf b/examples/data-sources/snowflake_account_roles/data-source.tf deleted file mode 100644 index c5846c0fab..0000000000 --- a/examples/data-sources/snowflake_account_roles/data-source.tf +++ /dev/null @@ -1,6 +0,0 @@ -data "snowflake_account_roles" "all" { -} - -data "snowflake_account_roles" "by_pattern" { - pattern = "some_prefix_%" -} diff --git a/examples/resources/snowflake_account_role/import.sh b/examples/resources/snowflake_account_role/import.sh deleted file mode 100644 index 96c1cd4276..0000000000 --- a/examples/resources/snowflake_account_role/import.sh +++ /dev/null @@ -1 +0,0 @@ -terraform import snowflake_account_role.example roleName diff --git a/examples/resources/snowflake_account_role/resource.tf b/examples/resources/snowflake_account_role/resource.tf deleted file mode 100644 index 740f215598..0000000000 --- a/examples/resources/snowflake_account_role/resource.tf +++ /dev/null @@ -1,4 +0,0 @@ -resource "snowflake_account_role" "role" { - name = "role_name" - comment = "comment" -} diff --git a/pkg/datasources/account_roles.go b/pkg/datasources/account_roles.go deleted file mode 100644 index e44147860c..0000000000 --- a/pkg/datasources/account_roles.go +++ /dev/null @@ -1,94 +0,0 @@ -package datasources - -import ( - "context" - "database/sql" - "fmt" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var accountRolesSchema = map[string]*schema.Schema{ - "pattern": { - Type: schema.TypeString, - Optional: true, - Description: "Filters the command output by object name.", - }, - "roles": { - Type: schema.TypeList, - Computed: true, - Description: "List of all the roles which you can view across your entire account, including the system-defined roles and any custom roles that exist.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Identifier for the role.", - }, - "comment": { - Type: schema.TypeString, - Computed: true, - Description: "The comment on the role", - }, - "owner": { - Type: schema.TypeString, - Computed: true, - Description: "The owner of the role", - }, - }, - }, - }, -} - -func AccountRoles() *schema.Resource { - return &schema.Resource{ - ReadContext: ReadAccountRoles, - Schema: accountRolesSchema, - } -} - -func ReadAccountRoles(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - db := meta.(*sql.DB) - client := sdk.NewClientFromDB(db) - - req := sdk.NewShowRoleRequest() - if pattern, ok := d.GetOk("pattern"); ok { - req.WithLike(sdk.NewLikeRequest(pattern.(string))) - } - - roles, err := client.Roles.Show(ctx, req) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to show account roles", - Detail: fmt.Sprintf("Search pattern: %v, err: %s", d.Get("pattern").(string), err), - }, - } - } - - mappedRoles := make([]map[string]any, len(roles)) - for i, role := range roles { - mappedRoles[i] = map[string]any{ - "name": role.Name, - "comment": role.Comment, - "owner": role.Owner, - } - } - - if err := d.Set("roles", mappedRoles); err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to set roles", - Detail: fmt.Sprintf("Search pattern: %v, err: %s", d.Get("pattern").(string), err), - }, - } - } - - d.SetId("roles_read") - - return nil -} diff --git a/pkg/datasources/account_roles_acceptance_test.go b/pkg/datasources/account_roles_acceptance_test.go deleted file mode 100644 index 0c0cbfc2f0..0000000000 --- a/pkg/datasources/account_roles_acceptance_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package datasources_test - -import ( - "fmt" - "strconv" - "strings" - "testing" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - "github.com/hashicorp/terraform-plugin-testing/config" - "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-plugin-testing/tfversion" - - "github.com/hashicorp/terraform-plugin-testing/helper/acctest" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" -) - -func TestAcc_AccountRoles_basic(t *testing.T) { - accountRoleNamePrefix := "account_roles_test_prefix_" - accountRoleName1 := accountRoleNamePrefix + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - accountRoleName2 := accountRoleNamePrefix + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - accountRoleName3 := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - comment := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - - configVariables := config.Variables{ - "account_role_name_1": config.StringVariable(accountRoleName1), - "account_role_name_2": config.StringVariable(accountRoleName2), - "account_role_name_3": config.StringVariable(accountRoleName3), - "pattern": config.StringVariable(accountRoleNamePrefix + "%"), - "comment": config.StringVariable(comment), - } - - 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{ - { - ConfigDirectory: config.TestNameDirectory(), - ConfigVariables: configVariables, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.snowflake_account_roles.test", "roles.#", "2"), - containsAccountRole(accountRoleName1, comment), - containsAccountRole(accountRoleName2, comment), - func(state *terraform.State) error { - err := containsAccountRole(accountRoleName3, comment)(state) - if err.Error() == fmt.Sprintf("role %s not found", accountRoleName3) { - return nil - } - return fmt.Errorf("expected %s not to be present", accountRoleName3) - }, - ), - }, - }, - }) -} - -func containsAccountRole(name string, comment string) func(s *terraform.State) error { - return func(s *terraform.State) error { - for _, rs := range s.RootModule().Resources { - if rs.Type != "snowflake_account_roles" { - continue - } - - iter, err := strconv.ParseInt(rs.Primary.Attributes["roles.#"], 10, 32) - if err != nil { - return err - } - - for i := 0; i < int(iter); i++ { - if rs.Primary.Attributes[fmt.Sprintf("roles.%d.name", i)] == name { - actualComment := rs.Primary.Attributes[fmt.Sprintf("roles.%d.comment", i)] - if actualComment != comment { - return fmt.Errorf("expected comment: %s, but got: %s", comment, actualComment) - } - - return nil - } - } - } - - return fmt.Errorf("role %s not found", name) - } -} diff --git a/pkg/datasources/role.go b/pkg/datasources/role.go index 4792af75c2..815624ee4a 100644 --- a/pkg/datasources/role.go +++ b/pkg/datasources/role.go @@ -27,7 +27,7 @@ func Role() *schema.Resource { return &schema.Resource{ Read: ReadRole, Schema: roleSchema, - DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_account_roles instead.", + DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_roles instead.", Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/pkg/datasources/roles.go b/pkg/datasources/roles.go index 4d94fd043e..e9bdd97c6d 100644 --- a/pkg/datasources/roles.go +++ b/pkg/datasources/roles.go @@ -1,13 +1,94 @@ package datasources import ( + "context" + "database/sql" + "fmt" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +var accountRolesSchema = map[string]*schema.Schema{ + "pattern": { + Type: schema.TypeString, + Optional: true, + Description: "Filters the command output by object name.", + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Description: "List of all the roles which you can view across your entire account, including the system-defined roles and any custom roles that exist.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: "Identifier for the role.", + }, + "comment": { + Type: schema.TypeString, + Computed: true, + Description: "The comment on the role", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The owner of the role", + }, + }, + }, + }, +} + func Roles() *schema.Resource { return &schema.Resource{ - ReadContext: ReadAccountRoles, - Schema: accountRolesSchema, - DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_account_roles instead.", + ReadContext: ReadAccountRoles, + Schema: accountRolesSchema, + } +} + +func ReadAccountRoles(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + + req := sdk.NewShowRoleRequest() + if pattern, ok := d.GetOk("pattern"); ok { + req.WithLike(sdk.NewLikeRequest(pattern.(string))) } + + roles, err := client.Roles.Show(ctx, req) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to show account roles", + Detail: fmt.Sprintf("Search pattern: %v, err: %s", d.Get("pattern").(string), err), + }, + } + } + + mappedRoles := make([]map[string]any, len(roles)) + for i, role := range roles { + mappedRoles[i] = map[string]any{ + "name": role.Name, + "comment": role.Comment, + "owner": role.Owner, + } + } + + if err := d.Set("roles", mappedRoles); err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to set roles", + Detail: fmt.Sprintf("Search pattern: %v, err: %s", d.Get("pattern").(string), err), + }, + } + } + + d.SetId("roles_read") + + return nil } diff --git a/pkg/datasources/roles_acceptance_test.go b/pkg/datasources/roles_acceptance_test.go index 9224ecd35c..a6dd78148a 100644 --- a/pkg/datasources/roles_acceptance_test.go +++ b/pkg/datasources/roles_acceptance_test.go @@ -2,9 +2,15 @@ package datasources_test import ( "fmt" + "strconv" "strings" "testing" + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) @@ -43,6 +49,80 @@ func TestAcc_Roles(t *testing.T) { }) } +func TestAcc_AccountRoles_basic(t *testing.T) { + accountRoleNamePrefix := "account_roles_test_prefix_" + accountRoleName1 := accountRoleNamePrefix + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + accountRoleName2 := accountRoleNamePrefix + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + accountRoleName3 := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + comment := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + + configVariables := config.Variables{ + "account_role_name_1": config.StringVariable(accountRoleName1), + "account_role_name_2": config.StringVariable(accountRoleName2), + "account_role_name_3": config.StringVariable(accountRoleName3), + "pattern": config.StringVariable(accountRoleNamePrefix + "%"), + "comment": config.StringVariable(comment), + } + + 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{ + { + ConfigDirectory: config.TestNameDirectory(), + ConfigVariables: configVariables, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.snowflake_roles.test", "roles.#", "2"), + containsAccountRole(accountRoleName1, comment), + containsAccountRole(accountRoleName2, comment), + doesntContainAccountRole(accountRoleName3, comment), + ), + }, + }, + }) +} + +func doesntContainAccountRole(name string, comment string) func(s *terraform.State) error { + return func(state *terraform.State) error { + err := containsAccountRole(name, comment)(state) + if err.Error() == fmt.Sprintf("role %s not found", name) { + return nil + } + return fmt.Errorf("expected %s not to be present", name) + } +} + +func containsAccountRole(name string, comment string) func(s *terraform.State) error { + return func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "snowflake_roles" { + continue + } + + iter, err := strconv.ParseInt(rs.Primary.Attributes["roles.#"], 10, 32) + if err != nil { + return err + } + + for i := 0; i < int(iter); i++ { + if rs.Primary.Attributes[fmt.Sprintf("roles.%d.name", i)] == name { + actualComment := rs.Primary.Attributes[fmt.Sprintf("roles.%d.comment", i)] + if actualComment != comment { + return fmt.Errorf("expected comment: %s, but got: %s", comment, actualComment) + } + + return nil + } + } + } + + return fmt.Errorf("role %s not found", name) + } +} + func roles(roleName, roleName2, comment string) string { return fmt.Sprintf(` resource snowflake_role "test_role" { diff --git a/pkg/datasources/testdata/TestAcc_AccountRoles_basic/test.tf b/pkg/datasources/testdata/TestAcc_AccountRoles_basic/test.tf index 68d5033a36..00ebde112b 100644 --- a/pkg/datasources/testdata/TestAcc_AccountRoles_basic/test.tf +++ b/pkg/datasources/testdata/TestAcc_AccountRoles_basic/test.tf @@ -1,23 +1,23 @@ -resource "snowflake_account_role" "test1" { +resource "snowflake_role" "test1" { name = var.account_role_name_1 comment = var.comment } -resource "snowflake_account_role" "test2" { +resource "snowflake_role" "test2" { name = var.account_role_name_2 comment = var.comment } -resource "snowflake_account_role" "test3" { +resource "snowflake_role" "test3" { name = var.account_role_name_3 comment = var.comment } -data "snowflake_account_roles" "test" { +data "snowflake_roles" "test" { depends_on = [ - snowflake_account_role.test1, - snowflake_account_role.test2, - snowflake_account_role.test3, + snowflake_role.test1, + snowflake_role.test2, + snowflake_role.test3, ] pattern = var.pattern } diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 54dafdffef..ac77870a3c 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -431,7 +431,6 @@ func getResources() map[string]*schema.Resource { "snowflake_account": resources.Account(), "snowflake_account_password_policy_attachment": resources.AccountPasswordPolicyAttachment(), "snowflake_account_parameter": resources.AccountParameter(), - "snowflake_account_role": resources.AccountRole(), "snowflake_alert": resources.Alert(), "snowflake_api_integration": resources.APIIntegration(), "snowflake_database": resources.Database(), @@ -519,7 +518,6 @@ func getDataSources() map[string]*schema.Resource { "snowflake_resource_monitors": datasources.ResourceMonitors(), "snowflake_role": datasources.Role(), "snowflake_roles": datasources.Roles(), - "snowflake_account_roles": datasources.AccountRoles(), "snowflake_row_access_policies": datasources.RowAccessPolicies(), "snowflake_schemas": datasources.Schemas(), "snowflake_sequences": datasources.Sequences(), diff --git a/pkg/resources/account_role.go b/pkg/resources/account_role.go deleted file mode 100644 index 63cf3e7205..0000000000 --- a/pkg/resources/account_role.go +++ /dev/null @@ -1,253 +0,0 @@ -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/diag" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var accountRoleSchema = map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), - }, - "comment": { - Type: schema.TypeString, - Optional: true, - }, - "tag": tagReferenceSchema, -} - -func AccountRole() *schema.Resource { - return &schema.Resource{ - CreateContext: CreateAccountRole, - ReadContext: ReadAccountRole, - DeleteContext: DeleteAccountRole, - UpdateContext: UpdateAccountRole, - - Schema: accountRoleSchema, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - } -} - -func CreateAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - db := meta.(*sql.DB) - client := sdk.NewClientFromDB(db) - - name := d.Get("name").(string) - id, err := helpers.DecodeSnowflakeParameterID(name) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to parse account role name", - Detail: fmt.Sprintf("Account role name: %s, err: %s", name, err), - }, - } - } - req := sdk.NewCreateRoleRequest(id.(sdk.AccountObjectIdentifier)) - - if v, ok := d.GetOk("comment"); ok { - req.WithComment(v.(string)) - } - - if _, ok := d.GetOk("tag"); ok { - req.WithTag(getPropertyTags(d, "tag")) - } - - err = client.Roles.Create(ctx, req) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to create account role", - Detail: fmt.Sprintf("Account role name: %s, err: %s", name, err), - }, - } - } - - d.SetId(helpers.EncodeSnowflakeID(id)) - - return ReadAccountRole(ctx, d, meta) -} - -func ReadAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - db := meta.(*sql.DB) - client := sdk.NewClientFromDB(db) - id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) - - accountRole, err := client.Roles.ShowByID(ctx, sdk.NewShowByIdRoleRequest(id)) - if err != nil { - if err.Error() == "object does not exist" { - d.SetId("") - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Warning, - Summary: "Account role not found; marking it as removed", - Detail: fmt.Sprintf("Account role name: %s, err: %s", id.FullyQualifiedName(), err), - }, - } - } - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to show account role by id", - Detail: fmt.Sprintf("Account role name: %s, err: %s", id.FullyQualifiedName(), err), - }, - } - } - - if err := d.Set("name", accountRole.Name); err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to set account role name", - Detail: fmt.Sprintf("Account role name: %s, err: %s", accountRole.Name, err), - }, - } - } - - if err := d.Set("comment", accountRole.Comment); err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to set account role comment", - Detail: fmt.Sprintf("Account role name: %s, comment: %s, err: %s", accountRole.Name, accountRole.Comment, err), - }, - } - } - - d.SetId(helpers.EncodeSnowflakeID(id)) - - return nil -} - -func UpdateAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - db := meta.(*sql.DB) - client := sdk.NewClientFromDB(db) - id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) - - if d.HasChange("comment") { - if v, ok := d.GetOk("comment"); ok { - err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithSetComment(v.(string))) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to set account role comment", - Detail: fmt.Sprintf("Account role name: %s, comment: %s, err: %s", id.FullyQualifiedName(), v, err), - }, - } - } - } else { - err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithUnsetComment(true)) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to unset account role comment", - Detail: fmt.Sprintf("Account role name: %s, err: %s", id.FullyQualifiedName(), err), - }, - } - } - } - } - - if d.HasChange("tag") { - unsetTags, setTags := GetTagsDiff(d, "tag") - - if len(unsetTags) > 0 { - err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithUnsetTags(unsetTags)) - if err != nil { - tagNames := make([]string, len(unsetTags)) - for i, v := range unsetTags { - tagNames[i] = v.FullyQualifiedName() - } - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to unset account role tags", - Detail: fmt.Sprintf("Account role name: %s, tags to unset: %v, err: %s", id.FullyQualifiedName(), tagNames, err), - }, - } - } - } - - if len(setTags) > 0 { - err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithSetTags(setTags)) - if err != nil { - tagNames := make([]string, len(unsetTags)) - for i, v := range unsetTags { - tagNames[i] = v.FullyQualifiedName() - } - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to set account role tags", - Detail: fmt.Sprintf("Account role name: %s, tags to set: %v, err: %s", id.FullyQualifiedName(), tagNames, err), - }, - } - } - } - } - - if d.HasChange("name") { - _, newName := d.GetChange("name") - - newId, err := helpers.DecodeSnowflakeParameterID(newName.(string)) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to parse account role name", - Detail: fmt.Sprintf("Account role name: %s, err: %s", newName, err), - }, - } - } - - err = client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithRenameTo(newId.(sdk.AccountObjectIdentifier))) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to rename account role name", - Detail: fmt.Sprintf("Previous account role name: %s, new account role name: %s, err: %s", id, newName, err), - }, - } - } - - d.SetId(helpers.EncodeSnowflakeID(newId)) - } - - return nil -} - -func DeleteAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - db := meta.(*sql.DB) - client := sdk.NewClientFromDB(db) - id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) - - err := client.Roles.Drop(ctx, sdk.NewDropRoleRequest(id)) - if err != nil { - return diag.Diagnostics{ - diag.Diagnostic{ - Severity: diag.Error, - Summary: "Failed to drop account role", - Detail: fmt.Sprintf("Account role name: %s, err: %s", d.Id(), err), - }, - } - } - - d.SetId("") - - return nil -} diff --git a/pkg/resources/account_role_acceptance_test.go b/pkg/resources/account_role_acceptance_test.go deleted file mode 100644 index 184a1d64f5..0000000000 --- a/pkg/resources/account_role_acceptance_test.go +++ /dev/null @@ -1,127 +0,0 @@ -package resources_test - -import ( - "context" - "database/sql" - "fmt" - "strings" - "testing" - - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" - "github.com/hashicorp/terraform-plugin-testing/config" - "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-plugin-testing/tfversion" - - acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" - "github.com/hashicorp/terraform-plugin-testing/helper/acctest" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" -) - -func TestAcc_AccountRole_basic(t *testing.T) { - name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - comment := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - configVariables := map[string]config.Variable{ - "name": config.StringVariable(name), - "comment": config.StringVariable(comment), - } - resourceName := "snowflake_account_role.test" - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: testAccCheckAccountRoleDestroy(name), - Steps: []resource.TestStep{ - { - ConfigDirectory: config.TestNameDirectory(), - ConfigVariables: configVariables, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), - resource.TestCheckResourceAttr(resourceName, "comment", comment), - resource.TestCheckResourceAttr(resourceName, "id", name), - ), - }, - // test import - { - ConfigDirectory: config.TestNameDirectory(), - ConfigVariables: configVariables, - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAcc_AccountRole_updates(t *testing.T) { - configVariables := func(name string, comment string) config.Variables { - return config.Variables{ - "name": config.StringVariable(name), - "comment": config.StringVariable(comment), - } - } - - name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - newName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - comment := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - NewComment := "updated comment with 'single' quotes" - resourceName := "snowflake_account_role.test" - - resource.Test(t, resource.TestCase{ - ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, - PreCheck: func() { acc.TestAccPreCheck(t) }, - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.RequireAbove(tfversion.Version1_5_0), - }, - CheckDestroy: testAccCheckAccountRoleDestroy(name), - Steps: []resource.TestStep{ - { - ConfigDirectory: config.TestNameDirectory(), - ConfigVariables: configVariables(name, comment), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", name), - resource.TestCheckResourceAttr(resourceName, "comment", comment), - resource.TestCheckResourceAttr(resourceName, "id", name), - ), - }, - { - ConfigDirectory: config.TestNameDirectory(), - ConfigVariables: configVariables(newName, NewComment), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", newName), - resource.TestCheckResourceAttr(resourceName, "comment", NewComment), - resource.TestCheckResourceAttr(resourceName, "id", newName), - ), - }, - // test import - { - ConfigDirectory: config.TestNameDirectory(), - ConfigVariables: configVariables(newName, NewComment), - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccCheckAccountRoleDestroy(accountRoleName string) func(state *terraform.State) error { - return func(state *terraform.State) error { - db := acc.TestAccProvider.Meta().(*sql.DB) - client := sdk.NewClientFromDB(db) - for _, rs := range state.RootModule().Resources { - if rs.Type != "snowflake_account_role" { - continue - } - ctx := context.Background() - id := sdk.NewAccountObjectIdentifier(rs.Primary.Attributes["name"]) - _, err := client.Roles.ShowByID(ctx, sdk.NewShowByIdRoleRequest(id)) - if err == nil { - return fmt.Errorf("account role %v still exists", accountRoleName) - } - } - return nil - } -} diff --git a/pkg/resources/role.go b/pkg/resources/role.go index d63266e781..d9e5a599fe 100644 --- a/pkg/resources/role.go +++ b/pkg/resources/role.go @@ -1,16 +1,35 @@ 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/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +var accountRoleSchema = map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), + }, + "comment": { + Type: schema.TypeString, + Optional: true, + }, + "tag": tagReferenceSchema, +} + func Role() *schema.Resource { return &schema.Resource{ - CreateContext: CreateAccountRole, - ReadContext: ReadAccountRole, - DeleteContext: DeleteAccountRole, - UpdateContext: UpdateAccountRole, - DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_account_role instead.", + CreateContext: CreateAccountRole, + ReadContext: ReadAccountRole, + DeleteContext: DeleteAccountRole, + UpdateContext: UpdateAccountRole, Schema: accountRoleSchema, Importer: &schema.ResourceImporter{ @@ -18,3 +37,207 @@ func Role() *schema.Resource { }, } } + +func CreateAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + + name := d.Get("name").(string) + id := sdk.NewAccountObjectIdentifier(name) + req := sdk.NewCreateRoleRequest(id) + + if v, ok := d.GetOk("comment"); ok { + req.WithComment(v.(string)) + } + + if _, ok := d.GetOk("tag"); ok { + req.WithTag(getPropertyTags(d, "tag")) + } + + err := client.Roles.Create(ctx, req) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to create account role", + Detail: fmt.Sprintf("Account role name: %s, err: %s", name, err), + }, + } + } + + d.SetId(helpers.EncodeSnowflakeID(id)) + + return ReadAccountRole(ctx, d, meta) +} + +func ReadAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + + accountRole, err := client.Roles.ShowByID(ctx, sdk.NewShowByIdRoleRequest(id)) + if err != nil { + if err.Error() == "object does not exist" { + d.SetId("") + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: "Account role not found; marking it as removed", + Detail: fmt.Sprintf("Account role name: %s, err: %s", id.FullyQualifiedName(), err), + }, + } + } + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to show account role by id", + Detail: fmt.Sprintf("Account role name: %s, err: %s", id.FullyQualifiedName(), err), + }, + } + } + + if err := d.Set("name", accountRole.Name); err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to set account role name", + Detail: fmt.Sprintf("Account role name: %s, err: %s", accountRole.Name, err), + }, + } + } + + if err := d.Set("comment", accountRole.Comment); err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to set account role comment", + Detail: fmt.Sprintf("Account role name: %s, comment: %s, err: %s", accountRole.Name, accountRole.Comment, err), + }, + } + } + + d.SetId(helpers.EncodeSnowflakeID(id)) + + return nil +} + +func UpdateAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + + if d.HasChange("comment") { + if v, ok := d.GetOk("comment"); ok { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithSetComment(v.(string))) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to set account role comment", + Detail: fmt.Sprintf("Account role name: %s, comment: %s, err: %s", id.FullyQualifiedName(), v, err), + }, + } + } + } else { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithUnsetComment(true)) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to unset account role comment", + Detail: fmt.Sprintf("Account role name: %s, err: %s", id.FullyQualifiedName(), err), + }, + } + } + } + } + + if d.HasChange("tag") { + unsetTags, setTags := GetTagsDiff(d, "tag") + + if len(unsetTags) > 0 { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithUnsetTags(unsetTags)) + if err != nil { + tagNames := make([]string, len(unsetTags)) + for i, v := range unsetTags { + tagNames[i] = v.FullyQualifiedName() + } + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to unset account role tags", + Detail: fmt.Sprintf("Account role name: %s, tags to unset: %v, err: %s", id.FullyQualifiedName(), tagNames, err), + }, + } + } + } + + if len(setTags) > 0 { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithSetTags(setTags)) + if err != nil { + tagNames := make([]string, len(unsetTags)) + for i, v := range unsetTags { + tagNames[i] = v.FullyQualifiedName() + } + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to set account role tags", + Detail: fmt.Sprintf("Account role name: %s, tags to set: %v, err: %s", id.FullyQualifiedName(), tagNames, err), + }, + } + } + } + } + + if d.HasChange("name") { + _, newName := d.GetChange("name") + + newId, err := helpers.DecodeSnowflakeParameterID(newName.(string)) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to parse account role name", + Detail: fmt.Sprintf("Account role name: %s, err: %s", newName, err), + }, + } + } + + err = client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithRenameTo(newId.(sdk.AccountObjectIdentifier))) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to rename account role name", + Detail: fmt.Sprintf("Previous account role name: %s, new account role name: %s, err: %s", id, newName, err), + }, + } + } + + d.SetId(helpers.EncodeSnowflakeID(newId)) + } + + return nil +} + +func DeleteAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + + err := client.Roles.Drop(ctx, sdk.NewDropRoleRequest(id)) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to drop account role", + Detail: fmt.Sprintf("Account role name: %s, err: %s", d.Id(), err), + }, + } + } + + d.SetId("") + + return nil +} diff --git a/pkg/resources/role_acceptance_test.go b/pkg/resources/role_acceptance_test.go index 093e984198..3112aaa721 100644 --- a/pkg/resources/role_acceptance_test.go +++ b/pkg/resources/role_acceptance_test.go @@ -1,10 +1,17 @@ package resources_test import ( + "context" + "database/sql" "fmt" "strings" "testing" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -52,6 +59,115 @@ func TestAcc_Role(t *testing.T) { }) } +func TestAcc_AccountRole_basic(t *testing.T) { + name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + comment := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + configVariables := map[string]config.Variable{ + "name": config.StringVariable(name), + "comment": config.StringVariable(comment), + } + resourceName := "snowflake_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: testAccCheckAccountRoleDestroy(name), + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestNameDirectory(), + ConfigVariables: configVariables, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "comment", comment), + resource.TestCheckResourceAttr(resourceName, "id", name), + ), + }, + // test import + { + ConfigDirectory: config.TestNameDirectory(), + ConfigVariables: configVariables, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAcc_AccountRole_updates(t *testing.T) { + configVariables := func(name string, comment string) config.Variables { + return config.Variables{ + "name": config.StringVariable(name), + "comment": config.StringVariable(comment), + } + } + + name := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + newName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + comment := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + NewComment := "updated comment with 'single' quotes" + resourceName := "snowflake_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: testAccCheckAccountRoleDestroy(name), + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestNameDirectory(), + ConfigVariables: configVariables(name, comment), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "comment", comment), + resource.TestCheckResourceAttr(resourceName, "id", name), + ), + }, + { + ConfigDirectory: config.TestNameDirectory(), + ConfigVariables: configVariables(newName, NewComment), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", newName), + resource.TestCheckResourceAttr(resourceName, "comment", NewComment), + resource.TestCheckResourceAttr(resourceName, "id", newName), + ), + }, + // test import + { + ConfigDirectory: config.TestNameDirectory(), + ConfigVariables: configVariables(newName, NewComment), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAccountRoleDestroy(accountRoleName string) func(state *terraform.State) error { + return func(state *terraform.State) error { + db := acc.TestAccProvider.Meta().(*sql.DB) + client := sdk.NewClientFromDB(db) + for _, rs := range state.RootModule().Resources { + if rs.Type != "snowflake_role" { + continue + } + ctx := context.Background() + id := sdk.NewAccountObjectIdentifier(rs.Primary.Attributes["name"]) + _, err := client.Roles.ShowByID(ctx, sdk.NewShowByIdRoleRequest(id)) + if err == nil { + return fmt.Errorf("account role %v still exists", accountRoleName) + } + } + return nil + } +} + func roleBasicConfig(name, comment string) string { s := ` resource "snowflake_role" "role" { diff --git a/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf b/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf index 1aa83161f4..7dac5cc2c3 100644 --- a/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf +++ b/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf @@ -1,4 +1,4 @@ -resource "snowflake_account_role" "test" { +resource "snowflake_role" "test" { name = var.name comment = var.comment } diff --git a/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf b/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf index 1aa83161f4..7dac5cc2c3 100644 --- a/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf +++ b/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf @@ -1,4 +1,4 @@ -resource "snowflake_account_role" "test" { +resource "snowflake_role" "test" { name = var.name comment = var.comment }