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