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