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