From 74bfbece69e6826836ae6820ad0cfa494d689128 Mon Sep 17 00:00:00 2001 From: Jason Waldrip Date: Mon, 13 Apr 2015 14:14:26 -0600 Subject: [PATCH] Implement Additional ELB Connection Attributes --- builtin/providers/aws/resource_aws_elb.go | 83 +++++--- .../providers/aws/resource_aws_elb_test.go | 190 ++++++++++++++++++ .../docs/providers/aws/r/elb.html.markdown | 6 + 3 files changed, 250 insertions(+), 29 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index b15fe1afa..fa2af811b 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -81,6 +81,24 @@ func resourceAwsElb() *schema.Resource { }, }, + "idle_timeout": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 30, + }, + + "connection_draining": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "connection_draining_timeout": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 300, + }, + "listener": &schema.Schema{ Type: schema.TypeSet, Required: true, @@ -213,38 +231,16 @@ func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { d.Set("tags", tagsToMapELB(tags)) - if d.HasChange("health_check") { - vs := d.Get("health_check").(*schema.Set).List() - if len(vs) > 0 { - check := vs[0].(map[string]interface{}) - - configureHealthCheckOpts := elb.ConfigureHealthCheckInput{ - LoadBalancerName: aws.String(d.Id()), - HealthCheck: &elb.HealthCheck{ - HealthyThreshold: aws.Integer(check["healthy_threshold"].(int)), - UnhealthyThreshold: aws.Integer(check["unhealthy_threshold"].(int)), - Interval: aws.Integer(check["interval"].(int)), - Target: aws.String(check["target"].(string)), - Timeout: aws.Integer(check["timeout"].(int)), - }, - } - - _, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts) - if err != nil { - return fmt.Errorf("Failure configuring health check: %s", err) - } - } - } - return resourceAwsElbUpdate(d, meta) } func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error { elbconn := meta.(*AWSClient).elbconn + elbName := d.Id() // Retrieve the ELB properties for updating the state describeElbOpts := &elb.DescribeAccessPointsInput{ - LoadBalancerNames: []string{d.Id()}, + LoadBalancerNames: []string{elbName}, } describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) @@ -261,6 +257,22 @@ func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancerDescriptions) } + describeAttrsOpts := &elb.DescribeLoadBalancerAttributesInput{ + LoadBalancerName: aws.String(elbName), + } + describeAttrsResp, err := elbconn.DescribeLoadBalancerAttributes(describeAttrsOpts) + if err != nil { + if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "LoadBalancerNotFound" { + // The ELB is gone now, so just remove it from the state + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving ELB: %s", err) + } + + lbAttrs := describeAttrsResp.LoadBalancerAttributes + lb := describeResp.LoadBalancerDescriptions[0] d.Set("name", *lb.LoadBalancerName) @@ -271,6 +283,9 @@ func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error { d.Set("listener", flattenListeners(lb.ListenerDescriptions)) d.Set("security_groups", lb.SecurityGroups) d.Set("subnets", lb.Subnets) + d.Set("idle_timeout", lbAttrs.ConnectionSettings.IdleTimeout) + d.Set("connection_draining", lbAttrs.ConnectionDraining.Enabled) + d.Set("connection_draining_timeout", lbAttrs.ConnectionDraining.Timeout) resp, err := elbconn.DescribeTags(&elb.DescribeTagsInput{ LoadBalancerNames: []string{*lb.LoadBalancerName}, @@ -332,21 +347,31 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { } log.Println("[INFO] outside modify attributes") - if d.HasChange("cross_zone_load_balancing") { + if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") || d.HasChange("connection_draining") || d.HasChange("connection_draining_timeout") { log.Println("[INFO] inside modify attributes") attrs := elb.ModifyLoadBalancerAttributesInput{ LoadBalancerName: aws.String(d.Get("name").(string)), LoadBalancerAttributes: &elb.LoadBalancerAttributes{ CrossZoneLoadBalancing: &elb.CrossZoneLoadBalancing{ - aws.Boolean(d.Get("cross_zone_load_balancing").(bool)), + Enabled: aws.Boolean(d.Get("cross_zone_load_balancing").(bool)), + }, + ConnectionSettings: &elb.ConnectionSettings{ + IdleTimeout: aws.Integer(d.Get("idle_timeout").(int)), + }, + ConnectionDraining: &elb.ConnectionDraining{ + Enabled: aws.Boolean(d.Get("connection_draining").(bool)), + Timeout: aws.Integer(d.Get("connection_draining_timeout").(int)), }, }, } _, err := elbconn.ModifyLoadBalancerAttributes(&attrs) if err != nil { - return fmt.Errorf("Failure configuring cross zone balancing: %s", err) + return fmt.Errorf("Failure configuring elb attributes: %s", err) } d.SetPartial("cross_zone_load_balancing") + d.SetPartial("idle_timeout") + d.SetPartial("connection_draining") + d.SetPartial("connection_draining_timeout") } if d.HasChange("health_check") { @@ -373,9 +398,9 @@ func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { if err := setTagsELB(elbconn, d); err != nil { return err - } else { - d.SetPartial("tags") } + + d.SetPartial("tags") d.Partial(false) return resourceAwsElbRead(d, meta) diff --git a/builtin/providers/aws/resource_aws_elb_test.go b/builtin/providers/aws/resource_aws_elb_test.go index 2fbe7ace8..308998e36 100644 --- a/builtin/providers/aws/resource_aws_elb_test.go +++ b/builtin/providers/aws/resource_aws_elb_test.go @@ -197,6 +197,114 @@ func TestAccAWSELBUpdate_HealthCheck(t *testing.T) { }) } +func testAccAWSELB_Timeout(t *testing.T) { + var conf elb.LoadBalancerDescription + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSELBDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSELBConfigIdleTimeout, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSELBExists("aws_elb.bar", &conf), + resource.TestCheckResourceAttr( + "aws_elb.bar", "idle_timeout", "200", + ), + ), + }, + }, + }) +} + +func testAccAWSELBUpdate_Timeout(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSELBDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSELBConfigIdleTimeout, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_elb.bar", "idle_timeout", "200", + ), + ), + }, + resource.TestStep{ + Config: testAccAWSELBConfigIdleTimeout_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_elb.bar", "idle_timeout", "400", + ), + ), + }, + }, + }) +} + +func testAccAWSELB_ConnectionDraining(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSELBDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSELBConfigConnectionDraining, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining", "true", + ), + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining_timeout", "400", + ), + ), + }, + }, + }) +} + +func testAccAWSELBUpdate_ConnectionDraining(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSELBDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSELBConfigConnectionDraining, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining", "true", + ), + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining_timeout", "400", + ), + ), + }, + resource.TestStep{ + Config: testAccAWSELBConfigConnectionDraining_update_timeout, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining", "true", + ), + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining_timeout", "600", + ), + ), + }, + resource.TestStep{ + Config: testAccAWSELBConfigConnectionDraining_update_disable, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_elb.bar", "connection_draining", "false", + ), + ), + }, + }, + }) +} + func testAccCheckAWSELBDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).elbconn @@ -452,3 +560,85 @@ resource "aws_elb" "bar" { } } ` + +const testAccAWSELBConfigIdleTimeout = ` +resource "aws_elb" "bar" { + name = "foobar-terraform-test" + availability_zones = ["us-west-2a"] + + listener { + instance_port = 8000 + instance_protocol = "http" + lb_port = 80 + lb_protocol = "http" + } + + idle_timeout = 200 +} +` + +const testAccAWSELBConfigIdleTimeout_update = ` +resource "aws_elb" "bar" { + name = "foobar-terraform-test" + availability_zones = ["us-west-2a"] + + listener { + instance_port = 8000 + instance_protocol = "http" + lb_port = 80 + lb_protocol = "http" + } + + idle_timeout = 400 +} +` + +const testAccAWSELBConfigConnectionDraining = ` +resource "aws_elb" "bar" { + name = "foobar-terraform-test" + availability_zones = ["us-west-2a"] + + listener { + instance_port = 8000 + instance_protocol = "http" + lb_port = 80 + lb_protocol = "http" + } + + connection_draining = true + connection_draining_timeout = 400 +} +` + +const testAccAWSELBConfigConnectionDraining_update_timeout = ` +resource "aws_elb" "bar" { + name = "foobar-terraform-test" + availability_zones = ["us-west-2a"] + + listener { + instance_port = 8000 + instance_protocol = "http" + lb_port = 80 + lb_protocol = "http" + } + + connection_draining = true + connection_draining_timeout = 400 +} +` + +const testAccAWSELBConfigConnectionDraining_update_disable = ` +resource "aws_elb" "bar" { + name = "foobar-terraform-test" + availability_zones = ["us-west-2a"] + + listener { + instance_port = 8000 + instance_protocol = "http" + lb_port = 80 + lb_protocol = "http" + } + + connection_draining = false +} +` diff --git a/website/source/docs/providers/aws/r/elb.html.markdown b/website/source/docs/providers/aws/r/elb.html.markdown index 31e1eb448..ff5dd2d58 100644 --- a/website/source/docs/providers/aws/r/elb.html.markdown +++ b/website/source/docs/providers/aws/r/elb.html.markdown @@ -43,6 +43,9 @@ resource "aws_elb" "bar" { instances = ["${aws_instance.foo.id}"] cross_zone_load_balancing = true + idle_timeout = 400 + connection_draining = true + connection_draining_timeout = 400 } ``` @@ -59,6 +62,9 @@ The following arguments are supported: * `listener` - (Required) A list of listener blocks. Listeners documented below. * `health_check` - (Optional) A health_check block. Health Check documented below. * `cross_zone_load_balancing` - (Optional) Enable cross-zone load balancing. +* `idle_timeout` - (Optional) The time in seconds that the connection is allowed to be idle. Default: 300. +* `connection_draining` - (Optional) Boolean to enable connection draining. +* `connection_draining_timeout` - (Optional) The time in seconds to allow for connections to drain. Exactly one of `availability_zones` or `subnets` must be specified: this determines if the ELB exists in a VPC or in EC2-classic.