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  }