Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mark the deleted field computed in google_project_iam_custom_role #2619

Merged
merged 1 commit into from
Dec 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 7 additions & 51 deletions google/resource_google_project_iam_custom_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ func resourceGoogleProjectIamCustomRole() *schema.Resource {
},
"deleted": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Computed: true,
},
},
}
Expand All @@ -69,10 +68,6 @@ func resourceGoogleProjectIamCustomRoleCreate(d *schema.ResourceData, meta inter
return err
}

if d.Get("deleted").(bool) {
return fmt.Errorf("Cannot create a custom project role with a deleted state. `deleted` field should be false.")
}

roleId := fmt.Sprintf("projects/%s/roles/%s", project, d.Get("role_id").(string))
r, err := config.clientIAM.Projects.Roles.Get(roleId).Do()
if err == nil {
Expand Down Expand Up @@ -140,50 +135,20 @@ func resourceGoogleProjectIamCustomRoleUpdate(d *schema.ResourceData, meta inter

d.Partial(true)

if d.Get("deleted").(bool) {
if d.HasChange("deleted") {
// If other fields were changed, we need to update those first and then delete.
// If we don't update, we will get diffs from re-apply
// If we delete and then try to update, we will get an error.
if err := resourceGoogleProjectIamCustomRoleUpdateNonDeletedFields(d, meta); err != nil {
return err
}
if err := resourceGoogleProjectIamCustomRoleDelete(d, meta); err != nil {
return err
}

d.SetPartial("deleted")
d.Partial(false)
return nil
} else {
return fmt.Errorf("cannot make changes to deleted custom project role %s", d.Id())
}
}

// We want to update the role to some undeleted state.
// Make sure the role with given ID exists and is un-deleted before patching.
r, err := config.clientIAM.Projects.Roles.Get(d.Id()).Do()
if err != nil {
return fmt.Errorf("unable to find custom project role %s to update: %v", d.Id(), err)
}
if r.Deleted {
// Undelete if deleted previously
if err := resourceGoogleProjectIamCustomRoleUndelete(d, meta); err != nil {
return err
_, err := config.clientIAM.Projects.Roles.Undelete(d.Id(), &iam.UndeleteRoleRequest{}).Do()
if err != nil {
return fmt.Errorf("Error undeleting the custom project role %s: %s", d.Get("title").(string), err)
}
d.SetPartial("deleted")
}

if err := resourceGoogleProjectIamCustomRoleUpdateNonDeletedFields(d, meta); err != nil {
return err
d.SetPartial("deleted")
}
d.Partial(false)

return nil
}

func resourceGoogleProjectIamCustomRoleUpdateNonDeletedFields(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

if d.HasChange("title") || d.HasChange("description") || d.HasChange("stage") || d.HasChange("permissions") {
_, err := config.clientIAM.Projects.Roles.Patch(d.Id(), &iam.Role{
Expand All @@ -201,6 +166,8 @@ func resourceGoogleProjectIamCustomRoleUpdateNonDeletedFields(d *schema.Resource
d.SetPartial("stage")
d.SetPartial("permissions")
}

d.Partial(false)
return nil
}

Expand All @@ -214,14 +181,3 @@ func resourceGoogleProjectIamCustomRoleDelete(d *schema.ResourceData, meta inter

return nil
}

func resourceGoogleProjectIamCustomRoleUndelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

_, err := config.clientIAM.Projects.Roles.Undelete(d.Id(), &iam.UndeleteRoleRequest{}).Do()
if err != nil {
return fmt.Errorf("Error undeleting the custom project role %s: %s", d.Get("title").(string), err)
}

return nil
}
51 changes: 31 additions & 20 deletions google/resource_google_project_iam_custom_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestAccProjectIamCustomRole_undelete(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccCheckGoogleProjectIamCustomRole_basic(roleId),
Check: resource.TestCheckResourceAttr("google_project_iam_custom_role.foo", "deleted", "false"),
Check: testAccCheckGoogleProjectIamCustomRoleDeletionStatus("google_project_iam_custom_role.foo", false),
},
{
ResourceName: "google_project_iam_custom_role.foo",
Expand All @@ -61,18 +61,15 @@ func TestAccProjectIamCustomRole_undelete(t *testing.T) {
},
// Soft-delete
{
Config: testAccCheckGoogleProjectIamCustomRole_deleted(roleId),
Check: resource.TestCheckResourceAttr("google_project_iam_custom_role.foo", "deleted", "true"),
},
{
ResourceName: "google_project_iam_custom_role.foo",
ImportState: true,
ImportStateVerify: true,
Config: testAccCheckGoogleProjectIamCustomRole_basic(roleId),
Check: testAccCheckGoogleProjectIamCustomRoleDeletionStatus("google_project_iam_custom_role.foo", true),
Destroy: true,
},
// Terraform doesn't have a config because of Destroy: true, so an import step would fail
// Undelete
{
Config: testAccCheckGoogleProjectIamCustomRole_basic(roleId),
Check: resource.TestCheckResourceAttr("google_project_iam_custom_role.foo", "deleted", "false"),
Check: testAccCheckGoogleProjectIamCustomRoleDeletionStatus("google_project_iam_custom_role.foo", false),
},
{
ResourceName: "google_project_iam_custom_role.foo",
Expand Down Expand Up @@ -141,25 +138,39 @@ func testAccCheckGoogleProjectIamCustomRoleDestroy(s *terraform.State) error {
return nil
}

func testAccCheckGoogleProjectIamCustomRole_basic(roleId string) string {
return fmt.Sprintf(`
resource "google_project_iam_custom_role" "foo" {
role_id = "%s"
title = "My Custom Role"
description = "foo"
permissions = ["iam.roles.list"]
}
`, roleId)
func testAccCheckGoogleProjectIamCustomRoleDeletionStatus(n string, deleted bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

config := testAccProvider.Meta().(*Config)
role, err := config.clientIAM.Projects.Roles.Get(rs.Primary.ID).Do()

if err != nil {
return err
}

if deleted != role.Deleted {
return fmt.Errorf("Incorrect deletion status. Expected %t, got %t", deleted, role.Deleted)
}

return nil
}
}

func testAccCheckGoogleProjectIamCustomRole_deleted(roleId string) string {
func testAccCheckGoogleProjectIamCustomRole_basic(roleId string) string {
return fmt.Sprintf(`
resource "google_project_iam_custom_role" "foo" {
role_id = "%s"
title = "My Custom Role"
description = "foo"
permissions = ["iam.roles.list"]
deleted = true
}
`, roleId)
}
Expand Down
7 changes: 7 additions & 0 deletions website/docs/r/google_project_iam_custom_role.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ The following arguments are supported:

* `description` - (Optional) A human-readable description for the role.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are
exported:

* `deleted` - (Optional) The current deleted state of the role.

## Import

Customized IAM project role can be imported using their URI, e.g.
Expand Down