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