github.com/anuaimi/terraform@v0.6.4-0.20150904235404-2bf9aec61da8/builtin/providers/aws/structure.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "sort" 8 "strings" 9 10 "github.com/aws/aws-sdk-go/aws" 11 "github.com/aws/aws-sdk-go/service/ec2" 12 "github.com/aws/aws-sdk-go/service/ecs" 13 "github.com/aws/aws-sdk-go/service/elasticache" 14 "github.com/aws/aws-sdk-go/service/elb" 15 "github.com/aws/aws-sdk-go/service/rds" 16 "github.com/aws/aws-sdk-go/service/route53" 17 "github.com/hashicorp/terraform/helper/schema" 18 ) 19 20 // Takes the result of flatmap.Expand for an array of listeners and 21 // returns ELB API compatible objects 22 func expandListeners(configured []interface{}) ([]*elb.Listener, error) { 23 listeners := make([]*elb.Listener, 0, len(configured)) 24 25 // Loop over our configured listeners and create 26 // an array of aws-sdk-go compatabile objects 27 for _, lRaw := range configured { 28 data := lRaw.(map[string]interface{}) 29 30 ip := int64(data["instance_port"].(int)) 31 lp := int64(data["lb_port"].(int)) 32 l := &elb.Listener{ 33 InstancePort: &ip, 34 InstanceProtocol: aws.String(data["instance_protocol"].(string)), 35 LoadBalancerPort: &lp, 36 Protocol: aws.String(data["lb_protocol"].(string)), 37 } 38 39 if v, ok := data["ssl_certificate_id"]; ok { 40 l.SSLCertificateId = aws.String(v.(string)) 41 } 42 43 listeners = append(listeners, l) 44 } 45 46 return listeners, nil 47 } 48 49 // Takes the result of flatmap. Expand for an array of listeners and 50 // returns ECS Volume compatible objects 51 func expandEcsVolumes(configured []interface{}) ([]*ecs.Volume, error) { 52 volumes := make([]*ecs.Volume, 0, len(configured)) 53 54 // Loop over our configured volumes and create 55 // an array of aws-sdk-go compatible objects 56 for _, lRaw := range configured { 57 data := lRaw.(map[string]interface{}) 58 59 l := &ecs.Volume{ 60 Name: aws.String(data["name"].(string)), 61 Host: &ecs.HostVolumeProperties{ 62 SourcePath: aws.String(data["host_path"].(string)), 63 }, 64 } 65 66 volumes = append(volumes, l) 67 } 68 69 return volumes, nil 70 } 71 72 // Takes JSON in a string. Decodes JSON into 73 // an array of ecs.ContainerDefinition compatible objects 74 func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) { 75 var definitions []*ecs.ContainerDefinition 76 77 err := json.Unmarshal([]byte(rawDefinitions), &definitions) 78 if err != nil { 79 return nil, fmt.Errorf("Error decoding JSON: %s", err) 80 } 81 82 return definitions, nil 83 } 84 85 // Takes the result of flatmap. Expand for an array of load balancers and 86 // returns ecs.LoadBalancer compatible objects 87 func expandEcsLoadBalancers(configured []interface{}) []*ecs.LoadBalancer { 88 loadBalancers := make([]*ecs.LoadBalancer, 0, len(configured)) 89 90 // Loop over our configured load balancers and create 91 // an array of aws-sdk-go compatible objects 92 for _, lRaw := range configured { 93 data := lRaw.(map[string]interface{}) 94 95 l := &ecs.LoadBalancer{ 96 ContainerName: aws.String(data["container_name"].(string)), 97 ContainerPort: aws.Int64(int64(data["container_port"].(int))), 98 LoadBalancerName: aws.String(data["elb_name"].(string)), 99 } 100 101 loadBalancers = append(loadBalancers, l) 102 } 103 104 return loadBalancers 105 } 106 107 // Takes the result of flatmap.Expand for an array of ingress/egress security 108 // group rules and returns EC2 API compatible objects. This function will error 109 // if it finds invalid permissions input, namely a protocol of "-1" with either 110 // to_port or from_port set to a non-zero value. 111 func expandIPPerms( 112 group *ec2.SecurityGroup, configured []interface{}) ([]*ec2.IpPermission, error) { 113 vpc := group.VpcId != nil 114 115 perms := make([]*ec2.IpPermission, len(configured)) 116 for i, mRaw := range configured { 117 var perm ec2.IpPermission 118 m := mRaw.(map[string]interface{}) 119 120 perm.FromPort = aws.Int64(int64(m["from_port"].(int))) 121 perm.ToPort = aws.Int64(int64(m["to_port"].(int))) 122 perm.IpProtocol = aws.String(m["protocol"].(string)) 123 124 // When protocol is "-1", AWS won't store any ports for the 125 // rule, but also won't error if the user specifies ports other 126 // than '0'. Force the user to make a deliberate '0' port 127 // choice when specifying a "-1" protocol, and tell them about 128 // AWS's behavior in the error message. 129 if *perm.IpProtocol == "-1" && (*perm.FromPort != 0 || *perm.ToPort != 0) { 130 return nil, fmt.Errorf( 131 "from_port (%d) and to_port (%d) must both be 0 to use the the 'ALL' \"-1\" protocol!", 132 *perm.FromPort, *perm.ToPort) 133 } 134 135 var groups []string 136 if raw, ok := m["security_groups"]; ok { 137 list := raw.(*schema.Set).List() 138 for _, v := range list { 139 groups = append(groups, v.(string)) 140 } 141 } 142 if v, ok := m["self"]; ok && v.(bool) { 143 if vpc { 144 groups = append(groups, *group.GroupId) 145 } else { 146 groups = append(groups, *group.GroupName) 147 } 148 } 149 150 if len(groups) > 0 { 151 perm.UserIdGroupPairs = make([]*ec2.UserIdGroupPair, len(groups)) 152 for i, name := range groups { 153 ownerId, id := "", name 154 if items := strings.Split(id, "/"); len(items) > 1 { 155 ownerId, id = items[0], items[1] 156 } 157 158 perm.UserIdGroupPairs[i] = &ec2.UserIdGroupPair{ 159 GroupId: aws.String(id), 160 } 161 162 if ownerId != "" { 163 perm.UserIdGroupPairs[i].UserId = aws.String(ownerId) 164 } 165 166 if !vpc { 167 perm.UserIdGroupPairs[i].GroupId = nil 168 perm.UserIdGroupPairs[i].GroupName = aws.String(id) 169 } 170 } 171 } 172 173 if raw, ok := m["cidr_blocks"]; ok { 174 list := raw.([]interface{}) 175 for _, v := range list { 176 perm.IpRanges = append(perm.IpRanges, &ec2.IpRange{CidrIp: aws.String(v.(string))}) 177 } 178 } 179 180 perms[i] = &perm 181 } 182 183 return perms, nil 184 } 185 186 // Takes the result of flatmap.Expand for an array of parameters and 187 // returns Parameter API compatible objects 188 func expandParameters(configured []interface{}) ([]*rds.Parameter, error) { 189 var parameters []*rds.Parameter 190 191 // Loop over our configured parameters and create 192 // an array of aws-sdk-go compatabile objects 193 for _, pRaw := range configured { 194 data := pRaw.(map[string]interface{}) 195 196 if data["name"].(string) == "" { 197 continue 198 } 199 200 p := &rds.Parameter{ 201 ApplyMethod: aws.String(data["apply_method"].(string)), 202 ParameterName: aws.String(data["name"].(string)), 203 ParameterValue: aws.String(data["value"].(string)), 204 } 205 206 parameters = append(parameters, p) 207 } 208 209 return parameters, nil 210 } 211 212 // Takes the result of flatmap.Expand for an array of parameters and 213 // returns Parameter API compatible objects 214 func expandElastiCacheParameters(configured []interface{}) ([]*elasticache.ParameterNameValue, error) { 215 parameters := make([]*elasticache.ParameterNameValue, 0, len(configured)) 216 217 // Loop over our configured parameters and create 218 // an array of aws-sdk-go compatabile objects 219 for _, pRaw := range configured { 220 data := pRaw.(map[string]interface{}) 221 222 p := &elasticache.ParameterNameValue{ 223 ParameterName: aws.String(data["name"].(string)), 224 ParameterValue: aws.String(data["value"].(string)), 225 } 226 227 parameters = append(parameters, p) 228 } 229 230 return parameters, nil 231 } 232 233 // Flattens a health check into something that flatmap.Flatten() 234 // can handle 235 func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} { 236 result := make([]map[string]interface{}, 0, 1) 237 238 chk := make(map[string]interface{}) 239 chk["unhealthy_threshold"] = *check.UnhealthyThreshold 240 chk["healthy_threshold"] = *check.HealthyThreshold 241 chk["target"] = *check.Target 242 chk["timeout"] = *check.Timeout 243 chk["interval"] = *check.Interval 244 245 result = append(result, chk) 246 247 return result 248 } 249 250 // Flattens an array of UserSecurityGroups into a []string 251 func flattenSecurityGroups(list []*ec2.UserIdGroupPair) []string { 252 result := make([]string, 0, len(list)) 253 for _, g := range list { 254 result = append(result, *g.GroupId) 255 } 256 return result 257 } 258 259 // Flattens an array of Instances into a []string 260 func flattenInstances(list []*elb.Instance) []string { 261 result := make([]string, 0, len(list)) 262 for _, i := range list { 263 result = append(result, *i.InstanceId) 264 } 265 return result 266 } 267 268 // Expands an array of String Instance IDs into a []Instances 269 func expandInstanceString(list []interface{}) []*elb.Instance { 270 result := make([]*elb.Instance, 0, len(list)) 271 for _, i := range list { 272 result = append(result, &elb.Instance{InstanceId: aws.String(i.(string))}) 273 } 274 return result 275 } 276 277 // Flattens an array of Backend Descriptions into a a map of instance_port to policy names. 278 func flattenBackendPolicies(backends []*elb.BackendServerDescription) map[int64][]string { 279 policies := make(map[int64][]string) 280 for _, i := range backends { 281 for _, p := range i.PolicyNames { 282 policies[*i.InstancePort] = append(policies[*i.InstancePort], *p) 283 } 284 sort.Strings(policies[*i.InstancePort]) 285 } 286 return policies 287 } 288 289 // Flattens an array of Listeners into a []map[string]interface{} 290 func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} { 291 result := make([]map[string]interface{}, 0, len(list)) 292 for _, i := range list { 293 l := map[string]interface{}{ 294 "instance_port": *i.Listener.InstancePort, 295 "instance_protocol": strings.ToLower(*i.Listener.InstanceProtocol), 296 "lb_port": *i.Listener.LoadBalancerPort, 297 "lb_protocol": strings.ToLower(*i.Listener.Protocol), 298 } 299 // SSLCertificateID is optional, and may be nil 300 if i.Listener.SSLCertificateId != nil { 301 l["ssl_certificate_id"] = *i.Listener.SSLCertificateId 302 } 303 result = append(result, l) 304 } 305 return result 306 } 307 308 // Flattens an array of Volumes into a []map[string]interface{} 309 func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { 310 result := make([]map[string]interface{}, 0, len(list)) 311 for _, volume := range list { 312 l := map[string]interface{}{ 313 "name": *volume.Name, 314 "host_path": *volume.Host.SourcePath, 315 } 316 result = append(result, l) 317 } 318 return result 319 } 320 321 // Flattens an array of ECS LoadBalancers into a []map[string]interface{} 322 func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} { 323 result := make([]map[string]interface{}, 0, len(list)) 324 for _, loadBalancer := range list { 325 l := map[string]interface{}{ 326 "elb_name": *loadBalancer.LoadBalancerName, 327 "container_name": *loadBalancer.ContainerName, 328 "container_port": *loadBalancer.ContainerPort, 329 } 330 result = append(result, l) 331 } 332 return result 333 } 334 335 // Encodes an array of ecs.ContainerDefinitions into a JSON string 336 func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) { 337 byteArray, err := json.Marshal(definitions) 338 if err != nil { 339 return "", fmt.Errorf("Error encoding to JSON: %s", err) 340 } 341 342 n := bytes.Index(byteArray, []byte{0}) 343 return string(byteArray[:n]), nil 344 } 345 346 // Flattens an array of Parameters into a []map[string]interface{} 347 func flattenParameters(list []*rds.Parameter) []map[string]interface{} { 348 result := make([]map[string]interface{}, 0, len(list)) 349 for _, i := range list { 350 result = append(result, map[string]interface{}{ 351 "name": strings.ToLower(*i.ParameterName), 352 "value": strings.ToLower(*i.ParameterValue), 353 }) 354 } 355 return result 356 } 357 358 // Flattens an array of Parameters into a []map[string]interface{} 359 func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]interface{} { 360 result := make([]map[string]interface{}, 0, len(list)) 361 for _, i := range list { 362 result = append(result, map[string]interface{}{ 363 "name": strings.ToLower(*i.ParameterName), 364 "value": strings.ToLower(*i.ParameterValue), 365 }) 366 } 367 return result 368 } 369 370 // Takes the result of flatmap.Expand for an array of strings 371 // and returns a []string 372 func expandStringList(configured []interface{}) []*string { 373 vs := make([]*string, 0, len(configured)) 374 for _, v := range configured { 375 vs = append(vs, aws.String(v.(string))) 376 } 377 return vs 378 } 379 380 //Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0" 381 func flattenNetworkInterfacesPrivateIPAddesses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string { 382 ips := make([]string, 0, len(dtos)) 383 for _, v := range dtos { 384 ip := *v.PrivateIpAddress 385 ips = append(ips, ip) 386 } 387 return ips 388 } 389 390 //Flattens security group identifiers into a []string, where the elements returned are the GroupIDs 391 func flattenGroupIdentifiers(dtos []*ec2.GroupIdentifier) []string { 392 ids := make([]string, 0, len(dtos)) 393 for _, v := range dtos { 394 group_id := *v.GroupId 395 ids = append(ids, group_id) 396 } 397 return ids 398 } 399 400 //Expands an array of IPs into a ec2 Private IP Address Spec 401 func expandPrivateIPAddesses(ips []interface{}) []*ec2.PrivateIpAddressSpecification { 402 dtos := make([]*ec2.PrivateIpAddressSpecification, 0, len(ips)) 403 for i, v := range ips { 404 new_private_ip := &ec2.PrivateIpAddressSpecification{ 405 PrivateIpAddress: aws.String(v.(string)), 406 } 407 408 new_private_ip.Primary = aws.Bool(i == 0) 409 410 dtos = append(dtos, new_private_ip) 411 } 412 return dtos 413 } 414 415 //Flattens network interface attachment into a map[string]interface 416 func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} { 417 att := make(map[string]interface{}) 418 att["instance"] = *a.InstanceId 419 att["device_index"] = *a.DeviceIndex 420 att["attachment_id"] = *a.AttachmentId 421 return att 422 } 423 424 func flattenResourceRecords(recs []*route53.ResourceRecord) []string { 425 strs := make([]string, 0, len(recs)) 426 for _, r := range recs { 427 if r.Value != nil { 428 s := strings.Replace(*r.Value, "\"", "", 2) 429 strs = append(strs, s) 430 } 431 } 432 return strs 433 } 434 435 func expandResourceRecords(recs []interface{}, typeStr string) []*route53.ResourceRecord { 436 records := make([]*route53.ResourceRecord, 0, len(recs)) 437 for _, r := range recs { 438 s := r.(string) 439 switch typeStr { 440 case "TXT": 441 str := fmt.Sprintf("\"%s\"", s) 442 records = append(records, &route53.ResourceRecord{Value: aws.String(str)}) 443 default: 444 records = append(records, &route53.ResourceRecord{Value: aws.String(s)}) 445 } 446 } 447 return records 448 }