provider/aws: Add `aws_alb` resource
This commit adds a resource, acceptance tests and documentation for the new Application Load Balancer (aws_alb). We choose to use the name alb over the package name, elbv2, in order to avoid confusion. This is the first in a series of commits to fully support the new resources necessary for Application Load Balancers.
This commit is contained in:
parent
ebdfe76530
commit
0b421b6998
|
@ -152,6 +152,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
},
|
},
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
|
"aws_alb": resourceAwsAlb(),
|
||||||
"aws_ami": resourceAwsAmi(),
|
"aws_ami": resourceAwsAmi(),
|
||||||
"aws_ami_copy": resourceAwsAmiCopy(),
|
"aws_ami_copy": resourceAwsAmiCopy(),
|
||||||
"aws_ami_from_instance": resourceAwsAmiFromInstance(),
|
"aws_ami_from_instance": resourceAwsAmiFromInstance(),
|
||||||
|
|
|
@ -0,0 +1,337 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAwsAlb() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsAlbCreate,
|
||||||
|
Read: resourceAwsAlbRead,
|
||||||
|
Update: resourceAwsAlbUpdate,
|
||||||
|
Delete: resourceAwsAlbDelete,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validateElbName,
|
||||||
|
},
|
||||||
|
|
||||||
|
"internal": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"security_groups": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
ForceNew: true,
|
||||||
|
Optional: true,
|
||||||
|
Set: schema.HashString,
|
||||||
|
},
|
||||||
|
|
||||||
|
"subnets": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
ForceNew: true,
|
||||||
|
Required: true,
|
||||||
|
Set: schema.HashString,
|
||||||
|
},
|
||||||
|
|
||||||
|
"access_logs": {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"bucket": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"prefix": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"enable_deletion_protection": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"idle_timeout": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Default: 60,
|
||||||
|
},
|
||||||
|
|
||||||
|
"vpc_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"zone_id": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"dns_name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"tags": tagsSchema(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsAlbCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
elbconn := meta.(*AWSClient).elbv2conn
|
||||||
|
|
||||||
|
elbOpts := &elbv2.CreateLoadBalancerInput{
|
||||||
|
Name: aws.String(d.Get("name").(string)),
|
||||||
|
Tags: tagsFromMapELBv2(d.Get("tags").(map[string]interface{})),
|
||||||
|
}
|
||||||
|
|
||||||
|
if scheme, ok := d.GetOk("internal"); ok && scheme.(bool) {
|
||||||
|
elbOpts.Scheme = aws.String("internal")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := d.GetOk("security_groups"); ok {
|
||||||
|
elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List())
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := d.GetOk("subnets"); ok {
|
||||||
|
elbOpts.Subnets = expandStringList(v.(*schema.Set).List())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] ALB create configuration: %#v", elbOpts)
|
||||||
|
|
||||||
|
resp, err := elbconn.CreateLoadBalancer(elbOpts)
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf("Error creating Application Load Balancer: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.LoadBalancers) != 1 {
|
||||||
|
return fmt.Errorf("No load balancers returned following creation of %s", d.Get("name").(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(*resp.LoadBalancers[0].LoadBalancerArn)
|
||||||
|
log.Printf("[INFO] ALB ID: %s", d.Id())
|
||||||
|
|
||||||
|
return resourceAwsAlbUpdate(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsAlbRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
elbconn := meta.(*AWSClient).elbv2conn
|
||||||
|
albArn := d.Id()
|
||||||
|
|
||||||
|
describeAlbOpts := &elbv2.DescribeLoadBalancersInput{
|
||||||
|
LoadBalancerArns: []*string{aws.String(albArn)},
|
||||||
|
}
|
||||||
|
|
||||||
|
describeResp, err := elbconn.DescribeLoadBalancers(describeAlbOpts)
|
||||||
|
if err != nil {
|
||||||
|
if isLoadBalancerNotFound(err) {
|
||||||
|
// The ALB is gone now, so just remove it from the state
|
||||||
|
log.Printf("[WARN] ALB %s not found in AWS, removing from state", d.Id())
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errwrap.Wrapf("Error retrieving ALB: {{err}}", err)
|
||||||
|
}
|
||||||
|
if len(describeResp.LoadBalancers) != 1 {
|
||||||
|
return fmt.Errorf("Unable to find ALB: %#v", describeResp.LoadBalancers)
|
||||||
|
}
|
||||||
|
|
||||||
|
alb := describeResp.LoadBalancers[0]
|
||||||
|
|
||||||
|
d.Set("name", alb.LoadBalancerName)
|
||||||
|
d.Set("internal", (alb.Scheme != nil && *alb.Scheme == "internal"))
|
||||||
|
d.Set("security_groups", flattenStringList(alb.SecurityGroups))
|
||||||
|
d.Set("subnets", flattenSubnetsFromAvailabilityZones(alb.AvailabilityZones))
|
||||||
|
d.Set("vpc_id", alb.VpcId)
|
||||||
|
d.Set("zone_id", alb.CanonicalHostedZoneId)
|
||||||
|
d.Set("dns_name", alb.DNSName)
|
||||||
|
|
||||||
|
respTags, err := elbconn.DescribeTags(&elbv2.DescribeTagsInput{
|
||||||
|
ResourceArns: []*string{alb.LoadBalancerArn},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf("Error retrieving ALB Tags: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var et []*elbv2.Tag
|
||||||
|
if len(respTags.TagDescriptions) > 0 {
|
||||||
|
et = respTags.TagDescriptions[0].Tags
|
||||||
|
}
|
||||||
|
d.Set("tags", tagsToMapELBv2(et))
|
||||||
|
|
||||||
|
attributesResp, err := elbconn.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{
|
||||||
|
LoadBalancerArn: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf("Error retrieving ALB Attributes: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
accessLogMap := map[string]interface{}{}
|
||||||
|
for _, attr := range attributesResp.Attributes {
|
||||||
|
switch *attr.Key {
|
||||||
|
case "access_logs.s3.bucket":
|
||||||
|
accessLogMap["bucket"] = *attr.Value
|
||||||
|
case "access_logs.s3.prefix":
|
||||||
|
accessLogMap["prefix"] = *attr.Value
|
||||||
|
case "idle_timeout.timeout_seconds":
|
||||||
|
timeout, err := strconv.Atoi(*attr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf("Error parsing ALB timeout: {{err}}", err)
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] Setting ALB Timeout Seconds: %d", timeout)
|
||||||
|
d.Set("idle_timeout", timeout)
|
||||||
|
case "deletion_protection.enabled":
|
||||||
|
protectionEnabled := (*attr.Value) == "true"
|
||||||
|
log.Printf("[DEBUG] Setting ALB Deletion Protection Enabled: %t", protectionEnabled)
|
||||||
|
d.Set("enable_deletion_protection", protectionEnabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Setting ALB Access Logs: %#v", accessLogMap)
|
||||||
|
if accessLogMap["bucket"] != "" || accessLogMap["prefix"] != "" {
|
||||||
|
d.Set("access_logs", []interface{}{accessLogMap})
|
||||||
|
} else {
|
||||||
|
d.Set("access_logs", []interface{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsAlbUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
elbconn := meta.(*AWSClient).elbv2conn
|
||||||
|
|
||||||
|
attributes := make([]*elbv2.LoadBalancerAttribute, 0)
|
||||||
|
|
||||||
|
if d.HasChange("access_logs") {
|
||||||
|
logs := d.Get("access_logs").([]interface{})
|
||||||
|
if len(logs) == 1 {
|
||||||
|
log := logs[0].(map[string]interface{})
|
||||||
|
|
||||||
|
attributes = append(attributes,
|
||||||
|
&elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String("access_logs.s3.enabled"),
|
||||||
|
Value: aws.String("true"),
|
||||||
|
},
|
||||||
|
&elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String("access_logs.s3.bucket"),
|
||||||
|
Value: aws.String(log["bucket"].(string)),
|
||||||
|
})
|
||||||
|
|
||||||
|
if prefix, ok := log["prefix"]; ok {
|
||||||
|
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String("access_logs.s3.prefix"),
|
||||||
|
Value: aws.String(prefix.(string)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if len(logs) == 0 {
|
||||||
|
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String("access_logs.s3.enabled"),
|
||||||
|
Value: aws.String("false"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("enable_deletion_protection") {
|
||||||
|
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String("deletion_protection.enabled"),
|
||||||
|
Value: aws.String(fmt.Sprintf("%t", d.Get("enable_deletion_protection").(bool))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("idle_timeout") {
|
||||||
|
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String("idle_timeout.timeout_seconds"),
|
||||||
|
Value: aws.String(fmt.Sprintf("%d", d.Get("idle_timeout").(int))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(attributes) != 0 {
|
||||||
|
input := &elbv2.ModifyLoadBalancerAttributesInput{
|
||||||
|
LoadBalancerArn: aws.String(d.Id()),
|
||||||
|
Attributes: attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 resourceAwsAlbRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsAlbDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
albconn := meta.(*AWSClient).elbv2conn
|
||||||
|
|
||||||
|
log.Printf("[INFO] Deleting ALB: %s", d.Id())
|
||||||
|
|
||||||
|
// Destroy the load balancer
|
||||||
|
deleteElbOpts := elbv2.DeleteLoadBalancerInput{
|
||||||
|
LoadBalancerArn: aws.String(d.Id()),
|
||||||
|
}
|
||||||
|
if _, err := albconn.DeleteLoadBalancer(&deleteElbOpts); err != nil {
|
||||||
|
return fmt.Errorf("Error deleting ALB: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tagsToMapELBv2 turns the list of tags into a map.
|
||||||
|
func tagsToMapELBv2(ts []*elbv2.Tag) map[string]string {
|
||||||
|
result := make(map[string]string)
|
||||||
|
for _, t := range ts {
|
||||||
|
result[*t.Key] = *t.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// tagsFromMapELBv2 returns the tags for the given map of data.
|
||||||
|
func tagsFromMapELBv2(m map[string]interface{}) []*elbv2.Tag {
|
||||||
|
var result []*elbv2.Tag
|
||||||
|
for k, v := range m {
|
||||||
|
result = append(result, &elbv2.Tag{
|
||||||
|
Key: aws.String(k),
|
||||||
|
Value: aws.String(v.(string)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// flattenSubnetsFromAvailabilityZones creates a slice of strings containing the subnet IDs
|
||||||
|
// for the ALB based on the AvailabilityZones structure returned by the API.
|
||||||
|
func flattenSubnetsFromAvailabilityZones(availabilityZones []*elbv2.AvailabilityZone) []string {
|
||||||
|
var result []string
|
||||||
|
for _, az := range availabilityZones {
|
||||||
|
result = append(result, *az.SubnetId)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -0,0 +1,336 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSALB_basic(t *testing.T) {
|
||||||
|
var conf elbv2.LoadBalancer
|
||||||
|
albName := fmt.Sprintf("testaccawsalb-basic-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
IDRefreshName: "aws_alb.alb_test",
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSALBDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testAccAWSALBConfig_basic(albName),
|
||||||
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
|
testAccCheckAWSALBExists("aws_alb.alb_test", &conf),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "name", albName),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "internal", "false"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "subnets.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "security_groups.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.%", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.TestName", "TestAccAWSALB_basic"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "enable_deletion_protection", "false"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "idle_timeout", "30"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "vpc_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "zone_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "dns_name"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccAWSALB_accesslogs(t *testing.T) {
|
||||||
|
var conf elbv2.LoadBalancer
|
||||||
|
bucketName := fmt.Sprintf("testaccawsalbaccesslogs-%s", acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum))
|
||||||
|
albName := fmt.Sprintf("testaccawsalbaccesslog-%s", acctest.RandStringFromCharSet(4, acctest.CharSetAlpha))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
IDRefreshName: "aws_alb.alb_test",
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSALBDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testAccAWSALBConfig_basic(albName),
|
||||||
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
|
testAccCheckAWSALBExists("aws_alb.alb_test", &conf),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "name", albName),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "internal", "false"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "subnets.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "security_groups.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.%", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.TestName", "TestAccAWSALB_basic"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "enable_deletion_protection", "false"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "idle_timeout", "30"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "vpc_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "zone_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "dns_name"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Config: testAccAWSALBConfig_accessLogs(albName, bucketName),
|
||||||
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
|
testAccCheckAWSALBExists("aws_alb.alb_test", &conf),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "name", albName),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "internal", "false"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "subnets.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "security_groups.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.%", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.TestName", "TestAccAWSALB_basic"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "enable_deletion_protection", "false"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "idle_timeout", "50"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "vpc_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "zone_id"),
|
||||||
|
resource.TestCheckResourceAttrSet("aws_alb.alb_test", "dns_name"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "access_logs.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "access_logs.0.bucket", bucketName),
|
||||||
|
resource.TestCheckResourceAttr("aws_alb.alb_test", "access_logs.0.prefix", "testAccAWSALBConfig_accessLogs"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSALBExists(n string, res *elbv2.LoadBalancer) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return errors.New("No ALB ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).elbv2conn
|
||||||
|
|
||||||
|
describe, err := conn.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{
|
||||||
|
LoadBalancerArns: []*string{aws.String(rs.Primary.ID)},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(describe.LoadBalancers) != 1 ||
|
||||||
|
*describe.LoadBalancers[0].LoadBalancerArn != rs.Primary.ID {
|
||||||
|
return errors.New("ALB not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
*res = *describe.LoadBalancers[0]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSALBDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).elbv2conn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_alb" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
describe, err := conn.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{
|
||||||
|
LoadBalancerArns: []*string{aws.String(rs.Primary.ID)},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
if len(describe.LoadBalancers) != 0 &&
|
||||||
|
*describe.LoadBalancers[0].LoadBalancerArn == rs.Primary.ID {
|
||||||
|
return fmt.Errorf("ALB %q still exists", rs.Primary.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the error
|
||||||
|
if isLoadBalancerNotFound(err) {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errwrap.Wrapf("Unexpected error checking ALB destroyed: {{err}}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSALBConfig_basic(albName string) string {
|
||||||
|
return fmt.Sprintf(`resource "aws_alb" "alb_test" {
|
||||||
|
name = "%s"
|
||||||
|
internal = false
|
||||||
|
security_groups = ["${aws_security_group.alb_test.id}"]
|
||||||
|
subnets = ["${aws_subnet.alb_test.*.id}"]
|
||||||
|
|
||||||
|
idle_timeout = 30
|
||||||
|
enable_deletion_protection = false
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "subnets" {
|
||||||
|
default = ["10.0.1.0/24", "10.0.2.0/24"]
|
||||||
|
type = "list"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_availability_zones" "available" {}
|
||||||
|
|
||||||
|
resource "aws_vpc" "alb_test" {
|
||||||
|
cidr_block = "10.0.0.0/16"
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_subnet" "alb_test" {
|
||||||
|
count = 2
|
||||||
|
vpc_id = "${aws_vpc.alb_test.id}"
|
||||||
|
cidr_block = "${element(var.subnets, count.index)}"
|
||||||
|
map_public_ip_on_launch = true
|
||||||
|
availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}"
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "alb_test" {
|
||||||
|
name = "allow_all_alb_test"
|
||||||
|
description = "Used for ALB Testing"
|
||||||
|
vpc_id = "${aws_vpc.alb_test.id}"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
egress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}`, albName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSALBConfig_accessLogs(albName, bucketName string) string {
|
||||||
|
return fmt.Sprintf(`resource "aws_alb" "alb_test" {
|
||||||
|
name = "%s"
|
||||||
|
internal = false
|
||||||
|
security_groups = ["${aws_security_group.alb_test.id}"]
|
||||||
|
subnets = ["${aws_subnet.alb_test.*.id}"]
|
||||||
|
|
||||||
|
idle_timeout = 50
|
||||||
|
enable_deletion_protection = false
|
||||||
|
|
||||||
|
access_logs {
|
||||||
|
bucket = "${aws_s3_bucket.logs.bucket}"
|
||||||
|
prefix = "${var.bucket_prefix}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "bucket_name" {
|
||||||
|
type = "string"
|
||||||
|
default = "%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "bucket_prefix" {
|
||||||
|
type = "string"
|
||||||
|
default = "testAccAWSALBConfig_accessLogs"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "logs" {
|
||||||
|
bucket = "${var.bucket_name}"
|
||||||
|
policy = "${data.aws_iam_policy_document.logs_bucket.json}"
|
||||||
|
# dangerous, only here for the test...
|
||||||
|
force_destroy = true
|
||||||
|
|
||||||
|
tags {
|
||||||
|
Name = "ALB Logs Bucket Test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_caller_identity" "current" {}
|
||||||
|
|
||||||
|
data "aws_elb_service_account" "current" {}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "logs_bucket" {
|
||||||
|
statement {
|
||||||
|
actions = ["s3:PutObject"]
|
||||||
|
effect = "Allow"
|
||||||
|
resources = ["arn:aws:s3:::${var.bucket_name}/${var.bucket_prefix}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"]
|
||||||
|
|
||||||
|
principals = {
|
||||||
|
type = "AWS"
|
||||||
|
identifiers = ["arn:aws:iam::${data.aws_elb_service_account.current.id}:root"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "subnets" {
|
||||||
|
default = ["10.0.1.0/24", "10.0.2.0/24"]
|
||||||
|
type = "list"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_availability_zones" "available" {}
|
||||||
|
|
||||||
|
resource "aws_vpc" "alb_test" {
|
||||||
|
cidr_block = "10.0.0.0/16"
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_subnet" "alb_test" {
|
||||||
|
count = 2
|
||||||
|
vpc_id = "${aws_vpc.alb_test.id}"
|
||||||
|
cidr_block = "${element(var.subnets, count.index)}"
|
||||||
|
map_public_ip_on_launch = true
|
||||||
|
availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}"
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "alb_test" {
|
||||||
|
name = "allow_all_alb_test"
|
||||||
|
description = "Used for ALB Testing"
|
||||||
|
vpc_id = "${aws_vpc.alb_test.id}"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
egress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
tags {
|
||||||
|
TestName = "TestAccAWSALB_basic"
|
||||||
|
}
|
||||||
|
}`, albName, bucketName)
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_alb"
|
||||||
|
sidebar_current: "docs-aws-resource-alb"
|
||||||
|
description: |-
|
||||||
|
Provides an Application Load Balancer resource.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_alb
|
||||||
|
|
||||||
|
Provides an Application Load Balancer resource.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
# Create a new load balancer
|
||||||
|
resource "aws_alb" "test" {
|
||||||
|
name = "test-alb-tf"
|
||||||
|
internal = false
|
||||||
|
security_groups = ["${aws_security_group.alb_sg.id}"]
|
||||||
|
subnets = ["${aws_subnet.public.*.id}"]
|
||||||
|
|
||||||
|
enable_deletion_protection = true
|
||||||
|
|
||||||
|
access_logs {
|
||||||
|
bucket = "${aws_s3_bucket.alb_logs.bucket}"
|
||||||
|
prefix = "test-alb"
|
||||||
|
}
|
||||||
|
|
||||||
|
tags {
|
||||||
|
Environment = "production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Optional) The name of the ALB. By default generated by Terraform.
|
||||||
|
* `internal` - (Optional) If true, the ALB will be internal.
|
||||||
|
* `security_groups` - (Optional) A list of security group IDs to assign to the ELB.
|
||||||
|
* `access_logs` - (Optional) An Access Logs block. Access Logs documented below.
|
||||||
|
* `subnets` - (Required) A list of subnet IDs to attach to the ELB.
|
||||||
|
* `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.
|
||||||
|
* `tags` - (Optional) A mapping of tags to assign to the resource.
|
||||||
|
|
||||||
|
Access Logs (`access_logs`) support the following:
|
||||||
|
|
||||||
|
* `bucket` - (Required) The S3 bucket name to store the logs in.
|
||||||
|
* `prefix` - (Optional) The S3 bucket prefix. Logs are stored in the root if not configured.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported in addition to the arguments listed above:
|
||||||
|
|
||||||
|
* `id` - The ARN of the load balancer
|
||||||
|
* `dns_name` - The DNS name of the load balancer
|
||||||
|
* `canonical_hosted_zone_id` - The canonical hosted zone ID of the load balancer.
|
||||||
|
* `zone_id` - The canonical hosted zone ID of the load balancer (to be used in a Route 53 Alias record)
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
ALBs can be imported using their ARN, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ terraform import aws_alb.bar arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188
|
||||||
|
```
|
|
@ -206,10 +206,14 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
<li<%= sidebar_current(/^docs-aws-resource-(ami|app|autoscaling|ebs|elb|eip|instance|launch|lb|proxy|spot|volume|placement|key-pair|elb_attachment|load-balancer)/) %>>
|
<li<%= sidebar_current(/^docs-aws-resource-(alb|ami|app|autoscaling|ebs|elb|eip|instance|launch|lb|proxy|spot|volume|placement|key-pair|elb_attachment|load-balancer)/) %>>
|
||||||
<a href="#">EC2 Resources</a>
|
<a href="#">EC2 Resources</a>
|
||||||
<ul class="nav nav-visible">
|
<ul class="nav nav-visible">
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-alb") %>>
|
||||||
|
<a href="/docs/providers/aws/r/alb.html">aws_alb</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-ami") %>>
|
<li<%= sidebar_current("docs-aws-resource-ami") %>>
|
||||||
<a href="/docs/providers/aws/r/ami.html">aws_ami</a>
|
<a href="/docs/providers/aws/r/ami.html">aws_ami</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue