Skip to content

Commit

Permalink
Merge pull request #3537 from mpilar/cross_zone_nlb
Browse files Browse the repository at this point in the history
resource/aws_lb: Add Cross Zone Load Balancing support for NLBs
  • Loading branch information
bflad authored Mar 2, 2018
2 parents d33f0ba + 7c89b7c commit eae509a
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 24 deletions.
48 changes: 33 additions & 15 deletions aws/resource_aws_lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
func resourceAwsLb() *schema.Resource {
return &schema.Resource{
Create: resourceAwsLbCreate,
Read: resoureAwsLbRead,
Read: resourceAwsLbRead,
Update: resourceAwsLbUpdate,
Delete: resourceAwsLbDelete,
// Subnets are ForceNew for Network Load Balancers
Expand Down Expand Up @@ -157,6 +157,12 @@ func resourceAwsLb() *schema.Resource {
Default: 60,
},

"enable_cross_zone_load_balancing": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},

"ip_address_type": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -247,7 +253,7 @@ func resourceAwsLbCreate(d *schema.ResourceData, meta interface{}) error {

lb := resp.LoadBalancers[0]
d.SetId(*lb.LoadBalancerArn)
log.Printf("[INFO] ALB ID: %s", d.Id())
log.Printf("[INFO] LB ID: %s", d.Id())

stateConf := &resource.StateChangeConf{
Pending: []string{"provisioning", "failed"},
Expand All @@ -265,7 +271,7 @@ func resourceAwsLbCreate(d *schema.ResourceData, meta interface{}) error {
}
dLb := describeResp.LoadBalancers[0]

log.Printf("[INFO] ALB state: %s", *dLb.State.Code)
log.Printf("[INFO] LB state: %s", *dLb.State.Code)

return describeResp, *dLb.State.Code, nil
},
Expand All @@ -281,7 +287,7 @@ func resourceAwsLbCreate(d *schema.ResourceData, meta interface{}) error {
return resourceAwsLbUpdate(d, meta)
}

func resoureAwsLbRead(d *schema.ResourceData, meta interface{}) error {
func resourceAwsLbRead(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn
lbArn := d.Id()

Expand Down Expand Up @@ -362,6 +368,14 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {
})
}

// It's important to know that Idle timeout is only supported for Network Loadbalancers
if d.Get("load_balancer_type").(string) == "network" && d.HasChange("enable_cross_zone_load_balancing") {
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
Key: aws.String("load_balancing.cross_zone.enabled"),
Value: aws.String(fmt.Sprintf("%t", d.Get("enable_cross_zone_load_balancing").(bool))),
})
}

if len(attributes) != 0 {
input := &elbv2.ModifyLoadBalancerAttributesInput{
LoadBalancerArn: aws.String(d.Id()),
Expand All @@ -371,7 +385,7 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] ALB Modify Load Balancer Attributes Request: %#v", input)
_, err := elbconn.ModifyLoadBalancerAttributes(input)
if err != nil {
return fmt.Errorf("Failure configuring ALB attributes: %s", err)
return fmt.Errorf("Failure configuring LB attributes: %s", err)
}
}

Expand All @@ -384,7 +398,7 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {
}
_, err := elbconn.SetSecurityGroups(params)
if err != nil {
return fmt.Errorf("Failure Setting ALB Security Groups: %s", err)
return fmt.Errorf("Failure Setting LB Security Groups: %s", err)
}

}
Expand All @@ -403,7 +417,7 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {

_, err := elbconn.SetSubnets(params)
if err != nil {
return fmt.Errorf("Failure Setting ALB Subnets: %s", err)
return fmt.Errorf("Failure Setting LB Subnets: %s", err)
}
}

Expand All @@ -416,7 +430,7 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {

_, err := elbconn.SetIpAddressType(params)
if err != nil {
return fmt.Errorf("Failure Setting ALB IP Address Type: %s", err)
return fmt.Errorf("Failure Setting LB IP Address Type: %s", err)
}

}
Expand All @@ -437,7 +451,7 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {
}
dLb := describeResp.LoadBalancers[0]

log.Printf("[INFO] ALB state: %s", *dLb.State.Code)
log.Printf("[INFO] LB state: %s", *dLb.State.Code)

return describeResp, *dLb.State.Code, nil
},
Expand All @@ -450,20 +464,20 @@ func resourceAwsLbUpdate(d *schema.ResourceData, meta interface{}) error {
return err
}

return resoureAwsLbRead(d, meta)
return resourceAwsLbRead(d, meta)
}

func resourceAwsLbDelete(d *schema.ResourceData, meta interface{}) error {
lbconn := meta.(*AWSClient).elbv2conn

log.Printf("[INFO] Deleting ALB: %s", d.Id())
log.Printf("[INFO] Deleting LB: %s", d.Id())

// Destroy the load balancer
deleteElbOpts := elbv2.DeleteLoadBalancerInput{
LoadBalancerArn: aws.String(d.Id()),
}
if _, err := lbconn.DeleteLoadBalancer(&deleteElbOpts); err != nil {
return fmt.Errorf("Error deleting ALB: %s", err)
return fmt.Errorf("Error deleting LB: %s", err)
}

conn := meta.(*AWSClient).ec2conn
Expand Down Expand Up @@ -642,7 +656,7 @@ func flattenAwsLbResource(d *schema.ResourceData, meta interface{}, lb *elbv2.Lo
ResourceArns: []*string{lb.LoadBalancerArn},
})
if err != nil {
return errwrap.Wrapf("Error retrieving ALB Tags: {{err}}", err)
return errwrap.Wrapf("Error retrieving LB Tags: {{err}}", err)
}

var et []*elbv2.Tag
Expand All @@ -658,7 +672,7 @@ func flattenAwsLbResource(d *schema.ResourceData, meta interface{}, lb *elbv2.Lo
LoadBalancerArn: aws.String(d.Id()),
})
if err != nil {
return errwrap.Wrapf("Error retrieving ALB Attributes: {{err}}", err)
return errwrap.Wrapf("Error retrieving LB Attributes: {{err}}", err)
}

accessLogMap := map[string]interface{}{}
Expand All @@ -679,8 +693,12 @@ func flattenAwsLbResource(d *schema.ResourceData, meta interface{}, lb *elbv2.Lo
d.Set("idle_timeout", timeout)
case "deletion_protection.enabled":
protectionEnabled := (*attr.Value) == "true"
log.Printf("[DEBUG] Setting ALB Deletion Protection Enabled: %t", protectionEnabled)
log.Printf("[DEBUG] Setting LB Deletion Protection Enabled: %t", protectionEnabled)
d.Set("enable_deletion_protection", protectionEnabled)
case "load_balancing.cross_zone.enabled":
crossZoneLbEnabled := (*attr.Value) == "true"
log.Printf("[DEBUG] Setting NLB Cross Zone Load Balancing Enabled: %t", crossZoneLbEnabled)
d.Set("enable_cross_zone_load_balancing", crossZoneLbEnabled)
}
}

Expand Down
53 changes: 44 additions & 9 deletions aws/resource_aws_lb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func TestAccAWSLB_basic(t *testing.T) {
})
}

func TestAccAWSLB_networkLoadbalancer(t *testing.T) {
func TestAccAWSLB_networkLoadbalancerBasic(t *testing.T) {
var conf elbv2.LoadBalancer
lbName := fmt.Sprintf("testaccawslb-basic-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

Expand All @@ -90,7 +90,7 @@ func TestAccAWSLB_networkLoadbalancer(t *testing.T) {
CheckDestroy: testAccCheckAWSLBDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLBConfig_networkLoadbalancer(lbName),
Config: testAccAWSLBConfig_networkLoadbalancer(lbName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLBExists("aws_lb.lb_test", &conf),
resource.TestCheckResourceAttr("aws_lb.lb_test", "name", lbName),
Expand Down Expand Up @@ -128,6 +128,7 @@ func TestAccAWSLB_networkLoadbalancerEIP(t *testing.T) {
resource.TestCheckResourceAttrSet("aws_lb.test", "zone_id"),
resource.TestCheckResourceAttrSet("aws_lb.test", "dns_name"),
resource.TestCheckResourceAttrSet("aws_lb.test", "arn"),
resource.TestCheckResourceAttr("aws_lb.test", "enable_cross_zone_load_balancing", "true"),
resource.TestCheckResourceAttr("aws_lb.test", "load_balancer_type", "network"),
resource.TestCheckResourceAttr("aws_lb.test", "subnet_mapping.#", "2"),
),
Expand Down Expand Up @@ -157,6 +158,7 @@ func TestAccAWSLBBackwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttr("aws_alb.lb_test", "tags.%", "1"),
resource.TestCheckResourceAttr("aws_alb.lb_test", "tags.Name", "TestAccAWSALB_basic"),
resource.TestCheckResourceAttr("aws_alb.lb_test", "enable_deletion_protection", "false"),
resource.TestCheckResourceAttr("aws_alb.lb_test", "enable_cross_zone_load_balancing", "false"),
resource.TestCheckResourceAttr("aws_alb.lb_test", "idle_timeout", "30"),
resource.TestCheckResourceAttr("aws_alb.lb_test", "ip_address_type", "ipv4"),
resource.TestCheckResourceAttr("aws_alb.lb_test", "load_balancer_type", "application"),
Expand Down Expand Up @@ -263,6 +265,35 @@ func TestAccAWSLB_tags(t *testing.T) {
})
}

func TestAccAWSLB_networkLoadbalancer_updateCrossZone(t *testing.T) {
var pre, post elbv2.LoadBalancer
lbName := fmt.Sprintf("testaccawslb-nlbcz-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: "aws_lb.lb_test",
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLBDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLBConfig_networkLoadbalancer(lbName, true),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLBExists("aws_lb.lb_test", &pre),
resource.TestCheckResourceAttr("aws_lb.lb_test", "enable_cross_zone_load_balancing", "true"),
),
},
{
Config: testAccAWSLBConfig_networkLoadbalancer(lbName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLBExists("aws_lb.lb_test", &post),
resource.TestCheckResourceAttr("aws_lb.lb_test", "enable_cross_zone_load_balancing", "false"),
testAccCheckAWSlbARNs(&pre, &post),
),
},
},
})
}

func TestAccAWSLB_updatedSecurityGroups(t *testing.T) {
var pre, post elbv2.LoadBalancer
lbName := fmt.Sprintf("testaccawslb-basic-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
Expand Down Expand Up @@ -861,10 +892,11 @@ resource "aws_lb" "lb_test" {
"${aws_subnet.alb_test_3.id}",
]
load_balancer_type = "network"
internal = true
idle_timeout = 60
enable_deletion_protection = false
load_balancer_type = "network"
internal = true
idle_timeout = 60
enable_deletion_protection = false
enable_cross_zone_load_balancing = false
tags {
Name = "testAccAWSLBConfig_networkLoadbalancer_subnets"
Expand Down Expand Up @@ -902,13 +934,15 @@ resource "aws_subnet" "alb_test_3" {
}
`, lbName)
}
func testAccAWSLBConfig_networkLoadbalancer(lbName string) string {

func testAccAWSLBConfig_networkLoadbalancer(lbName string, cz bool) string {
return fmt.Sprintf(`resource "aws_lb" "lb_test" {
name = "%s"
internal = true
load_balancer_type = "network"
enable_deletion_protection = false
enable_deletion_protection = false
enable_cross_zone_load_balancing = %t
subnet_mapping {
subnet_id = "${aws_subnet.alb_test.id}"
Expand Down Expand Up @@ -938,7 +972,7 @@ resource "aws_subnet" "alb_test" {
}
}
`, lbName)
`, lbName, cz)
}

func testAccAWSLBConfig_networkLoadBalancerEIP(lbName string) string {
Expand Down Expand Up @@ -980,6 +1014,7 @@ resource "aws_route_table_association" "a" {
resource "aws_lb" "test" {
name = "%s"
load_balancer_type = "network"
enable_cross_zone_load_balancing = true
subnet_mapping {
subnet_id = "${aws_subnet.public.0.id}"
allocation_id = "${aws_eip.lb.0.id}"
Expand Down
2 changes: 2 additions & 0 deletions website/docs/r/lb.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ will for load balancers of type `network` will force a recreation of the resourc
* `idle_timeout` - (Optional) The time in seconds that the connection is allowed to be idle. Default: 60.
* `enable_deletion_protection` - (Optional) If true, deletion of the load balancer will be disabled via
the AWS API. This will prevent Terraform from deleting the load balancer. Defaults to `false`.
* `enable_cross_zone_load_balancing` - (Optional) If true, cross-zone load balancing of the load balancer will be enabled.
This is a `network` load balancer feature. Defaults to `false`.
* `ip_address_type` - (Optional) The type of IP addresses used by the subnets for your load balancer. The possible values are `ipv4` and `dualstack`
* `tags` - (Optional) A mapping of tags to assign to the resource.

Expand Down

0 comments on commit eae509a

Please sign in to comment.