github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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 }