From 2135ff02b781cf0d143d7ace3d68341ecd2da880 Mon Sep 17 00:00:00 2001 From: Patrick Gray Date: Wed, 17 Jun 2015 10:56:33 -0400 Subject: [PATCH] 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 5ac2c5c50b..218715a82b 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 fa43009ef5..a025f52059 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 = <