Skip to content

Commit

Permalink
provider/aws: Support Tags for aws_alb and aws_alb_target_group (h…
Browse files Browse the repository at this point in the history
…ashicorp#8422)

resources

Fixes hashicorp#8420

Adds the ability to update tags on the ALB resource as well as
supporting tags on `aws_alb_target_group`

```
ALB Tests:

% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSALB_'                                                                                                                         2 ↵ ✹
==> Checking that code complies with gofmt requirements...
/Users/stacko/Code/go/bin/stringer
go generate $(go list ./... | grep -v /terraform/vendor/)
2016/08/23 19:30:16 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSALB_ -timeout 120m
=== RUN   TestAccAWSALB_basic
--- PASS: TestAccAWSALB_basic (67.18s)
=== RUN   TestAccAWSALB_tags
--- PASS: TestAccAWSALB_tags (99.88s)
=== RUN   TestAccAWSALB_noSecurityGroup
--- PASS: TestAccAWSALB_noSecurityGroup (62.49s)
=== RUN   TestAccAWSALB_accesslogs
--- PASS: TestAccAWSALB_accesslogs (126.25s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	355.835s
```

```
ALB Target Group Tests:

% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSALBTargetGroup_'
==> Checking that code complies with gofmt requirements...
/Users/stacko/Code/go/bin/stringer
go generate $(go list ./... | grep -v /terraform/vendor/)
2016/08/23 19:37:37 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSALBTargetGroup_ -timeout 120m
=== RUN   TestAccAWSALBTargetGroup_basic
--- PASS: TestAccAWSALBTargetGroup_basic (47.26s)
=== RUN   TestAccAWSALBTargetGroup_tags
--- PASS: TestAccAWSALBTargetGroup_tags (81.01s)
=== RUN   TestAccAWSALBTargetGroup_updateHealthCheck
--- PASS: TestAccAWSALBTargetGroup_updateHealthCheck (78.74s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	207.025s
```
  • Loading branch information
stack72 authored and Richard Bowden committed Aug 27, 2016
1 parent 3ec33cc commit c71b4e0
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 25 deletions.
29 changes: 6 additions & 23 deletions builtin/providers/aws/resource_aws_alb.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ func resourceAwsAlbRead(d *schema.ResourceData, meta interface{}) error {
func resourceAwsAlbUpdate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn

if !d.IsNewResource() {
if err := setElbV2Tags(elbconn, d); err != nil {
return errwrap.Wrapf("Error Modifying Tags on ALB: {{err}}", err)
}
}

attributes := make([]*elbv2.LoadBalancerAttribute, 0)

if d.HasChange("access_logs") {
Expand Down Expand Up @@ -310,29 +316,6 @@ func resourceAwsAlbDelete(d *schema.ResourceData, meta interface{}) error {
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 {
Expand Down
6 changes: 6 additions & 0 deletions builtin/providers/aws/resource_aws_alb_target_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ func resourceAwsAlbTargetGroup() *schema.Resource {
},
},
},

"tags": tagsSchema(),
},
}
}
Expand Down Expand Up @@ -258,6 +260,10 @@ func resourceAwsAlbTargetGroupRead(d *schema.ResourceData, meta interface{}) err
func resourceAwsAlbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbv2conn

if err := setElbV2Tags(elbconn, d); err != nil {
return errwrap.Wrapf("Error Modifying Tags on ALB Target Group: {{err}}", err)
}

if d.HasChange("health_check") {
healthChecks := d.Get("health_check").([]interface{})

Expand Down
75 changes: 75 additions & 0 deletions builtin/providers/aws/resource_aws_alb_target_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,37 @@ func TestAccAWSALBTargetGroup_basic(t *testing.T) {
})
}

func TestAccAWSALBTargetGroup_tags(t *testing.T) {
var conf elbv2.TargetGroup
targetGroupName := fmt.Sprintf("test-target-group-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: "aws_alb_target_group.test",
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSALBTargetGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSALBTargetGroupConfig_basic(targetGroupName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSALBTargetGroupExists("aws_alb_target_group.test", &conf),
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.%", "1"),
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.TestName", "TestAccAWSALBTargetGroup_basic"),
),
},
{
Config: testAccAWSALBTargetGroupConfig_updateTags(targetGroupName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSALBTargetGroupExists("aws_alb_target_group.test", &conf),
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.%", "2"),
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.Environment", "Production"),
resource.TestCheckResourceAttr("aws_alb_target_group.test", "tags.Type", "ALB Target Group"),
),
},
},
})
}

func TestAccAWSALBTargetGroup_updateHealthCheck(t *testing.T) {
var conf elbv2.TargetGroup
targetGroupName := fmt.Sprintf("test-target-group-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
Expand Down Expand Up @@ -198,6 +229,50 @@ func testAccAWSALBTargetGroupConfig_basic(targetGroupName string) string {
unhealthy_threshold = 3
matcher = "200-299"
}
tags {
TestName = "TestAccAWSALBTargetGroup_basic"
}
}
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
tags {
TestName = "TestAccAWSALBTargetGroup_basic"
}
}`, targetGroupName)
}

func testAccAWSALBTargetGroupConfig_updateTags(targetGroupName string) string {
return fmt.Sprintf(`resource "aws_alb_target_group" "test" {
name = "%s"
port = 443
protocol = "HTTPS"
vpc_id = "${aws_vpc.test.id}"
deregistration_delay = 200
stickiness {
type = "lb_cookie"
cookie_duration = 10000
}
health_check {
path = "/health"
interval = 60
port = 8081
protocol = "HTTP"
timeout = 3
healthy_threshold = 3
unhealthy_threshold = 3
matcher = "200-299"
}
tags {
Environment = "Production"
Type = "ALB Target Group"
}
}
resource "aws_vpc" "test" {
Expand Down
102 changes: 100 additions & 2 deletions builtin/providers/aws/resource_aws_alb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,37 @@ func TestAccAWSALB_basic(t *testing.T) {
})
}

func TestAccAWSALB_tags(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", "tags.%", "1"),
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.TestName", "TestAccAWSALB_basic"),
),
},
{
Config: testAccAWSALBConfig_updatedTags(albName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSALBExists("aws_alb.alb_test", &conf),
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.%", "2"),
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.Type", "Sample Type Tag"),
resource.TestCheckResourceAttr("aws_alb.alb_test", "tags.Environment", "Production"),
),
},
},
})
}

// TestAccAWSALB_noSecurityGroup regression tests the issue in #8264,
// where if an ALB is created without a security group, a default one
// is assigned.
Expand Down Expand Up @@ -118,7 +149,7 @@ func TestAccAWSALB_accesslogs(t *testing.T) {
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", "tags.TestName", "TestAccAWSALB_basic1"),
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"),
Expand Down Expand Up @@ -237,6 +268,73 @@ resource "aws_subnet" "alb_test" {
}
}
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_updatedTags(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 {
Environment = "Production"
Type = "Sample Type Tag"
}
}
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"
Expand Down Expand Up @@ -278,7 +376,7 @@ func testAccAWSALBConfig_accessLogs(albName, bucketName string) string {
}
tags {
TestName = "TestAccAWSALB_basic"
TestName = "TestAccAWSALB_basic1"
}
}
Expand Down
81 changes: 81 additions & 0 deletions builtin/providers/aws/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/hashicorp/terraform/helper/schema"
)

Expand All @@ -17,6 +18,43 @@ func tagsSchema() *schema.Schema {
}
}

func setElbV2Tags(conn *elbv2.ELBV2, d *schema.ResourceData) error {
if d.HasChange("tags") {
oraw, nraw := d.GetChange("tags")
o := oraw.(map[string]interface{})
n := nraw.(map[string]interface{})
create, remove := diffElbV2Tags(tagsFromMapELBv2(o), tagsFromMapELBv2(n))

// Set tags
if len(remove) > 0 {
var tagKeys []*string
for _, tag := range remove {
tagKeys = append(tagKeys, tag.Key)
}
log.Printf("[DEBUG] Removing tags: %#v from %s", remove, d.Id())
_, err := conn.RemoveTags(&elbv2.RemoveTagsInput{
ResourceArns: []*string{aws.String(d.Id())},
TagKeys: tagKeys,
})
if err != nil {
return err
}
}
if len(create) > 0 {
log.Printf("[DEBUG] Creating tags: %s for %s", create, d.Id())
_, err := conn.AddTags(&elbv2.AddTagsInput{
ResourceArns: []*string{aws.String(d.Id())},
Tags: create,
})
if err != nil {
return err
}
}
}

return nil
}

// setTags is a helper to set the tags for a resource. It expects the
// tags field to be named "tags"
func setTags(conn *ec2.EC2, d *schema.ResourceData) error {
Expand Down Expand Up @@ -97,3 +135,46 @@ func tagsToMap(ts []*ec2.Tag) map[string]string {

return result
}

func diffElbV2Tags(oldTags, newTags []*elbv2.Tag) ([]*elbv2.Tag, []*elbv2.Tag) {
// First, we're creating everything we have
create := make(map[string]interface{})
for _, t := range newTags {
create[*t.Key] = *t.Value
}

// Build the list of what to remove
var remove []*elbv2.Tag
for _, t := range oldTags {
old, ok := create[*t.Key]
if !ok || old != *t.Value {
// Delete it!
remove = append(remove, t)
}
}

return tagsFromMapELBv2(create), remove
}

// 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
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The following arguments are supported:
* `deregistration_delay` - (Optional) The amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused. The range is 0-3600 seconds. The default value is 300 seconds.
* `stickiness` - (Optional) A Stickiness block. Stickiness blocks are documented below.
* `health_check` - (Optional) A Health Check block. Health Check blocks are documented below.
* `tags` - (Optional) A mapping of tags to assign to the resource.

Stickiness Blocks (`stickiness`) support the following:

Expand Down

0 comments on commit c71b4e0

Please sign in to comment.