github.com/i0n/terraform@v0.4.3-0.20150506151324-010a39a58ec1/builtin/providers/aws/resource_aws_proxy_protocol_policy.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/awslabs/aws-sdk-go/aws"
    10  	"github.com/awslabs/aws-sdk-go/service/elb"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsProxyProtocolPolicy() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsProxyProtocolPolicyCreate,
    18  		Read:   resourceAwsProxyProtocolPolicyRead,
    19  		Update: resourceAwsProxyProtocolPolicyUpdate,
    20  		Delete: resourceAwsProxyProtocolPolicyDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"load_balancer": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  			},
    27  
    28  			"instance_ports": &schema.Schema{
    29  				Type:     schema.TypeSet,
    30  				Elem:     &schema.Schema{Type: schema.TypeString},
    31  				Required: true,
    32  				Set: func(v interface{}) int {
    33  					return hashcode.String(v.(string))
    34  				},
    35  			},
    36  		},
    37  	}
    38  }
    39  
    40  func resourceAwsProxyProtocolPolicyCreate(d *schema.ResourceData, meta interface{}) error {
    41  	elbconn := meta.(*AWSClient).elbconn
    42  	elbname := aws.String(d.Get("load_balancer").(string))
    43  
    44  	input := &elb.CreateLoadBalancerPolicyInput{
    45  		LoadBalancerName: elbname,
    46  		PolicyAttributes: []*elb.PolicyAttribute{
    47  			&elb.PolicyAttribute{
    48  				AttributeName:  aws.String("ProxyProtocol"),
    49  				AttributeValue: aws.String("True"),
    50  			},
    51  		},
    52  		PolicyName:     aws.String("TFEnableProxyProtocol"),
    53  		PolicyTypeName: aws.String("ProxyProtocolPolicyType"),
    54  	}
    55  
    56  	// Create a policy
    57  	log.Printf("[DEBUG] ELB create a policy %s from policy type %s",
    58  		*input.PolicyName, *input.PolicyTypeName)
    59  
    60  	if _, err := elbconn.CreateLoadBalancerPolicy(input); err != nil {
    61  		return fmt.Errorf("Error creating a policy %s: %s",
    62  			*input.PolicyName, err)
    63  	}
    64  
    65  	// Assign the policy name for use later
    66  	d.Partial(true)
    67  	d.SetId(fmt.Sprintf("%s:%s", *elbname, *input.PolicyName))
    68  	d.SetPartial("load_balancer")
    69  	log.Printf("[INFO] ELB PolicyName: %s", *input.PolicyName)
    70  
    71  	return resourceAwsProxyProtocolPolicyUpdate(d, meta)
    72  }
    73  
    74  func resourceAwsProxyProtocolPolicyRead(d *schema.ResourceData, meta interface{}) error {
    75  	elbconn := meta.(*AWSClient).elbconn
    76  	elbname := aws.String(d.Get("load_balancer").(string))
    77  
    78  	// Retrieve the current ELB policies for updating the state
    79  	req := &elb.DescribeLoadBalancersInput{
    80  		LoadBalancerNames: []*string{elbname},
    81  	}
    82  	resp, err := elbconn.DescribeLoadBalancers(req)
    83  	if err != nil {
    84  		if isLoadBalancerNotFound(err) {
    85  			// The ELB is gone now, so just remove it from the state
    86  			d.SetId("")
    87  			return nil
    88  		}
    89  		return fmt.Errorf("Error retrieving ELB attributes: %s", err)
    90  	}
    91  
    92  	backends := flattenBackendPolicies(resp.LoadBalancerDescriptions[0].BackendServerDescriptions)
    93  
    94  	ports := []*string{}
    95  	for ip := range backends {
    96  		ipstr := strconv.Itoa(int(ip))
    97  		ports = append(ports, &ipstr)
    98  	}
    99  	d.Set("instance_ports", ports)
   100  	d.Set("load_balancer", *elbname)
   101  	return nil
   102  }
   103  
   104  func resourceAwsProxyProtocolPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
   105  	elbconn := meta.(*AWSClient).elbconn
   106  	elbname := aws.String(d.Get("load_balancer").(string))
   107  
   108  	// Retrieve the current ELB policies for updating the state
   109  	req := &elb.DescribeLoadBalancersInput{
   110  		LoadBalancerNames: []*string{elbname},
   111  	}
   112  	resp, err := elbconn.DescribeLoadBalancers(req)
   113  	if err != nil {
   114  		if isLoadBalancerNotFound(err) {
   115  			// The ELB is gone now, so just remove it from the state
   116  			d.SetId("")
   117  			return nil
   118  		}
   119  		return fmt.Errorf("Error retrieving ELB attributes: %s", err)
   120  	}
   121  
   122  	backends := flattenBackendPolicies(resp.LoadBalancerDescriptions[0].BackendServerDescriptions)
   123  	_, policyName := resourceAwsProxyProtocolPolicyParseId(d.Id())
   124  
   125  	d.Partial(true)
   126  	if d.HasChange("instance_ports") {
   127  		o, n := d.GetChange("instance_ports")
   128  		os := o.(*schema.Set)
   129  		ns := n.(*schema.Set)
   130  		remove := os.Difference(ns).List()
   131  		add := ns.Difference(os).List()
   132  
   133  		inputs := []*elb.SetLoadBalancerPoliciesForBackendServerInput{}
   134  
   135  		i, err := resourceAwsProxyProtocolPolicyRemove(policyName, remove, backends)
   136  		if err != nil {
   137  			return err
   138  		}
   139  		inputs = append(inputs, i...)
   140  
   141  		i, err = resourceAwsProxyProtocolPolicyAdd(policyName, add, backends)
   142  		if err != nil {
   143  			return err
   144  		}
   145  		inputs = append(inputs, i...)
   146  
   147  		for _, input := range inputs {
   148  			input.LoadBalancerName = elbname
   149  			if _, err := elbconn.SetLoadBalancerPoliciesForBackendServer(input); err != nil {
   150  				return fmt.Errorf("Error setting policy for backend: %s", err)
   151  			}
   152  		}
   153  
   154  		d.SetPartial("instance_ports")
   155  	}
   156  
   157  	return resourceAwsProxyProtocolPolicyRead(d, meta)
   158  }
   159  
   160  func resourceAwsProxyProtocolPolicyDelete(d *schema.ResourceData, meta interface{}) error {
   161  	elbconn := meta.(*AWSClient).elbconn
   162  	elbname := aws.String(d.Get("load_balancer").(string))
   163  
   164  	// Retrieve the current ELB policies for updating the state
   165  	req := &elb.DescribeLoadBalancersInput{
   166  		LoadBalancerNames: []*string{elbname},
   167  	}
   168  	resp, err := elbconn.DescribeLoadBalancers(req)
   169  	if err != nil {
   170  		if isLoadBalancerNotFound(err) {
   171  			// The ELB is gone now, so just remove it from the state
   172  			d.SetId("")
   173  			return nil
   174  		}
   175  		return fmt.Errorf("Error retrieving ELB attributes: %s", err)
   176  	}
   177  
   178  	backends := flattenBackendPolicies(resp.LoadBalancerDescriptions[0].BackendServerDescriptions)
   179  	ports := d.Get("instance_ports").(*schema.Set).List()
   180  	_, policyName := resourceAwsProxyProtocolPolicyParseId(d.Id())
   181  
   182  	inputs, err := resourceAwsProxyProtocolPolicyRemove(policyName, ports, backends)
   183  	if err != nil {
   184  		return fmt.Errorf("Error detaching a policy from backend: %s", err)
   185  	}
   186  	for _, input := range inputs {
   187  		input.LoadBalancerName = elbname
   188  		if _, err := elbconn.SetLoadBalancerPoliciesForBackendServer(input); err != nil {
   189  			return fmt.Errorf("Error setting policy for backend: %s", err)
   190  		}
   191  	}
   192  
   193  	pOpt := &elb.DeleteLoadBalancerPolicyInput{
   194  		LoadBalancerName: elbname,
   195  		PolicyName:       aws.String(policyName),
   196  	}
   197  	if _, err := elbconn.DeleteLoadBalancerPolicy(pOpt); err != nil {
   198  		return fmt.Errorf("Error removing a policy from load balancer: %s", err)
   199  	}
   200  
   201  	return nil
   202  }
   203  
   204  func resourceAwsProxyProtocolPolicyRemove(policyName string, ports []interface{}, backends map[int64][]string) ([]*elb.SetLoadBalancerPoliciesForBackendServerInput, error) {
   205  	inputs := make([]*elb.SetLoadBalancerPoliciesForBackendServerInput, 0, len(ports))
   206  	for _, p := range ports {
   207  		ip, err := strconv.ParseInt(p.(string), 10, 64)
   208  		if err != nil {
   209  			return nil, fmt.Errorf("Error detaching the policy: %s", err)
   210  		}
   211  
   212  		newPolicies := []*string{}
   213  		curPolicies, found := backends[ip]
   214  		if !found {
   215  			// No policy for this instance port found, just skip it.
   216  			continue
   217  		}
   218  
   219  		for _, policy := range curPolicies {
   220  			if policy == policyName {
   221  				// remove the policy
   222  				continue
   223  			}
   224  			newPolicies = append(newPolicies, &policy)
   225  		}
   226  
   227  		inputs = append(inputs, &elb.SetLoadBalancerPoliciesForBackendServerInput{
   228  			InstancePort: &ip,
   229  			PolicyNames:  newPolicies,
   230  		})
   231  	}
   232  	return inputs, nil
   233  }
   234  
   235  func resourceAwsProxyProtocolPolicyAdd(policyName string, ports []interface{}, backends map[int64][]string) ([]*elb.SetLoadBalancerPoliciesForBackendServerInput, error) {
   236  	inputs := make([]*elb.SetLoadBalancerPoliciesForBackendServerInput, 0, len(ports))
   237  	for _, p := range ports {
   238  		ip, err := strconv.ParseInt(p.(string), 10, 64)
   239  		if err != nil {
   240  			return nil, fmt.Errorf("Error attaching the policy: %s", err)
   241  		}
   242  
   243  		newPolicies := []*string{}
   244  		curPolicies := backends[ip]
   245  		for _, p := range curPolicies {
   246  			if p == policyName {
   247  				// Just remove it for now. It will be back later.
   248  				continue
   249  			} else {
   250  				newPolicies = append(newPolicies, &p)
   251  			}
   252  		}
   253  		newPolicies = append(newPolicies, aws.String(policyName))
   254  
   255  		inputs = append(inputs, &elb.SetLoadBalancerPoliciesForBackendServerInput{
   256  			InstancePort: &ip,
   257  			PolicyNames:  newPolicies,
   258  		})
   259  	}
   260  	return inputs, nil
   261  }
   262  
   263  // resourceAwsProxyProtocolPolicyParseId takes an ID and parses it into
   264  // it's constituent parts. You need two axes (LB name, policy name)
   265  // to create or identify a proxy protocol policy in AWS's API.
   266  func resourceAwsProxyProtocolPolicyParseId(id string) (string, string) {
   267  	parts := strings.SplitN(id, ":", 2)
   268  	return parts[0], parts[1]
   269  }