github.com/ves/terraform@v0.8.0-beta2/builtin/providers/aws/resource_aws_iam_role.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "regexp" 6 "time" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/aws/awserr" 10 "github.com/aws/aws-sdk-go/service/iam" 11 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func resourceAwsIamRole() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceAwsIamRoleCreate, 19 Read: resourceAwsIamRoleRead, 20 Update: resourceAwsIamRoleUpdate, 21 Delete: resourceAwsIamRoleDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "arn": { 25 Type: schema.TypeString, 26 Computed: true, 27 }, 28 29 "unique_id": { 30 Type: schema.TypeString, 31 Computed: true, 32 }, 33 34 "name": { 35 Type: schema.TypeString, 36 Optional: true, 37 Computed: true, 38 ForceNew: true, 39 ConflictsWith: []string{"name_prefix"}, 40 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 41 // https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8329-L8334 42 value := v.(string) 43 if len(value) > 64 { 44 errors = append(errors, fmt.Errorf( 45 "%q cannot be longer than 64 characters", k)) 46 } 47 if !regexp.MustCompile("^[\\w+=,.@-]*$").MatchString(value) { 48 errors = append(errors, fmt.Errorf( 49 "%q must match [\\w+=,.@-]", k)) 50 } 51 return 52 }, 53 }, 54 55 "name_prefix": { 56 Type: schema.TypeString, 57 Optional: true, 58 ForceNew: true, 59 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 60 // https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8329-L8334 61 value := v.(string) 62 if len(value) > 32 { 63 errors = append(errors, fmt.Errorf( 64 "%q cannot be longer than 32 characters, name is limited to 64", k)) 65 } 66 if !regexp.MustCompile("^[\\w+=,.@-]*$").MatchString(value) { 67 errors = append(errors, fmt.Errorf( 68 "%q must match [\\w+=,.@-]", k)) 69 } 70 return 71 }, 72 }, 73 74 "path": { 75 Type: schema.TypeString, 76 Optional: true, 77 Default: "/", 78 ForceNew: true, 79 }, 80 81 "assume_role_policy": { 82 Type: schema.TypeString, 83 Required: true, 84 }, 85 86 "create_date": { 87 Type: schema.TypeString, 88 Computed: true, 89 }, 90 }, 91 } 92 } 93 94 func resourceAwsIamRoleCreate(d *schema.ResourceData, meta interface{}) error { 95 iamconn := meta.(*AWSClient).iamconn 96 97 var name string 98 if v, ok := d.GetOk("name"); ok { 99 name = v.(string) 100 } else if v, ok := d.GetOk("name_prefix"); ok { 101 name = resource.PrefixedUniqueId(v.(string)) 102 } else { 103 name = resource.UniqueId() 104 } 105 106 request := &iam.CreateRoleInput{ 107 Path: aws.String(d.Get("path").(string)), 108 RoleName: aws.String(name), 109 AssumeRolePolicyDocument: aws.String(d.Get("assume_role_policy").(string)), 110 } 111 112 var createResp *iam.CreateRoleOutput 113 err := resource.Retry(30*time.Second, func() *resource.RetryError { 114 var err error 115 createResp, err = iamconn.CreateRole(request) 116 // IAM users (referenced in Principal field of assume policy) 117 // can take ~30 seconds to propagate in AWS 118 if isAWSErr(err, "MalformedPolicyDocument", "Invalid principal in policy") { 119 return resource.RetryableError(err) 120 } 121 return resource.NonRetryableError(err) 122 }) 123 if err != nil { 124 return fmt.Errorf("Error creating IAM Role %s: %s", name, err) 125 } 126 return resourceAwsIamRoleReadResult(d, createResp.Role) 127 } 128 129 func resourceAwsIamRoleRead(d *schema.ResourceData, meta interface{}) error { 130 iamconn := meta.(*AWSClient).iamconn 131 132 request := &iam.GetRoleInput{ 133 RoleName: aws.String(d.Id()), 134 } 135 136 getResp, err := iamconn.GetRole(request) 137 if err != nil { 138 if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { // XXX test me 139 d.SetId("") 140 return nil 141 } 142 return fmt.Errorf("Error reading IAM Role %s: %s", d.Id(), err) 143 } 144 return resourceAwsIamRoleReadResult(d, getResp.Role) 145 } 146 147 func resourceAwsIamRoleUpdate(d *schema.ResourceData, meta interface{}) error { 148 iamconn := meta.(*AWSClient).iamconn 149 150 if d.HasChange("assume_role_policy") { 151 assumeRolePolicyInput := &iam.UpdateAssumeRolePolicyInput{ 152 RoleName: aws.String(d.Id()), 153 PolicyDocument: aws.String(d.Get("assume_role_policy").(string)), 154 } 155 _, err := iamconn.UpdateAssumeRolePolicy(assumeRolePolicyInput) 156 if err != nil { 157 if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { 158 d.SetId("") 159 return nil 160 } 161 return fmt.Errorf("Error Updating IAM Role (%s) Assume Role Policy: %s", d.Id(), err) 162 } 163 } 164 165 return nil 166 } 167 168 func resourceAwsIamRoleReadResult(d *schema.ResourceData, role *iam.Role) error { 169 d.SetId(*role.RoleName) 170 if err := d.Set("name", role.RoleName); err != nil { 171 return err 172 } 173 if err := d.Set("arn", role.Arn); err != nil { 174 return err 175 } 176 if err := d.Set("path", role.Path); err != nil { 177 return err 178 } 179 if err := d.Set("unique_id", role.RoleId); err != nil { 180 return err 181 } 182 if err := d.Set("create_date", role.CreateDate.Format(time.RFC3339)); err != nil { 183 return err 184 } 185 return nil 186 } 187 188 func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error { 189 iamconn := meta.(*AWSClient).iamconn 190 191 // Roles cannot be destroyed when attached to an existing Instance Profile 192 resp, err := iamconn.ListInstanceProfilesForRole(&iam.ListInstanceProfilesForRoleInput{ 193 RoleName: aws.String(d.Id()), 194 }) 195 if err != nil { 196 return fmt.Errorf("Error listing Profiles for IAM Role (%s) when trying to delete: %s", d.Id(), err) 197 } 198 199 // Loop and remove this Role from any Profiles 200 if len(resp.InstanceProfiles) > 0 { 201 for _, i := range resp.InstanceProfiles { 202 _, err := iamconn.RemoveRoleFromInstanceProfile(&iam.RemoveRoleFromInstanceProfileInput{ 203 InstanceProfileName: i.InstanceProfileName, 204 RoleName: aws.String(d.Id()), 205 }) 206 if err != nil { 207 return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err) 208 } 209 } 210 } 211 212 request := &iam.DeleteRoleInput{ 213 RoleName: aws.String(d.Id()), 214 } 215 216 if _, err := iamconn.DeleteRole(request); err != nil { 217 return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err) 218 } 219 return nil 220 }