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

resource/aws_iam_policy_attachment: Bypass NoSuchEntity error when detaching groups, roles, and users (support group, role, and user renames) #9278

Merged
merged 3 commits into from
Jul 10, 2019
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
9 changes: 9 additions & 0 deletions aws/resource_aws_iam_policy_attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,9 @@ func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) error {
UserName: u,
PolicyArn: aws.String(arn),
})
if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
continue
}
if err != nil {
return err
}
Expand All @@ -348,6 +351,9 @@ func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) error {
RoleName: r,
PolicyArn: aws.String(arn),
})
if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
continue
}
if err != nil {
return err
}
Expand All @@ -360,6 +366,9 @@ func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) error {
GroupName: g,
PolicyArn: aws.String(arn),
})
if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
continue
}
if err != nil {
return err
}
Expand Down
204 changes: 204 additions & 0 deletions aws/resource_aws_iam_policy_attachment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,99 @@ func TestAccAWSIAMPolicyAttachment_paginatedEntities(t *testing.T) {
})
}

func TestAccAWSIAMPolicyAttachment_Groups_RenamedGroup(t *testing.T) {
var out iam.ListEntitiesForPolicyOutput

rName := acctest.RandomWithPrefix("tf-acc-test")
groupName1 := fmt.Sprintf("%s-1", rName)
groupName2 := fmt.Sprintf("%s-2", rName)
resourceName := "aws_iam_policy_attachment.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSPolicyAttachmentDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSIamPolicyAttachmentConfigGroupsRenamedGroup(rName, groupName1),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSPolicyAttachmentExists(resourceName, 1, &out),
testAccCheckAWSPolicyAttachmentAttributes([]string{}, []string{}, []string{groupName1}, &out),
),
},
{
Config: testAccAWSIamPolicyAttachmentConfigGroupsRenamedGroup(rName, groupName2),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSPolicyAttachmentExists(resourceName, 1, &out),
testAccCheckAWSPolicyAttachmentAttributes([]string{}, []string{}, []string{groupName2}, &out),
),
},
},
})
}

func TestAccAWSIAMPolicyAttachment_Roles_RenamedRole(t *testing.T) {
var out iam.ListEntitiesForPolicyOutput

rName := acctest.RandomWithPrefix("tf-acc-test")
roleName1 := fmt.Sprintf("%s-1", rName)
roleName2 := fmt.Sprintf("%s-2", rName)
resourceName := "aws_iam_policy_attachment.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSPolicyAttachmentDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSIamPolicyAttachmentConfigRolesRenamedRole(rName, roleName1),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSPolicyAttachmentExists(resourceName, 1, &out),
testAccCheckAWSPolicyAttachmentAttributes([]string{}, []string{roleName1}, []string{}, &out),
),
},
{
Config: testAccAWSIamPolicyAttachmentConfigRolesRenamedRole(rName, roleName2),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSPolicyAttachmentExists(resourceName, 1, &out),
testAccCheckAWSPolicyAttachmentAttributes([]string{}, []string{roleName2}, []string{}, &out),
),
},
},
})
}

func TestAccAWSIAMPolicyAttachment_Users_RenamedUser(t *testing.T) {
var out iam.ListEntitiesForPolicyOutput

rName := acctest.RandomWithPrefix("tf-acc-test")
userName1 := fmt.Sprintf("%s-1", rName)
userName2 := fmt.Sprintf("%s-2", rName)
resourceName := "aws_iam_policy_attachment.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSPolicyAttachmentDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSIamPolicyAttachmentConfigUsersRenamedUser(rName, userName1),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSPolicyAttachmentExists(resourceName, 1, &out),
testAccCheckAWSPolicyAttachmentAttributes([]string{userName1}, []string{}, []string{}, &out),
),
},
{
Config: testAccAWSIamPolicyAttachmentConfigUsersRenamedUser(rName, userName2),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSPolicyAttachmentExists(resourceName, 1, &out),
testAccCheckAWSPolicyAttachmentAttributes([]string{userName2}, []string{}, []string{}, &out),
),
},
},
})
}

func testAccCheckAWSPolicyAttachmentDestroy(s *terraform.State) error {
return nil
}
Expand Down Expand Up @@ -483,3 +576,114 @@ resource "aws_iam_policy_attachment" "test-paginated-attach" {
}
`, userNamePrefix, policyName, attachmentName)
}

func testAccAWSIamPolicyAttachmentConfigGroupsRenamedGroup(rName, groupName string) string {
return fmt.Sprintf(`
resource "aws_iam_policy" "test" {
name = %[1]q

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "*",
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}

resource "aws_iam_group" "test" {
name = %[2]q
}

resource "aws_iam_policy_attachment" "test" {
groups = ["${aws_iam_group.test.name}"]
name = %[1]q
policy_arn = "${aws_iam_policy.test.arn}"
}
`, rName, groupName)
}

func testAccAWSIamPolicyAttachmentConfigRolesRenamedRole(rName, roleName string) string {
return fmt.Sprintf(`
resource "aws_iam_policy" "test" {
name = %[1]q

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "*",
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}

resource "aws_iam_role" "test" {
force_detach_policies = true
name = %[2]q

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_iam_policy_attachment" "test" {
name = %[1]q
policy_arn = "${aws_iam_policy.test.arn}"
roles = ["${aws_iam_role.test.name}"]
}
`, rName, roleName)
}

func testAccAWSIamPolicyAttachmentConfigUsersRenamedUser(rName, userName string) string {
return fmt.Sprintf(`
resource "aws_iam_policy" "test" {
name = %[1]q

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "*",
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}

resource "aws_iam_user" "test" {
force_destroy = true
name = %[2]q
}

resource "aws_iam_policy_attachment" "test" {
name = %[1]q
policy_arn = "${aws_iam_policy.test.arn}"
users = ["${aws_iam_user.test.name}"]
}
`, rName, userName)
}
2 changes: 2 additions & 0 deletions website/docs/r/iam_role.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ description: |-

Provides an IAM role.

~> *NOTE:* If policies are attached to the role via the [`aws_iam_policy_attachment` resource](/docs/providers/aws/r/iam_policy_attachment.html) and you are modifying the role `name` or `path`, the `force_detach_policies` argument must be set to `true` and applied before attempting the operation otherwise you will encounter a `DeleteConflict` error. The [`aws_iam_role_policy_attachment` resource (recommended)](/docs/providers/aws/r/iam_role_policy_attachment.html) does not have this requirement.

## Example Usage

```hcl
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/iam_user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ description: |-

Provides an IAM user.

~> *NOTE:* If policies are attached to the user via the [`aws_iam_policy_attachment` resource](/docs/providers/aws/r/iam_policy_attachment.html) and you are modifying the user `name` or `path`, the `force_destroy` argument must be set to `true` and applied before attempting the operation otherwise you will encounter a `DeleteConflict` error. The [`aws_iam_user_policy_attachment` resource (recommended)](/docs/providers/aws/r/iam_user_policy_attachment.html) does not have this requirement.

## Example Usage

```hcl
Expand Down