From 0708a7fe11993a3badbf371c36d3234f8dc473e8 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 --- .../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/roles.go | 81 ++++++ pkg/datasources/roles_acceptance_test.go | 79 ++++++ pkg/provider/provider.go | 2 - pkg/resources/account_role.go | 253 ------------------ pkg/resources/account_role_acceptance_test.go | 127 --------- pkg/resources/role.go | 223 +++++++++++++++ pkg/resources/role_acceptance_test.go | 115 ++++++++ 12 files changed, 498 insertions(+), 573 deletions(-) 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/examples/data-sources/snowflake_account_roles/data-source.tf b/examples/data-sources/snowflake_account_roles/data-source.tf deleted file mode 100644 index c5846c0fab6..00000000000 --- 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 96c1cd42765..00000000000 --- 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 740f215598f..00000000000 --- 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 e44147860cb..00000000000 --- 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 0c0cbfc2f0a..00000000000 --- 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/roles.go b/pkg/datasources/roles.go index 4d94fd043e7..7f8f8b84513 100644 --- a/pkg/datasources/roles.go +++ b/pkg/datasources/roles.go @@ -1,9 +1,46 @@ 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, @@ -11,3 +48,47 @@ func Roles() *schema.Resource { DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_account_roles instead.", } } + +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 9224ecd35c7..78a8a85c587 100644 --- a/pkg/datasources/roles_acceptance_test.go +++ b/pkg/datasources/roles_acceptance_test.go @@ -2,6 +2,11 @@ package datasources_test import ( "fmt" + 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" + "strconv" "strings" "testing" @@ -43,6 +48,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_account_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_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) + } +} + func roles(roleName, roleName2, comment string) string { return fmt.Sprintf(` resource snowflake_role "test_role" { diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 21b11488dbb..b72a7f76bb7 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(), @@ -518,7 +517,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 63cf3e7205e..00000000000 --- 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 184a1d64f55..00000000000 --- 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 d63266e7816..ee3f149a35e 100644 --- a/pkg/resources/role.go +++ b/pkg/resources/role.go @@ -1,9 +1,28 @@ 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, @@ -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 093e9841983..687a9f73785 100644 --- a/pkg/resources/role_acceptance_test.go +++ b/pkg/resources/role_acceptance_test.go @@ -1,7 +1,13 @@ package resources_test import ( + "context" + "database/sql" "fmt" + "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" "strings" "testing" @@ -52,6 +58,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_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 + } +} + func roleBasicConfig(name, comment string) string { s := ` resource "snowflake_role" "role" {