github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/resource_aws_iam_instance_profile.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 resourceAwsIamInstanceProfile() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAwsIamInstanceProfileCreate, 18 Read: resourceAwsIamInstanceProfileRead, 19 Update: resourceAwsIamInstanceProfileUpdate, 20 Delete: resourceAwsIamInstanceProfileDelete, 21 22 Schema: map[string]*schema.Schema{ 23 "arn": &schema.Schema{ 24 Type: schema.TypeString, 25 Computed: true, 26 }, 27 28 "create_date": &schema.Schema{ 29 Type: schema.TypeString, 30 Computed: true, 31 }, 32 33 "unique_id": &schema.Schema{ 34 Type: schema.TypeString, 35 Computed: true, 36 }, 37 38 "name": &schema.Schema{ 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#L8196-L8201 46 value := v.(string) 47 if len(value) > 128 { 48 errors = append(errors, fmt.Errorf( 49 "%q cannot be longer than 128 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": &schema.Schema{ 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#L8196-L8201 65 value := v.(string) 66 if len(value) > 64 { 67 errors = append(errors, fmt.Errorf( 68 "%q cannot be longer than 64 characters, name is limited to 128", 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": &schema.Schema{ 79 Type: schema.TypeString, 80 Optional: true, 81 Default: "/", 82 ForceNew: true, 83 }, 84 85 "roles": &schema.Schema{ 86 Type: schema.TypeSet, 87 Required: true, 88 Elem: &schema.Schema{Type: schema.TypeString}, 89 Set: schema.HashString, 90 }, 91 }, 92 } 93 } 94 95 func resourceAwsIamInstanceProfileCreate(d *schema.ResourceData, meta interface{}) error { 96 iamconn := meta.(*AWSClient).iamconn 97 98 var name string 99 if v, ok := d.GetOk("name"); ok { 100 name = v.(string) 101 } else if v, ok := d.GetOk("name_prefix"); ok { 102 name = resource.PrefixedUniqueId(v.(string)) 103 } else { 104 name = resource.UniqueId() 105 } 106 107 request := &iam.CreateInstanceProfileInput{ 108 InstanceProfileName: aws.String(name), 109 Path: aws.String(d.Get("path").(string)), 110 } 111 112 var err error 113 response, err := iamconn.CreateInstanceProfile(request) 114 if err == nil { 115 err = instanceProfileReadResult(d, response.InstanceProfile) 116 } 117 if err != nil { 118 return fmt.Errorf("Error creating IAM instance profile %s: %s", name, err) 119 } 120 121 return instanceProfileSetRoles(d, iamconn) 122 } 123 124 func instanceProfileAddRole(iamconn *iam.IAM, profileName, roleName string) error { 125 request := &iam.AddRoleToInstanceProfileInput{ 126 InstanceProfileName: aws.String(profileName), 127 RoleName: aws.String(roleName), 128 } 129 130 _, err := iamconn.AddRoleToInstanceProfile(request) 131 return err 132 } 133 134 func instanceProfileRemoveRole(iamconn *iam.IAM, profileName, roleName string) error { 135 request := &iam.RemoveRoleFromInstanceProfileInput{ 136 InstanceProfileName: aws.String(profileName), 137 RoleName: aws.String(roleName), 138 } 139 140 _, err := iamconn.RemoveRoleFromInstanceProfile(request) 141 if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { 142 return nil 143 } 144 return err 145 } 146 147 func instanceProfileSetRoles(d *schema.ResourceData, iamconn *iam.IAM) error { 148 oldInterface, newInterface := d.GetChange("roles") 149 oldRoles := oldInterface.(*schema.Set) 150 newRoles := newInterface.(*schema.Set) 151 152 currentRoles := schema.CopySet(oldRoles) 153 154 d.Partial(true) 155 156 for _, role := range oldRoles.Difference(newRoles).List() { 157 err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string)) 158 if err != nil { 159 return fmt.Errorf("Error removing role %s from IAM instance profile %s: %s", role, d.Id(), err) 160 } 161 currentRoles.Remove(role) 162 d.Set("roles", currentRoles) 163 d.SetPartial("roles") 164 } 165 166 for _, role := range newRoles.Difference(oldRoles).List() { 167 err := instanceProfileAddRole(iamconn, d.Id(), role.(string)) 168 if err != nil { 169 return fmt.Errorf("Error adding role %s to IAM instance profile %s: %s", role, d.Id(), err) 170 } 171 currentRoles.Add(role) 172 d.Set("roles", currentRoles) 173 d.SetPartial("roles") 174 } 175 176 d.Partial(false) 177 178 return nil 179 } 180 181 func instanceProfileRemoveAllRoles(d *schema.ResourceData, iamconn *iam.IAM) error { 182 for _, role := range d.Get("roles").(*schema.Set).List() { 183 err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string)) 184 if err != nil { 185 return fmt.Errorf("Error removing role %s from IAM instance profile %s: %s", role, d.Id(), err) 186 } 187 } 188 return nil 189 } 190 191 func resourceAwsIamInstanceProfileUpdate(d *schema.ResourceData, meta interface{}) error { 192 iamconn := meta.(*AWSClient).iamconn 193 194 if !d.HasChange("roles") { 195 return nil 196 } 197 198 return instanceProfileSetRoles(d, iamconn) 199 } 200 201 func resourceAwsIamInstanceProfileRead(d *schema.ResourceData, meta interface{}) error { 202 iamconn := meta.(*AWSClient).iamconn 203 204 request := &iam.GetInstanceProfileInput{ 205 InstanceProfileName: aws.String(d.Id()), 206 } 207 208 result, err := iamconn.GetInstanceProfile(request) 209 if err != nil { 210 if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { 211 d.SetId("") 212 return nil 213 } 214 return fmt.Errorf("Error reading IAM instance profile %s: %s", d.Id(), err) 215 } 216 217 return instanceProfileReadResult(d, result.InstanceProfile) 218 } 219 220 func resourceAwsIamInstanceProfileDelete(d *schema.ResourceData, meta interface{}) error { 221 iamconn := meta.(*AWSClient).iamconn 222 223 if err := instanceProfileRemoveAllRoles(d, iamconn); err != nil { 224 return err 225 } 226 227 request := &iam.DeleteInstanceProfileInput{ 228 InstanceProfileName: aws.String(d.Id()), 229 } 230 _, err := iamconn.DeleteInstanceProfile(request) 231 if err != nil { 232 return fmt.Errorf("Error deleting IAM instance profile %s: %s", d.Id(), err) 233 } 234 d.SetId("") 235 return nil 236 } 237 238 func instanceProfileReadResult(d *schema.ResourceData, result *iam.InstanceProfile) error { 239 d.SetId(*result.InstanceProfileName) 240 if err := d.Set("name", result.InstanceProfileName); err != nil { 241 return err 242 } 243 if err := d.Set("arn", result.Arn); err != nil { 244 return err 245 } 246 if err := d.Set("path", result.Path); err != nil { 247 return err 248 } 249 250 roles := &schema.Set{F: schema.HashString} 251 for _, role := range result.Roles { 252 roles.Add(*role.RoleName) 253 } 254 if err := d.Set("roles", roles); err != nil { 255 return err 256 } 257 258 return nil 259 }