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 }