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