github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/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  }