github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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/aws/aws-sdk-go/aws"
    10  	"github.com/aws/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  	var err error
   169  	resp, err := elbconn.DescribeLoadBalancers(req)
   170  	if err != nil {
   171  		if isLoadBalancerNotFound(err) {
   172  			// The ELB is gone now, so just remove it from the state
   173  			d.SetId("")
   174  			return nil
   175  		}
   176  		return fmt.Errorf("Error retrieving ELB attributes: %s", err)
   177  	}
   178  
   179  	backends := flattenBackendPolicies(resp.LoadBalancerDescriptions[0].BackendServerDescriptions)
   180  	ports := d.Get("instance_ports").(*schema.Set).List()
   181  	_, policyName := resourceAwsProxyProtocolPolicyParseId(d.Id())
   182  
   183  	inputs, err := resourceAwsProxyProtocolPolicyRemove(policyName, ports, backends)
   184  	if err != nil {
   185  		return fmt.Errorf("Error detaching a policy from backend: %s", err)
   186  	}
   187  	for _, input := range inputs {
   188  		input.LoadBalancerName = elbname
   189  		if _, err := elbconn.SetLoadBalancerPoliciesForBackendServer(input); err != nil {
   190  			return fmt.Errorf("Error setting policy for backend: %s", err)
   191  		}
   192  	}
   193  
   194  	pOpt := &elb.DeleteLoadBalancerPolicyInput{
   195  		LoadBalancerName: elbname,
   196  		PolicyName:       aws.String(policyName),
   197  	}
   198  	if _, err := elbconn.DeleteLoadBalancerPolicy(pOpt); err != nil {
   199  		return fmt.Errorf("Error removing a policy from load balancer: %s", err)
   200  	}
   201  
   202  	return nil
   203  }
   204  
   205  func resourceAwsProxyProtocolPolicyRemove(policyName string, ports []interface{}, backends map[int64][]string) ([]*elb.SetLoadBalancerPoliciesForBackendServerInput, error) {
   206  	inputs := make([]*elb.SetLoadBalancerPoliciesForBackendServerInput, 0, len(ports))
   207  	for _, p := range ports {
   208  		ip, err := strconv.ParseInt(p.(string), 10, 64)
   209  		if err != nil {
   210  			return nil, fmt.Errorf("Error detaching the policy: %s", err)
   211  		}
   212  
   213  		newPolicies := []*string{}
   214  		curPolicies, found := backends[ip]
   215  		if !found {
   216  			// No policy for this instance port found, just skip it.
   217  			continue
   218  		}
   219  
   220  		for _, policy := range curPolicies {
   221  			if policy == policyName {
   222  				// remove the policy
   223  				continue
   224  			}
   225  			newPolicies = append(newPolicies, &policy)
   226  		}
   227  
   228  		inputs = append(inputs, &elb.SetLoadBalancerPoliciesForBackendServerInput{
   229  			InstancePort: &ip,
   230  			PolicyNames:  newPolicies,
   231  		})
   232  	}
   233  	return inputs, nil
   234  }
   235  
   236  func resourceAwsProxyProtocolPolicyAdd(policyName string, ports []interface{}, backends map[int64][]string) ([]*elb.SetLoadBalancerPoliciesForBackendServerInput, error) {
   237  	inputs := make([]*elb.SetLoadBalancerPoliciesForBackendServerInput, 0, len(ports))
   238  	for _, p := range ports {
   239  		ip, err := strconv.ParseInt(p.(string), 10, 64)
   240  		if err != nil {
   241  			return nil, fmt.Errorf("Error attaching the policy: %s", err)
   242  		}
   243  
   244  		newPolicies := []*string{}
   245  		curPolicies := backends[ip]
   246  		for _, p := range curPolicies {
   247  			if p == policyName {
   248  				// Just remove it for now. It will be back later.
   249  				continue
   250  			} else {
   251  				newPolicies = append(newPolicies, &p)
   252  			}
   253  		}
   254  		newPolicies = append(newPolicies, aws.String(policyName))
   255  
   256  		inputs = append(inputs, &elb.SetLoadBalancerPoliciesForBackendServerInput{
   257  			InstancePort: &ip,
   258  			PolicyNames:  newPolicies,
   259  		})
   260  	}
   261  	return inputs, nil
   262  }
   263  
   264  // resourceAwsProxyProtocolPolicyParseId takes an ID and parses it into
   265  // it's constituent parts. You need two axes (LB name, policy name)
   266  // to create or identify a proxy protocol policy in AWS's API.
   267  func resourceAwsProxyProtocolPolicyParseId(id string) (string, string) {
   268  	parts := strings.SplitN(id, ":", 2)
   269  	return parts[0], parts[1]
   270  }