diff --git a/pkg/datasources/role.go b/pkg/datasources/role.go index 6cf81c4271..815624ee4a 100644 --- a/pkg/datasources/role.go +++ b/pkg/datasources/role.go @@ -25,8 +25,9 @@ var roleSchema = map[string]*schema.Schema{ // Role Snowflake Role resource. func Role() *schema.Resource { return &schema.Resource{ - Read: ReadRole, - Schema: roleSchema, + Read: ReadRole, + Schema: roleSchema, + 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 781bed6e73..e9bdd97c6d 100644 --- a/pkg/datasources/roles.go +++ b/pkg/datasources/roles.go @@ -1,15 +1,16 @@ package datasources import ( + "context" "database/sql" - "errors" - "log" + "fmt" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" + "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 rolesSchema = map[string]*schema.Schema{ +var accountRolesSchema = map[string]*schema.Schema{ "pattern": { Type: schema.TypeString, Optional: true, @@ -41,47 +42,53 @@ var rolesSchema = map[string]*schema.Schema{ }, } -// Roles Snowflake Roles resource. func Roles() *schema.Resource { return &schema.Resource{ - Read: ReadRoles, - Schema: rolesSchema, + ReadContext: ReadAccountRoles, + Schema: accountRolesSchema, } } -// ReadRoles Reads the database metadata information. -func ReadRoles(d *schema.ResourceData, meta interface{}) error { +func ReadAccountRoles(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { db := meta.(*sql.DB) - d.SetId("roles_read") - rolePattern := d.Get("pattern").(string) + client := sdk.NewClientFromDB(db) - listRoles, err := snowflake.ListRoles(db, rolePattern) - if errors.Is(err, sql.ErrNoRows) { - log.Printf("[DEBUG] no roles found in account (%s)", d.Id()) - d.SetId("") - return nil - } else if err != nil { - log.Println("[DEBUG] failed to list roles") - d.SetId("") - return nil + req := sdk.NewShowRoleRequest() + if pattern, ok := d.GetOk("pattern"); ok { + req.WithLike(sdk.NewLikeRequest(pattern.(string))) } - log.Printf("[DEBUG] list roles: %v", listRoles) + 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), + }, + } + } - roles := []map[string]interface{}{} - for _, role := range listRoles { - roleMap := map[string]interface{}{} - if !role.Name.Valid { - continue + 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, } - roleMap["name"] = role.Name.String - roleMap["comment"] = role.Comment.String - roleMap["owner"] = role.Owner.String - roles = append(roles, roleMap) } - if err := d.Set("roles", roles); err != nil { - return err + 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 new file mode 100644 index 0000000000..00ebde112b --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_AccountRoles_basic/test.tf @@ -0,0 +1,23 @@ +resource "snowflake_role" "test1" { + name = var.account_role_name_1 + comment = var.comment +} + +resource "snowflake_role" "test2" { + name = var.account_role_name_2 + comment = var.comment +} + +resource "snowflake_role" "test3" { + name = var.account_role_name_3 + comment = var.comment +} + +data "snowflake_roles" "test" { + depends_on = [ + snowflake_role.test1, + snowflake_role.test2, + snowflake_role.test3, + ] + pattern = var.pattern +} diff --git a/pkg/datasources/testdata/TestAcc_AccountRoles_basic/variables.tf b/pkg/datasources/testdata/TestAcc_AccountRoles_basic/variables.tf new file mode 100644 index 0000000000..c632a5527e --- /dev/null +++ b/pkg/datasources/testdata/TestAcc_AccountRoles_basic/variables.tf @@ -0,0 +1,19 @@ +variable "account_role_name_1" { + type = string +} + +variable "account_role_name_2" { + type = string +} + +variable "account_role_name_3" { + type = string +} + +variable "comment" { + type = string +} + +variable "pattern" { + type = string +} diff --git a/pkg/resources/database_role_acceptance_test.go b/pkg/resources/database_role_acceptance_test.go index 071ef0f9b1..9729a449eb 100644 --- a/pkg/resources/database_role_acceptance_test.go +++ b/pkg/resources/database_role_acceptance_test.go @@ -10,14 +10,12 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) -var ( - resourceName = "snowflake_database_role.test_db_role" - dbRoleName = "db_role_" + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) - comment = "dummy" - comment2 = "test comment" -) - func TestAcc_DatabaseRole(t *testing.T) { + resourceName := "snowflake_database_role.test_db_role" + dbRoleName := "db_role_" + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + comment := "dummy" + comment2 := "test comment" + resource.Test(t, resource.TestCase{ Providers: acc.TestAccProviders(), PreCheck: func() { acc.TestAccPreCheck(t) }, diff --git a/pkg/resources/dynamic_table.go b/pkg/resources/dynamic_table.go index 49446f14f4..eba737df17 100644 --- a/pkg/resources/dynamic_table.go +++ b/pkg/resources/dynamic_table.go @@ -12,7 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -var dynamicTableShema = map[string]*schema.Schema{ +var dynamicTableSchema = map[string]*schema.Schema{ "or_replace": { Type: schema.TypeBool, Optional: true, @@ -145,7 +145,7 @@ func DynamicTable() *schema.Resource { Update: UpdateDynamicTable, Delete: DeleteDynamicTable, - Schema: dynamicTableShema, + Schema: dynamicTableSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/pkg/resources/external_table.go b/pkg/resources/external_table.go index f9d73c4237..5b1235ca16 100644 --- a/pkg/resources/external_table.go +++ b/pkg/resources/external_table.go @@ -285,18 +285,22 @@ func UpdateExternalTable(d *schema.ResourceData, meta any) error { if d.HasChange("tag") { unsetTags, setTags := GetTagsDiff(d, "tag") - err := client.ExternalTables.Alter(ctx, sdk.NewAlterExternalTableRequest(id).WithUnsetTag(unsetTags)) - if err != nil { - return fmt.Errorf("error setting tags on %v, err = %w", d.Id(), err) + if len(unsetTags) > 0 { + err := client.ExternalTables.Alter(ctx, sdk.NewAlterExternalTableRequest(id).WithUnsetTag(unsetTags)) + if err != nil { + return fmt.Errorf("error setting tags on %v, err = %w", d.Id(), err) + } } - tagAssociationRequests := make([]*sdk.TagAssociationRequest, len(setTags)) - for i, t := range setTags { - tagAssociationRequests[i] = sdk.NewTagAssociationRequest(t.Name, t.Value) - } - err = client.ExternalTables.Alter(ctx, sdk.NewAlterExternalTableRequest(id).WithSetTag(tagAssociationRequests)) - if err != nil { - return fmt.Errorf("error setting tags on %v, err = %w", d.Id(), err) + if len(setTags) > 0 { + tagAssociationRequests := make([]*sdk.TagAssociationRequest, len(setTags)) + for i, t := range setTags { + tagAssociationRequests[i] = sdk.NewTagAssociationRequest(t.Name, t.Value) + } + err := client.ExternalTables.Alter(ctx, sdk.NewAlterExternalTableRequest(id).WithSetTag(tagAssociationRequests)) + if err != nil { + return fmt.Errorf("error setting tags on %v, err = %w", d.Id(), err) + } } } diff --git a/pkg/resources/role.go b/pkg/resources/role.go index 60268121d2..b834650a6c 100644 --- a/pkg/resources/role.go +++ b/pkg/resources/role.go @@ -1,154 +1,244 @@ package resources import ( + "context" "database/sql" - "errors" - "log" + "fmt" + "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/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -var roleSchema = map[string]*schema.Schema{ +var accountRoleSchema = map[string]*schema.Schema{ "name": { Type: schema.TypeString, Required: true, - ValidateFunc: func(val interface{}, key string) ([]string, []error) { - additionalCharsToIgnoreValidation := []string{".", " ", ":", "(", ")"} - return sdk.ValidateIdentifier(val, additionalCharsToIgnoreValidation) - }, + // TODO(SNOW-999049): Uncomment once better identifier validation will be implemented + // ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), }, "comment": { Type: schema.TypeString, Optional: true, - // TODO validation }, "tag": tagReferenceSchema, } func Role() *schema.Resource { return &schema.Resource{ - Create: CreateRole, - Read: ReadRole, - Delete: DeleteRole, - Update: UpdateRole, + CreateContext: CreateAccountRole, + ReadContext: ReadAccountRole, + DeleteContext: DeleteAccountRole, + UpdateContext: UpdateAccountRole, - Schema: roleSchema, + Schema: accountRoleSchema, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, } } -func CreateRole(d *schema.ResourceData, meta interface{}) error { - name := d.Get("name").(string) +func CreateAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { db := meta.(*sql.DB) - builder := snowflake.NewRoleBuilder(db, name) + client := sdk.NewClientFromDB(db) + + name := d.Get("name").(string) + id := sdk.NewAccountObjectIdentifier(name) + req := sdk.NewCreateRoleRequest(id) + if v, ok := d.GetOk("comment"); ok { - builder.WithComment(v.(string)) + req.WithComment(v.(string)) } - if v, ok := d.GetOk("tag"); ok { - tags := getTags(v) - builder.WithTags(tags.toSnowflakeTagValues()) + + if _, ok := d.GetOk("tag"); ok { + req.WithTag(getPropertyTags(d, "tag")) } - err := builder.Create() + + err := client.Roles.Create(ctx, req) if err != nil { - return err + 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(name) - return ReadRole(d, meta) + + d.SetId(helpers.EncodeSnowflakeID(id)) + + return ReadAccountRole(ctx, d, meta) } -func ReadRole(d *schema.ResourceData, meta interface{}) error { +func ReadAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { db := meta.(*sql.DB) - id := d.Id() - // If the name is not set (such as during import) then use the id - name := d.Get("name").(string) - if name == "" { - name = id - } + client := sdk.NewClientFromDB(db) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) - builder := snowflake.NewRoleBuilder(db, name) - role, err := builder.Show() - if errors.Is(err, sql.ErrNoRows) { - log.Printf("[WARN] role (%s) not found", name) - d.SetId("") - return nil - } else if err != nil { - return err + 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", role.Name.String); err != nil { - return 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", role.Comment.String); err != nil { - return 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 UpdateRole(d *schema.ResourceData, meta interface{}) error { +func UpdateAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { db := meta.(*sql.DB) - name := d.Get("name").(string) - builder := snowflake.NewRoleBuilder(db, name) - - if d.HasChange("name") { - o, n := d.GetChange("name") - builder.WithName(o.(string)) - err := builder.Rename(n.(string)) - if err != nil { - return err - } - builder.WithName(n.(string)) - } + client := sdk.NewClientFromDB(db) + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) if d.HasChange("comment") { - o, n := d.GetChange("comment") - if n == nil || n.(string) == "" { - builder.WithComment(o.(string)) - err := builder.UnsetComment() + if v, ok := d.GetOk("comment"); ok { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithSetComment(v.(string))) if err != nil { - return err + 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 := builder.SetComment(n.(string)) + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithUnsetComment(true)) if err != nil { - return err + 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") { - o, n := d.GetChange("tag") - removed, added, changed := getTags(o).diffs(getTags(n)) - for _, tA := range removed { - err := builder.UnsetTag(tA.toSnowflakeTagValue()) + unsetTags, setTags := GetTagsDiff(d, "tag") + + if len(unsetTags) > 0 { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithUnsetTags(unsetTags)) if err != nil { - return err + 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), + }, + } } } - for _, tA := range added { - err := builder.SetTag(tA.toSnowflakeTagValue()) + + if len(setTags) > 0 { + err := client.Roles.Alter(ctx, sdk.NewAlterRoleRequest(id).WithSetTags(setTags)) if err != nil { - return err + 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), + }, + } } } - for _, tA := range changed { - err := builder.ChangeTag(tA.toSnowflakeTagValue()) - if err != nil { - return 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 DeleteRole(d *schema.ResourceData, meta interface{}) error { +func DeleteAccountRole(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { db := meta.(*sql.DB) - name := d.Get("name").(string) - builder := snowflake.NewRoleBuilder(db, name) - err := builder.Drop() - return err + 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/schema.go b/pkg/resources/schema.go index bdd30aa3ca..7dc7474541 100644 --- a/pkg/resources/schema.go +++ b/pkg/resources/schema.go @@ -231,18 +231,22 @@ func UpdateSchema(d *schema.ResourceData, meta interface{}) error { if d.HasChange("tag") { unsetTags, setTags := GetTagsDiff(d, "tag") - err := client.Schemas.Alter(ctx, id, &sdk.AlterSchemaOptions{ - UnsetTag: unsetTags, - }) - if err != nil { - return fmt.Errorf("error occurred when dropping tags on %v, err = %w", d.Id(), err) + if len(unsetTags) > 0 { + err := client.Schemas.Alter(ctx, id, &sdk.AlterSchemaOptions{ + UnsetTag: unsetTags, + }) + if err != nil { + return fmt.Errorf("error occurred when dropping tags on %v, err = %w", d.Id(), err) + } } - err = client.Schemas.Alter(ctx, id, &sdk.AlterSchemaOptions{ - SetTag: setTags, - }) - if err != nil { - return fmt.Errorf("error occurred when setting tags on %v, err = %w", d.Id(), err) + if len(setTags) > 0 { + err := client.Schemas.Alter(ctx, id, &sdk.AlterSchemaOptions{ + SetTag: setTags, + }) + if err != nil { + return fmt.Errorf("error occurred when setting tags on %v, err = %w", d.Id(), err) + } } } diff --git a/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf b/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf new file mode 100644 index 0000000000..7dac5cc2c3 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_AccountRole_basic/test.tf @@ -0,0 +1,4 @@ +resource "snowflake_role" "test" { + name = var.name + comment = var.comment +} diff --git a/pkg/resources/testdata/TestAcc_AccountRole_basic/variables.tf b/pkg/resources/testdata/TestAcc_AccountRole_basic/variables.tf new file mode 100644 index 0000000000..821eeebe89 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_AccountRole_basic/variables.tf @@ -0,0 +1,7 @@ +variable "name" { + type = string +} + +variable "comment" { + type = string +} diff --git a/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf b/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf new file mode 100644 index 0000000000..7dac5cc2c3 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_AccountRole_updates/test.tf @@ -0,0 +1,4 @@ +resource "snowflake_role" "test" { + name = var.name + comment = var.comment +} diff --git a/pkg/resources/testdata/TestAcc_AccountRole_updates/variables.tf b/pkg/resources/testdata/TestAcc_AccountRole_updates/variables.tf new file mode 100644 index 0000000000..821eeebe89 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_AccountRole_updates/variables.tf @@ -0,0 +1,7 @@ +variable "name" { + type = string +} + +variable "comment" { + type = string +}