diff --git a/builtin/providers/aws/resource_aws_iam_group_membership.go b/builtin/providers/aws/resource_aws_iam_group_membership.go index 10556567c..6fd788a8e 100644 --- a/builtin/providers/aws/resource_aws_iam_group_membership.go +++ b/builtin/providers/aws/resource_aws_iam_group_membership.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -14,7 +13,7 @@ func resourceAwsIamGroupMembership() *schema.Resource { return &schema.Resource{ Create: resourceAwsIamGroupMembershipCreate, Read: resourceAwsIamGroupMembershipRead, - //Update: resourceAwsIamGroupMembershipUpdate, + Update: resourceAwsIamGroupMembershipUpdate, Delete: resourceAwsIamGroupMembershipDelete, Schema: map[string]*schema.Schema{ @@ -43,18 +42,11 @@ func resourceAwsIamGroupMembership() *schema.Resource { func resourceAwsIamGroupMembershipCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn - userList := expandStringList(d.Get("users").(*schema.Set).List()) group := d.Get("group").(string) + userList := expandStringList(d.Get("users").(*schema.Set).List()) - for _, u := range userList { - _, err := conn.AddUserToGroup(&iam.AddUserToGroupInput{ - UserName: u, - GroupName: aws.String(group), - }) - - if err != nil { - return err - } + if err := addUsersToGroup(conn, userList, group); err != nil { + return err } d.SetId(d.Get("name").(string)) @@ -63,16 +55,19 @@ func resourceAwsIamGroupMembershipCreate(d *schema.ResourceData, meta interface{ func resourceAwsIamGroupMembershipRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn + group := d.Get("group").(string) resp, err := conn.GetGroup(&iam.GetGroupInput{ - GroupName: aws.String(d.Get("group").(string)), + GroupName: aws.String(group), }) if err != nil { if awsErr, ok := err.(awserr.Error); ok { // aws specific error - log.Printf("\n\n------\n AWS Error: %s :::: %s", awsErr.Code(), awsErr.Message()) - // group not found - d.SetId("") + if awsErr.Code() == "NoSuchEntity" { + // group not found + d.SetId("") + return nil + } } return err } @@ -83,18 +78,58 @@ func resourceAwsIamGroupMembershipRead(d *schema.ResourceData, meta interface{}) } if err := d.Set("users", ul); err != nil { - return fmt.Errorf("[WARN] Error setting user list from IAM Group Membership (%s), error: %s", err) + return fmt.Errorf("[WARN] Error setting user list from IAM Group Membership (%s), error: %s", group, err) } return nil } +func resourceAwsIamGroupMembershipUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + + if d.HasChange("users") { + group := d.Get("group").(string) + + o, n := d.GetChange("users") + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) + } + + os := o.(*schema.Set) + ns := n.(*schema.Set) + remove := expandStringList(os.Difference(ns).List()) + add := expandStringList(ns.Difference(os).List()) + + if err := removeUsersFromGroup(conn, remove, group); err != nil { + return err + } + + if err := addUsersToGroup(conn, add, group); err != nil { + return err + } + } + + return resourceAwsIamGroupMembershipRead(d, meta) +} + func resourceAwsIamGroupMembershipDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn userList := expandStringList(d.Get("users").(*schema.Set).List()) group := d.Get("group").(string) - for _, u := range userList { + if err := removeUsersFromGroup(conn, userList, group); err != nil { + return err + } + + d.SetId("") + return nil +} + +func removeUsersFromGroup(conn *iam.IAM, users []*string, group string) error { + for _, u := range users { _, err := conn.RemoveUserFromGroup(&iam.RemoveUserFromGroupInput{ UserName: u, GroupName: aws.String(group), @@ -104,7 +139,19 @@ func resourceAwsIamGroupMembershipDelete(d *schema.ResourceData, meta interface{ return err } } - - d.SetId("") + return nil +} + +func addUsersToGroup(conn *iam.IAM, users []*string, group string) error { + for _, u := range users { + _, err := conn.AddUserToGroup(&iam.AddUserToGroupInput{ + UserName: u, + GroupName: aws.String(group), + }) + + if err != nil { + return err + } + } return nil } diff --git a/builtin/providers/aws/resource_aws_iam_group_membership_test.go b/builtin/providers/aws/resource_aws_iam_group_membership_test.go index a24ac1a74..91573c588 100644 --- a/builtin/providers/aws/resource_aws_iam_group_membership_test.go +++ b/builtin/providers/aws/resource_aws_iam_group_membership_test.go @@ -11,7 +11,7 @@ import ( ) func TestAccAWSGroupMembership_basic(t *testing.T) { - var group iam.Group + var group iam.GetGroupOutput resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -22,7 +22,15 @@ func TestAccAWSGroupMembership_basic(t *testing.T) { Config: testAccAWSGroupMemberConfig, Check: resource.ComposeTestCheckFunc( testAccCheckAWSGroupMembershipExists("aws_iam_group_membership.team", &group), - testAccCheckAWSGroupMembershipAttributes(&group), + testAccCheckAWSGroupMembershipAttributes(&group, []string{"test-user"}), + ), + }, + + resource.TestStep{ + Config: testAccAWSGroupMemberConfigUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGroupMembershipExists("aws_iam_group_membership.team", &group), + testAccCheckAWSGroupMembershipAttributes(&group, []string{"test-user-two", "test-user-three"}), ), }, }, @@ -37,7 +45,6 @@ func testAccCheckAWSGroupMembershipDestroy(s *terraform.State) error { continue } - // Try to get user group := rs.Primary.Attributes["group"] _, err := conn.GetGroup(&iam.GetGroupInput{ @@ -55,7 +62,7 @@ func testAccCheckAWSGroupMembershipDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSGroupMembershipExists(n string, g *iam.Group) resource.TestCheckFunc { +func testAccCheckAWSGroupMembershipExists(n string, g *iam.GetGroupOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -77,16 +84,29 @@ func testAccCheckAWSGroupMembershipExists(n string, g *iam.Group) resource.TestC return fmt.Errorf("Error: Group (%s) not found", gn) } - *g = *resp.Group + *g = *resp return nil } } -func testAccCheckAWSGroupMembershipAttributes(group *iam.Group) resource.TestCheckFunc { +func testAccCheckAWSGroupMembershipAttributes(group *iam.GetGroupOutput, users []string) resource.TestCheckFunc { return func(s *terraform.State) error { - if *group.GroupName != "test-group" { - return fmt.Errorf("Bad group membership: expected %s, got %s", "test-group-update", *group.GroupName) + if *group.Group.GroupName != "test-group" { + return fmt.Errorf("Bad group membership: expected %s, got %s", "test-group-update", *group.Group.GroupName) + } + + uc := len(users) + for _, u := range users { + for _, gu := range group.Users { + if u == *gu.UserName { + uc-- + } + } + } + + if uc > 0 { + return fmt.Errorf("Bad group membership count, expected (%d), but only (%d) found", len(users), uc) } return nil } @@ -109,3 +129,34 @@ resource "aws_iam_group_membership" "team" { group = "${aws_iam_group.group.name}" } ` + +const testAccAWSGroupMemberConfigUpdate = ` +resource "aws_iam_group" "group" { + name = "test-group" + path = "/" +} + +resource "aws_iam_user" "user" { + name = "test-user" + path = "/" +} + +resource "aws_iam_user" "user_two" { + name = "test-user-two" + path = "/" +} + +resource "aws_iam_user" "user_three" { + name = "test-user-three" + path = "/" +} + +resource "aws_iam_group_membership" "team" { + name = "tf-testing-group-membership" + users = [ + "${aws_iam_user.user_two.name}", + "${aws_iam_user.user_three.name}", + ] + group = "${aws_iam_group.group.name}" +} +`