From 2b7e3d0b517a009f1a4ccf3a861ae2d32e7802ed Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Fri, 12 Jun 2015 12:44:35 -0400 Subject: [PATCH 01/12] commit create and delete with a start of test --- .../aws/resource_aws_iam_policy_attach.go | 185 ++++++++++++++++++ .../resource_aws_iam_policy_attach_test.go | 14 ++ 2 files changed, 199 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_iam_policy_attach.go create mode 100644 builtin/providers/aws/resource_aws_iam_policy_attach_test.go diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach.go b/builtin/providers/aws/resource_aws_iam_policy_attach.go new file mode 100644 index 000000000..5ac2c5c50 --- /dev/null +++ b/builtin/providers/aws/resource_aws_iam_policy_attach.go @@ -0,0 +1,185 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsIamPolicyAttach() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsIamPolicyAttachCreate, + Read: resourceAwsIamPolicyAttachRead, + Update: resourceAwsIamPolicyAttachUpdate, + Delete: resourceAwsIamPolicyAttachDelete, + + Schema: map[]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "users": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "roles": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "groups": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "arn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceAwsIamPolicyAttachCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + + name := d.Get("name").(string) + arn := d.Get("arn").(string) + users := expandStringList(d.Get("users").(*schema.Set).List()) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + groups := expandStringList(d.Get("groups").(*schema.Set).List()) + + if users == nil && roles == nil && groups == nil { + return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for %s", d.Get("name").(string)) + } + else { + var userErr, roleErr, groupErr error + if users != nil { + userErr = attachPolicyToUsers(conn, users, arn) + } + if roles != nil { + roleErr = attachPolicyToRoles(conn, roles, arn) + } + if groups != nil { + groupErr = attachPolicyToGroups(conn, groups, arn) + } + if userErr != nil || roleErr != nil || groupErr != nil { + return fmt.Errorf("[WARN] Error attaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) + } + } + return resourceAwsIamPolicyAttachRead(d, meta) +} +func resourceAwsIamPolicyAttachRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + users := expandStringList(d.Get("users").(*schema.Set).List()) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + groups := expandStringList(d.Get("groups").(*schema.Set).List()) + + + return nil +} +func resourceAwsIamPolicyAttachUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + + return nil +} +func resourceAwsIamPolicyAttachDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + name := d.Get("name").(string) + arn := d.Id() + users := expandStringList(d.Get("users").(*schema.Set).List()) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + groups := expandStringList(d.Get("groups").(*schema.Set).List()) + + var userErr, roleErr, groupErr error + if users != nil { + userErr = detachPolicyFromUsers(conn, users, arn) + } + if roles != nil { + roleErr = detachPolicyFromRoles(conn, roles, arn) + } + if groups != nil { + groupErr = detachPolicyFromGroups(conn, groups, arn) + } + if userErr != nil || roleErr != nil || groupErr != nil { + return fmt.Errorf("Error detaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\ groups - %v", name, userErr, roleErr, groupErr) + } + return nil +} +func attachPolicyToUsers (conn *iam.IAM, users []*string, arn string) { + for _, u := range users { + _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicy{ + GroupName: u, + PolicyArn: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil +} +func attachPolicyToRoles (conn *iam.IAM, roles []*string, arn string) { + for _, r := range roles { + _, err := conn.AttachRolePolicy(&iam.AttachRolePolicy{ + RoleName: u, + PolicyArn: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil + +} +func attachPolicyToGroups (conn *iam.IAM, groups []*string, arn string) { + for _, g := range groups { + _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicy{ + GroupName: g, + PolicyArn: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil +} +func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) { + for _, u := range users { + _, err := conn.DetachUserPolicy(&iam.DetachUserPolicy{ + UserName: u, + PolicyArn: aws.String(arn), + } + if err != nil { + return err + } + } + return nil +} +func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) { + for _, r := range roles { + _, err := conn.DetachRolePolicy(&iam.DetachRolePolicy{ + RoleName: r, + PolicyArn: aws.String(arn), + } + if err != nil { + return err + } + } + return nil +} +func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) { + for _, g := range groups { + _, err := conn.DetachGroupPolicy(&iam.DetachGroupPolicy{ + GroupName: g, + PolicyArn: aws.String(arn), + } + if err != nil { + return err + } + } + return nil +} diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach_test.go b/builtin/providers/aws/resource_aws_iam_policy_attach_test.go new file mode 100644 index 000000000..fa43009ef --- /dev/null +++ b/builtin/providers/aws/resource_aws_iam_policy_attach_test.go @@ -0,0 +1,14 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "testing" +) + +const testAccAWSPolicyAttachConfig = ` + +` From 73e8191983bfe2017ecaccda46dea601b8bad1ae Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Tue, 16 Jun 2015 16:10:45 -0400 Subject: [PATCH 02/12] add to provider --- builtin/providers/aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 3e517d71f..44082a59c 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -106,6 +106,7 @@ func Provider() terraform.ResourceProvider { "aws_iam_group_membership": resourceAwsIamGroupMembership(), "aws_iam_instance_profile": resourceAwsIamInstanceProfile(), "aws_iam_policy": resourceAwsIamPolicy(), + "aws_iam_policy_attachment": resourceAwsIamPolicyAttachment(), "aws_iam_role_policy": resourceAwsIamRolePolicy(), "aws_iam_role": resourceAwsIamRole(), "aws_iam_server_certificate": resourceAwsIAMServerCertificate(), From 2135ff02b781cf0d143d7ace3d68341ecd2da880 Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Wed, 17 Jun 2015 10:56:33 -0400 Subject: [PATCH 03/12] add works but need tests --- .../aws/resource_aws_iam_policy_attach.go | 448 +++++++++++------- .../resource_aws_iam_policy_attach_test.go | 144 +++++- 2 files changed, 431 insertions(+), 161 deletions(-) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach.go b/builtin/providers/aws/resource_aws_iam_policy_attach.go index 5ac2c5c50..218715a82 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attach.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attach.go @@ -1,185 +1,313 @@ package aws import ( - "fmt" - "github.com/aws/aws-sdk-go/aws" + "fmt" + + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/iam" "github.com/hashicorp/terraform/helper/schema" ) -func resourceAwsIamPolicyAttach() *schema.Resource { - return &schema.Resource{ - Create: resourceAwsIamPolicyAttachCreate, - Read: resourceAwsIamPolicyAttachRead, - Update: resourceAwsIamPolicyAttachUpdate, - Delete: resourceAwsIamPolicyAttachDelete, +func resourceAwsIamPolicyAttachment() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsIamPolicyAttachmentCreate, + Read: resourceAwsIamPolicyAttachmentRead, + Update: resourceAwsIamPolicyAttachmentUpdate, + Delete: resourceAwsIamPolicyAttachmentDelete, - Schema: map[]*schema.Schema{ - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "users": &schema.Schema{ - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "roles": &schema.Schema{ - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "groups": &schema.Schema{ - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "arn": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - }, - } + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "users": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "roles": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "groups": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "policy_arn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } } -func resourceAwsIamPolicyAttachCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).iamconn +func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn - name := d.Get("name").(string) - arn := d.Get("arn").(string) - users := expandStringList(d.Get("users").(*schema.Set).List()) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - groups := expandStringList(d.Get("groups").(*schema.Set).List()) + name := d.Get("name").(string) + arn := d.Get("policy_arn").(string) + users := expandStringList(d.Get("users").(*schema.Set).List()) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + groups := expandStringList(d.Get("groups").(*schema.Set).List()) - if users == nil && roles == nil && groups == nil { - return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for %s", d.Get("name").(string)) - } - else { - var userErr, roleErr, groupErr error - if users != nil { - userErr = attachPolicyToUsers(conn, users, arn) - } - if roles != nil { - roleErr = attachPolicyToRoles(conn, roles, arn) - } - if groups != nil { - groupErr = attachPolicyToGroups(conn, groups, arn) - } - if userErr != nil || roleErr != nil || groupErr != nil { - return fmt.Errorf("[WARN] Error attaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) - } - } - return resourceAwsIamPolicyAttachRead(d, meta) + if users == nil && roles == nil && groups == nil { + return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for %s", name) + } else { + var userErr, roleErr, groupErr error + if users != nil { + userErr = attachPolicyToUsers(conn, users, arn) + } + if roles != nil { + roleErr = attachPolicyToRoles(conn, roles, arn) + } + if groups != nil { + groupErr = attachPolicyToGroups(conn, groups, arn) + } + if userErr != nil || roleErr != nil || groupErr != nil { + return fmt.Errorf("[WARN] Error attaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) + } + } + return resourceAwsIamPolicyAttachmentRead(d, meta) } -func resourceAwsIamPolicyAttachRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).iamconn - users := expandStringList(d.Get("users").(*schema.Set).List()) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - groups := expandStringList(d.Get("groups").(*schema.Set).List()) +func resourceAwsIamPolicyAttachmentRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + arn := d.Get("policy_arn").(string) + name := d.Get("name").(string) + _, err := conn.GetPolicy(&iam.GetPolicyInput{ + PolicyARN: aws.String(arn), + }) - return nil -} -func resourceAwsIamPolicyAttachUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).iamconn + if err != nil { + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "NoSuchIdentity" { + d.SetId("") + return nil + } + } + return err + } - return nil + policyEntities, err := conn.ListEntitiesForPolicy(&iam.ListEntitiesForPolicyInput{ + PolicyARN: aws.String(arn), + }) + + if err != nil { + return err + } + + ul := make([]string, 0, len(policyEntities.PolicyUsers)) + rl := make([]string, 0, len(policyEntities.PolicyRoles)) + gl := make([]string, 0, len(policyEntities.PolicyGroups)) + + for _, u := range policyEntities.PolicyUsers { + ul = append(ul, *u.UserName) + } + + for _, r := range policyEntities.PolicyRoles { + rl = append(rl, *r.RoleName) + } + + for _, g := range policyEntities.PolicyGroups { + gl = append(gl, *g.GroupName) + } + + userErr := d.Set("users", ul) + roleErr := d.Set("roles", rl) + groupErr := d.Set("groups", gl) + + if userErr != nil || roleErr != nil || groupErr != nil { + return fmt.Errorf("[WARN} Error setting user, role, or group list from IAM Policy Attach (%s):\n user error - %s\n role error - %s\n group error - %s", name, userErr, roleErr, groupErr) + } + + return nil } -func resourceAwsIamPolicyAttachDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).iamconn - name := d.Get("name").(string) - arn := d.Id() - users := expandStringList(d.Get("users").(*schema.Set).List()) - roles := expandStringList(d.Get("roles").(*schema.Set).List()) - groups := expandStringList(d.Get("groups").(*schema.Set).List()) - - var userErr, roleErr, groupErr error - if users != nil { - userErr = detachPolicyFromUsers(conn, users, arn) - } - if roles != nil { - roleErr = detachPolicyFromRoles(conn, roles, arn) - } - if groups != nil { - groupErr = detachPolicyFromGroups(conn, groups, arn) - } - if userErr != nil || roleErr != nil || groupErr != nil { - return fmt.Errorf("Error detaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\ groups - %v", name, userErr, roleErr, groupErr) - } - return nil +func resourceAwsIamPolicyAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + name := d.Get("name").(string) + var userErr, roleErr, groupErr error + + if d.HasChange("users") { + userErr = updateUsers(conn, d, meta) + } + if d.HasChange("roles") { + roleErr = updateRoles(conn, d, meta) + } + if d.HasChange("groups") { + groupErr = updateGroups(conn, d, meta) + } + if userErr != nil || roleErr != nil || groupErr != nil { + return fmt.Errorf("[WARN] Error updating user, role, or group list from IAM Policy Attach (%s):\n user error - %s\n role error - %s\n group error - %s", name, userErr, roleErr, groupErr) + } + return nil } -func attachPolicyToUsers (conn *iam.IAM, users []*string, arn string) { - for _, u := range users { - _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicy{ - GroupName: u, - PolicyArn: aws.String(arn), - }) - if err != nil { - return err - } - } - return nil +func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + name := d.Get("name").(string) + arn := d.Get("policy_arn").(string) + users := expandStringList(d.Get("users").(*schema.Set).List()) + roles := expandStringList(d.Get("roles").(*schema.Set).List()) + groups := expandStringList(d.Get("groups").(*schema.Set).List()) + + var userErr, roleErr, groupErr error + if users != nil { + userErr = detachPolicyFromUsers(conn, users, arn) + } + if roles != nil { + roleErr = detachPolicyFromRoles(conn, roles, arn) + } + if groups != nil { + groupErr = detachPolicyFromGroups(conn, groups, arn) + } + if userErr != nil || roleErr != nil || groupErr != nil { + return fmt.Errorf("[WARN] Error removing user, role, or group list from IAM Policy Detach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) + } + return nil } -func attachPolicyToRoles (conn *iam.IAM, roles []*string, arn string) { - for _, r := range roles { - _, err := conn.AttachRolePolicy(&iam.AttachRolePolicy{ - RoleName: u, - PolicyArn: aws.String(arn), - }) - if err != nil { - return err - } - } - return nil +func attachPolicyToUsers(conn *iam.IAM, users []*string, arn string) error { + for _, u := range users { + _, err := conn.AttachUserPolicy(&iam.AttachUserPolicyInput{ + UserName: u, + PolicyARN: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil +} +func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error { + for _, r := range roles { + _, err := conn.AttachRolePolicy(&iam.AttachRolePolicyInput{ + RoleName: r, + PolicyARN: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil +} +func attachPolicyToGroups(conn *iam.IAM, groups []*string, arn string) error { + for _, g := range groups { + _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicyInput{ + GroupName: g, + PolicyARN: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil +} +func updateUsers(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { + arn := d.Get("policy_arn").(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 rErr := detachPolicyFromUsers(conn, remove, arn); rErr != nil { + return rErr + } + if aErr := attachPolicyToUsers(conn, add, arn); aErr != nil { + return aErr + } + return nil +} +func updateRoles(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { + arn := d.Get("policy_arn").(string) + o, n := d.GetChange("roles") + 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 rErr := detachPolicyFromRoles(conn, remove, arn); rErr != nil { + return rErr + } + if aErr := attachPolicyToRoles(conn, add, arn); aErr != nil { + return aErr + } + return nil +} +func updateGroups(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { + arn := d.Get("policy_arn").(string) + o, n := d.GetChange("groups") + 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 rErr := detachPolicyFromGroups(conn, remove, arn); rErr != nil { + return rErr + } + if aErr := attachPolicyToGroups(conn, add, arn); aErr != nil { + return aErr + } + return nil } -func attachPolicyToGroups (conn *iam.IAM, groups []*string, arn string) { - for _, g := range groups { - _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicy{ - GroupName: g, - PolicyArn: aws.String(arn), - }) - if err != nil { - return err - } - } - return nil +func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) error { + for _, u := range users { + _, err := conn.DetachUserPolicy(&iam.DetachUserPolicyInput{ + UserName: u, + PolicyARN: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil } -func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) { - for _, u := range users { - _, err := conn.DetachUserPolicy(&iam.DetachUserPolicy{ - UserName: u, - PolicyArn: aws.String(arn), - } - if err != nil { - return err - } - } - return nil +func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) error { + for _, r := range roles { + _, err := conn.DetachRolePolicy(&iam.DetachRolePolicyInput{ + RoleName: r, + PolicyARN: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil } -func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) { - for _, r := range roles { - _, err := conn.DetachRolePolicy(&iam.DetachRolePolicy{ - RoleName: r, - PolicyArn: aws.String(arn), - } - if err != nil { - return err - } - } - return nil -} -func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) { - for _, g := range groups { - _, err := conn.DetachGroupPolicy(&iam.DetachGroupPolicy{ - GroupName: g, - PolicyArn: aws.String(arn), - } - if err != nil { - return err - } - } - return nil +func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) error { + for _, g := range groups { + _, err := conn.DetachGroupPolicy(&iam.DetachGroupPolicyInput{ + GroupName: g, + PolicyARN: aws.String(arn), + }) + if err != nil { + return err + } + } + return nil } diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach_test.go b/builtin/providers/aws/resource_aws_iam_policy_attach_test.go index fa43009ef..a025f5205 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attach_test.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attach_test.go @@ -9,6 +9,148 @@ import ( "testing" ) -const testAccAWSPolicyAttachConfig = ` +func TestAccAWSPolicyAttach_basic(t *testing.T) { + var policy iam.GetPolicyOutput + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSPolicyAttachmentDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSPolicyAttachConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSPolicyAttachmentExists(), + testAccCheckAWSPolicyAttachmentAttributes(), + ), + }, + resource.TestStep{ + Config: testAccAWSPolicyAttachConfigUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSPolicyAttachmentExists(), + testAccCheckAWSPolicyAttachmentAttributes(), + ), + }, + }, + }) +} + +func testAccCheckAWSPolicyAttachmentDestroy(s *terraform.State) error { + + return nil +} + +func testAccCheckAWSPolicyAttachmentExists(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).iamconn + + return nil +} +func testAccCheckAWSPolicyAttachmentAttributes() error { + + return nil +} + +const testAccAWSPolicyAttachConfig = ` +resource "aws_iam_user" "user" { + name = "test-user" +} +resource "aws_iam_role" "role" { + name = "test-role" +} +resource "aws_iam_group" "group" { + name = "test-group" +} + +resource "aws_iam_policy" "policy" { + name = "test-policy" + description = "A test policy" + policy = < Date: Wed, 17 Jun 2015 15:21:41 -0400 Subject: [PATCH 04/12] seems to work --- builtin/providers/aws/resource_aws_iam_policy_attach.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach.go b/builtin/providers/aws/resource_aws_iam_policy_attach.go index 218715a82..ecc3f307f 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attach.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attach.go @@ -75,8 +75,10 @@ func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface return fmt.Errorf("[WARN] Error attaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) } } + d.SetId(d.Get("name").(string)) return resourceAwsIamPolicyAttachmentRead(d, meta) } + func resourceAwsIamPolicyAttachmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn arn := d.Get("policy_arn").(string) @@ -147,8 +149,9 @@ func resourceAwsIamPolicyAttachmentUpdate(d *schema.ResourceData, meta interface if userErr != nil || roleErr != nil || groupErr != nil { return fmt.Errorf("[WARN] Error updating user, role, or group list from IAM Policy Attach (%s):\n user error - %s\n role error - %s\n group error - %s", name, userErr, roleErr, groupErr) } - return nil + return resourceAwsIamPolicyAttachmentRead(d, meta) } + func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn name := d.Get("name").(string) From 3266c44b83c95f1901ae8a6f0f203fb3ca2f5c43 Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Thu, 18 Jun 2015 10:53:52 -0400 Subject: [PATCH 05/12] rename to more intuitive name and finish tests --- ... => resource_aws_iam_policy_attachment.go} | 0 ...esource_aws_iam_policy_attachment_test.go} | 84 +++++++++++++++---- 2 files changed, 70 insertions(+), 14 deletions(-) rename builtin/providers/aws/{resource_aws_iam_policy_attach.go => resource_aws_iam_policy_attachment.go} (100%) rename builtin/providers/aws/{resource_aws_iam_policy_attach_test.go => resource_aws_iam_policy_attachment_test.go} (51%) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach.go b/builtin/providers/aws/resource_aws_iam_policy_attachment.go similarity index 100% rename from builtin/providers/aws/resource_aws_iam_policy_attach.go rename to builtin/providers/aws/resource_aws_iam_policy_attachment.go diff --git a/builtin/providers/aws/resource_aws_iam_policy_attach_test.go b/builtin/providers/aws/resource_aws_iam_policy_attachment_test.go similarity index 51% rename from builtin/providers/aws/resource_aws_iam_policy_attach_test.go rename to builtin/providers/aws/resource_aws_iam_policy_attachment_test.go index a025f5205..fe8fe9e1e 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attach_test.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attachment_test.go @@ -9,8 +9,8 @@ import ( "testing" ) -func TestAccAWSPolicyAttach_basic(t *testing.T) { - var policy iam.GetPolicyOutput +func TestAccAWSPolicyAttachment_basic(t *testing.T) { + var out iam.GetPolicyOutput resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -20,34 +20,90 @@ func TestAccAWSPolicyAttach_basic(t *testing.T) { resource.TestStep{ Config: testAccAWSPolicyAttachConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSPolicyAttachmentExists(), - testAccCheckAWSPolicyAttachmentAttributes(), + testAccCheckAWSPolicyAttachmentExists("aws_iam_policy_attachment.test-attachment", 3, &out), + testAccCheckAWSPolicyAttachmentAttributes([]string{"test-user"}, []string{"test-role"}, []string{"test-group"}, &out), ), }, resource.TestStep{ Config: testAccAWSPolicyAttachConfigUpdate, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSPolicyAttachmentExists(), - testAccCheckAWSPolicyAttachmentAttributes(), + testAccCheckAWSPolicyAttachmentExists("aws_iam_policy_attachment.test-attachment", 6, &out), + testAccCheckAWSPolicyAttachmentAttributes([]string{"test-user3", "test-user3"}, []string{"test-role2", "test-role3"}, []string{"test-group2", "test-group3"}, &out), ), }, }, }) } - func testAccCheckAWSPolicyAttachmentDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSPolicyAttachmentExists(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).iamconn +func testAccCheckAWSPolicyAttachmentExists(n string, c int, out *iam.ListEntitiesForPolicyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } - return nil + if rs.Primary.ID == "" { + return fmt.Errorf("No policy name is set") + } + + conn := testAccProvider.Meta().(*AWSClient).iamconn + arn := rs.Primary.Attributes["policy_arn"] + + resp, err := conn.GetPolicy(&iam.GetPolicyInput{ + PolicyARN: aws.String(arn), + }) + if err != nil { + return fmt.Errorf("Error: Policy (%s) not found", n) + } + if c != resp.Policy.AttachmentCount { + return fmt.Errorf("Error: Policy (%s) has wrong number of entities attached on initial creation", n) + } + resp2, err := conn.ListEntitiesForPolicy(&iam.ListEntitiesForPolicyOutput{ + PolicyARN: aws.String(arn), + }) + if err != nil { + return fmt.Errorf("Error: Failed to get entities for Policy (%s)", arn) + } + + *out = *resp2 + return nil + } } -func testAccCheckAWSPolicyAttachmentAttributes() error { +func testAccCheckAWSPolicyAttachmentAttributes(users []string, roles []string, groups []string, out *iam.ListEntitiesForPolicyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + uc := len(u) + rc := len(r) + gc := len(g) - return nil + for _, u := range users { + for _, pu := range out.PolicyUsers { + if u == *pu.UserName { + uc-- + } + } + } + for _, r := range roles { + for _, pr := range out.PolicyRoles { + if r == *pu.RoleName { + rc-- + } + } + } + for _, g := range users { + for _, pg := range out.PolicyGroups { + if g == *pu.GroupName { + gc-- + } + } + } + if uc != 0 || rc != 0 || gc != 0 { + return fmt.Errorf("Error: Number of attached users, roles, or groups was incorrect:\n expected %d users and found %d\nexpected %d roles and found %d\nexpected %d groups and found %d", len(users), (len(users) - uc), len(roles), (len(roles) - rc), len(groups), (len(groups) - gc)) + } + } } const testAccAWSPolicyAttachConfig = ` @@ -80,7 +136,7 @@ resource "aws_iam_policy" "policy" { EOF } -resource "aws_iam_policy_attach" "test-attach" { +resource "aws_iam_policy_attachment" "test-attach" { name = "test-attachment" users = ["${aws_iam_user.user.name}"] roles = ["${aws_iam_role.role.name}"] @@ -137,7 +193,7 @@ resource "aws_iam_policy" "policy" { EOF } -resource "aws_iam_policy_attach" "test-attach" { +resource "aws_iam_policy_attachment" "test-attach" { name = "test-attachment" users = [ "${aws_iam_user.user2.name}", From 24e2cfb26006b85e0c2ced1b00eec76a51ca173d Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Thu, 18 Jun 2015 11:10:14 -0400 Subject: [PATCH 06/12] test works --- ...resource_aws_iam_policy_attachment_test.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attachment_test.go b/builtin/providers/aws/resource_aws_iam_policy_attachment_test.go index fe8fe9e1e..3e6ef445d 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attachment_test.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attachment_test.go @@ -10,7 +10,7 @@ import ( ) func TestAccAWSPolicyAttachment_basic(t *testing.T) { - var out iam.GetPolicyOutput + var out iam.ListEntitiesForPolicyOutput resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -39,7 +39,7 @@ func testAccCheckAWSPolicyAttachmentDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSPolicyAttachmentExists(n string, c int, out *iam.ListEntitiesForPolicyOutput) resource.TestCheckFunc { +func testAccCheckAWSPolicyAttachmentExists(n string, c int64, out *iam.ListEntitiesForPolicyOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -59,10 +59,10 @@ func testAccCheckAWSPolicyAttachmentExists(n string, c int, out *iam.ListEntitie if err != nil { return fmt.Errorf("Error: Policy (%s) not found", n) } - if c != resp.Policy.AttachmentCount { + if c != *resp.Policy.AttachmentCount { return fmt.Errorf("Error: Policy (%s) has wrong number of entities attached on initial creation", n) } - resp2, err := conn.ListEntitiesForPolicy(&iam.ListEntitiesForPolicyOutput{ + resp2, err := conn.ListEntitiesForPolicy(&iam.ListEntitiesForPolicyInput{ PolicyARN: aws.String(arn), }) if err != nil { @@ -75,9 +75,9 @@ func testAccCheckAWSPolicyAttachmentExists(n string, c int, out *iam.ListEntitie } func testAccCheckAWSPolicyAttachmentAttributes(users []string, roles []string, groups []string, out *iam.ListEntitiesForPolicyOutput) resource.TestCheckFunc { return func(s *terraform.State) error { - uc := len(u) - rc := len(r) - gc := len(g) + uc := len(users) + rc := len(roles) + gc := len(groups) for _, u := range users { for _, pu := range out.PolicyUsers { @@ -88,14 +88,14 @@ func testAccCheckAWSPolicyAttachmentAttributes(users []string, roles []string, g } for _, r := range roles { for _, pr := range out.PolicyRoles { - if r == *pu.RoleName { + if r == *pr.RoleName { rc-- } } } for _, g := range users { for _, pg := range out.PolicyGroups { - if g == *pu.GroupName { + if g == *pg.GroupName { gc-- } } @@ -103,6 +103,7 @@ func testAccCheckAWSPolicyAttachmentAttributes(users []string, roles []string, g if uc != 0 || rc != 0 || gc != 0 { return fmt.Errorf("Error: Number of attached users, roles, or groups was incorrect:\n expected %d users and found %d\nexpected %d roles and found %d\nexpected %d groups and found %d", len(users), (len(users) - uc), len(roles), (len(roles) - rc), len(groups), (len(groups) - gc)) } + return nil } } From fa0573b22c60ec54aabf93d143efdd988eb9679f Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Thu, 18 Jun 2015 11:37:12 -0400 Subject: [PATCH 07/12] add doc link to aws.erb --- website/source/layouts/aws.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 6cab799b1..07b7fc625 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -100,6 +100,9 @@ > aws_iam_policy + > + aws_iam_policy_attachment + > aws_iam_role From d1325b0dce3158938e48859ae529b9abcc0f46bb Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Thu, 18 Jun 2015 11:43:16 -0400 Subject: [PATCH 08/12] fix whitespace --- website/source/layouts/aws.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 07b7fc625..49ff076ea 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -100,7 +100,7 @@ > aws_iam_policy - > + > aws_iam_policy_attachment From 8abca07889089f4845ef0cb36d5f82a030a3a50f Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Thu, 18 Jun 2015 11:54:26 -0400 Subject: [PATCH 09/12] add markdown --- .../aws/r/iam_policy_attachment.html.markdown | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 website/source/docs/providers/aws/r/iam_policy_attachment.html.markdown diff --git a/website/source/docs/providers/aws/r/iam_policy_attachment.html.markdown b/website/source/docs/providers/aws/r/iam_policy_attachment.html.markdown new file mode 100644 index 000000000..4cc0e18cb --- /dev/null +++ b/website/source/docs/providers/aws/r/iam_policy_attachment.html.markdown @@ -0,0 +1,54 @@ +--- +layout: "aws" +page_title: "AWS: aws_iam_policy_attachment" +sidebar_current: "docs-aws-resource-iam-policy-attachment" +description: |- + Attaches a Managed IAM Policy to user(s), role(s), and/or group(s) +--- + +# aws\_iam\_policy\_attachment + +Attaches a Managed IAM Policy to user(s), role(s), and/or group(s) + +``` +resource "aws_iam_user" "user" { + name = "test-user" +} +resource "aws_iam_role" "role" { + name = "test-role" +} +resource "aws_iam_group" "group" { + name = "test-group" +} + +resource "aws_iam_policy" "policy" { + name = "test-policy" + description = "A test policy" + policy = #omitted +} + +resource "aws_iam_policy_attachment" "test-attach" { + name = "test-attachment" + users = ["${aws_iam_user.user.name}"] + roles = ["${aws_iam_role.role.name}"] + groups = ["${aws_iam_group.group.name}"] + policy_arn = "${aws_iam_policy.policy.arn}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` (Required) - The name of the policy. +* `users` (Optional) - The user(s) the policy should be applied to +* `roles (Optional) - The role(s) the policy should be applied to` +* `groups (Optional) - The group(s) the policy should be applied to` +* `policy_arn` (Required) - The ARN of the policy you want to apply + +## Attributes Reference + +The following attributes are exported: + +* `id` - The policy's ID. +* `name` - The name of the policy. From c375a72f15e9a040bbd5c95cb0a9ac0524e002e2 Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Sun, 28 Jun 2015 19:39:50 -0400 Subject: [PATCH 10/12] check for empty string instead of nil --- .../providers/aws/resource_aws_iam_policy_attachment.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attachment.go b/builtin/providers/aws/resource_aws_iam_policy_attachment.go index ecc3f307f..e2a5b51a9 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attachment.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attachment.go @@ -58,7 +58,7 @@ func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface roles := expandStringList(d.Get("roles").(*schema.Set).List()) groups := expandStringList(d.Get("groups").(*schema.Set).List()) - if users == nil && roles == nil && groups == nil { + if users == "" && roles == "" && groups == "" { return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for %s", name) } else { var userErr, roleErr, groupErr error @@ -161,13 +161,13 @@ func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface groups := expandStringList(d.Get("groups").(*schema.Set).List()) var userErr, roleErr, groupErr error - if users != nil { + if users != "" { userErr = detachPolicyFromUsers(conn, users, arn) } - if roles != nil { + if roles != "" { roleErr = detachPolicyFromRoles(conn, roles, arn) } - if groups != nil { + if groups != "" { groupErr = detachPolicyFromGroups(conn, groups, arn) } if userErr != nil || roleErr != nil || groupErr != nil { From 0f5c9c012df1d3da26a9ff80c13ec1f88efe2d17 Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Sun, 28 Jun 2015 20:00:55 -0400 Subject: [PATCH 11/12] check length of slices instead of using incorrect type --- .../aws/resource_aws_iam_policy_attachment.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attachment.go b/builtin/providers/aws/resource_aws_iam_policy_attachment.go index e2a5b51a9..18393565e 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attachment.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attachment.go @@ -58,7 +58,7 @@ func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface roles := expandStringList(d.Get("roles").(*schema.Set).List()) groups := expandStringList(d.Get("groups").(*schema.Set).List()) - if users == "" && roles == "" && groups == "" { + if len(users) > 0 && len(roles) > 0 && len(groups) > 0 { return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for %s", name) } else { var userErr, roleErr, groupErr error @@ -161,13 +161,13 @@ func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface groups := expandStringList(d.Get("groups").(*schema.Set).List()) var userErr, roleErr, groupErr error - if users != "" { + if len(users) != 0 { userErr = detachPolicyFromUsers(conn, users, arn) } - if roles != "" { + if len(roles) != 0 { roleErr = detachPolicyFromRoles(conn, roles, arn) } - if groups != "" { + if len(groups) != 0 { groupErr = detachPolicyFromGroups(conn, groups, arn) } if userErr != nil || roleErr != nil || groupErr != nil { @@ -175,6 +175,13 @@ func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface } return nil } + +//func composeErrors(desc string, uErr error, rErr error, gErr error) error { +// errMsg := fmt.Sprintf(desc) +// errs := []error{uErr, rErr, gErr} +// return nil +//} + func attachPolicyToUsers(conn *iam.IAM, users []*string, arn string) error { for _, u := range users { _, err := conn.AttachUserPolicy(&iam.AttachUserPolicyInput{ From 28506c3750e4e67d70068f021a369ee71c6f1aea Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Sun, 28 Jun 2015 22:30:54 -0400 Subject: [PATCH 12/12] add composeErrors function to only expose errors that happened --- .../aws/resource_aws_iam_policy_attachment.go | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/builtin/providers/aws/resource_aws_iam_policy_attachment.go b/builtin/providers/aws/resource_aws_iam_policy_attachment.go index 18393565e..a9028c57c 100644 --- a/builtin/providers/aws/resource_aws_iam_policy_attachment.go +++ b/builtin/providers/aws/resource_aws_iam_policy_attachment.go @@ -59,7 +59,7 @@ func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface groups := expandStringList(d.Get("groups").(*schema.Set).List()) if len(users) > 0 && len(roles) > 0 && len(groups) > 0 { - return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for %s", name) + return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for IAM Policy Attachment %s", name) } else { var userErr, roleErr, groupErr error if users != nil { @@ -72,7 +72,7 @@ func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface groupErr = attachPolicyToGroups(conn, groups, arn) } if userErr != nil || roleErr != nil || groupErr != nil { - return fmt.Errorf("[WARN] Error attaching policy with IAM Policy Attach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) + return composeErrors(fmt.Sprint("[WARN] Error attaching policy with IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) } } d.SetId(d.Get("name").(string)) @@ -127,7 +127,7 @@ func resourceAwsIamPolicyAttachmentRead(d *schema.ResourceData, meta interface{} groupErr := d.Set("groups", gl) if userErr != nil || roleErr != nil || groupErr != nil { - return fmt.Errorf("[WARN} Error setting user, role, or group list from IAM Policy Attach (%s):\n user error - %s\n role error - %s\n group error - %s", name, userErr, roleErr, groupErr) + return composeErrors(fmt.Sprint("[WARN} Error setting user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) } return nil @@ -147,7 +147,7 @@ func resourceAwsIamPolicyAttachmentUpdate(d *schema.ResourceData, meta interface groupErr = updateGroups(conn, d, meta) } if userErr != nil || roleErr != nil || groupErr != nil { - return fmt.Errorf("[WARN] Error updating user, role, or group list from IAM Policy Attach (%s):\n user error - %s\n role error - %s\n group error - %s", name, userErr, roleErr, groupErr) + return composeErrors(fmt.Sprint("[WARN] Error updating user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) } return resourceAwsIamPolicyAttachmentRead(d, meta) } @@ -171,16 +171,21 @@ func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface groupErr = detachPolicyFromGroups(conn, groups, arn) } if userErr != nil || roleErr != nil || groupErr != nil { - return fmt.Errorf("[WARN] Error removing user, role, or group list from IAM Policy Detach (%s), error:\n users - %v\n roles - %v\n groups - %v", name, userErr, roleErr, groupErr) + return composeErrors(fmt.Sprint("[WARN] Error removing user, role, or group list from IAM Policy Detach ", name, ":"), userErr, roleErr, groupErr) } return nil } -//func composeErrors(desc string, uErr error, rErr error, gErr error) error { -// errMsg := fmt.Sprintf(desc) -// errs := []error{uErr, rErr, gErr} -// return nil -//} +func composeErrors(desc string, uErr error, rErr error, gErr error) error { + errMsg := fmt.Sprintf(desc) + errs := []error{uErr, rErr, gErr} + for _, e := range errs { + if e != nil { + errMsg = errMsg + "\n– " + e.Error() + } + } + return fmt.Errorf(errMsg) +} func attachPolicyToUsers(conn *iam.IAM, users []*string, arn string) error { for _, u := range users {