Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tagging support to ec2 traffic mirror session #12134

Merged
merged 2 commits into from
Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions aws/resource_aws_ec2_traffic_mirror_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsEc2TrafficMirrorSession() *schema.Resource {
Expand Down Expand Up @@ -52,6 +53,7 @@ func resourceAwsEc2TrafficMirrorSession() *schema.Resource {
Computed: true,
ValidateFunc: validation.IntBetween(1, 16777216),
},
"tags": tagsSchema(),
},
}
}
Expand Down Expand Up @@ -81,6 +83,10 @@ func resourceAwsEc2TrafficMirrorSessionCreate(d *schema.ResourceData, meta inter
input.VirtualNetworkId = aws.Int64(int64(v.(int)))
}

if v, ok := d.GetOk("tags"); ok {
input.TagSpecifications = ec2TagSpecificationsFromMap(v.(map[string]interface{}), ec2.ResourceTypeTrafficMirrorSession)
}

out, err := conn.CreateTrafficMirrorSession(input)
if nil != err {
return fmt.Errorf("Error creating traffic mirror session %v", err)
Expand Down Expand Up @@ -153,6 +159,14 @@ func resourceAwsEc2TrafficMirrorSessionUpdate(d *schema.ResourceData, meta inter
return fmt.Errorf("Error updating traffic mirror session %v", err)
}

if d.HasChange("tags") {
o, n := d.GetChange("tags")

if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil {
return fmt.Errorf("error updating EC2 Traffic Mirror Session (%s) tags: %s", d.Id(), err)
}
}

return resourceAwsEc2TrafficMirrorSessionRead(d, meta)
}

Expand All @@ -167,6 +181,13 @@ func resourceAwsEc2TrafficMirrorSessionRead(d *schema.ResourceData, meta interfa
}

out, err := conn.DescribeTrafficMirrorSessions(input)

if isAWSErr(err, "InvalidTrafficMirrorSessionId.NotFound", "") {
log.Printf("[WARN] EC2 Traffic Mirror Session (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if nil != err {
return fmt.Errorf("error describing EC2 Traffic Mirror Session (%s): %w", sessionId, err)
}
Expand All @@ -186,6 +207,10 @@ func resourceAwsEc2TrafficMirrorSessionRead(d *schema.ResourceData, meta interfa
d.Set("packet_length", session.PacketLength)
d.Set("virtual_network_id", session.VirtualNetworkId)

if err := d.Set("tags", keyvaluetags.Ec2KeyValueTags(session.Tags).IgnoreAws().Map()); err != nil {
return fmt.Errorf("error setting tags: %s", err)
}

return nil
}

Expand Down
179 changes: 157 additions & 22 deletions aws/resource_aws_ec2_traffic_mirror_session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import (
)

func TestAccAWSEc2TrafficMirrorSession_basic(t *testing.T) {
resourceName := "aws_ec2_traffic_mirror_session.session"
var v ec2.TrafficMirrorSession
resourceName := "aws_ec2_traffic_mirror_session.test"
description := "test session"
session := acctest.RandIntRange(1, 32766)
lbName := acctest.RandString(31)
rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
pLen := acctest.RandIntRange(1, 255)
vni := acctest.RandIntRange(1, 16777216)

Expand All @@ -33,20 +34,21 @@ func TestAccAWSEc2TrafficMirrorSession_basic(t *testing.T) {
Steps: []resource.TestStep{
//create
{
Config: testAccTrafficMirrorSessionConfig(lbName, session),
Config: testAccTrafficMirrorSessionConfig(rName, session),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName),
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "description", ""),
resource.TestCheckResourceAttr(resourceName, "packet_length", "0"),
resource.TestCheckResourceAttr(resourceName, "session_number", strconv.Itoa(session)),
resource.TestMatchResourceAttr(resourceName, "virtual_network_id", regexp.MustCompile(`\d+`)),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
),
},
// update of description, packet length and VNI
{
Config: testAccTrafficMirrorSessionConfigWithOptionals(description, lbName, session, pLen, vni),
Config: testAccTrafficMirrorSessionConfigWithOptionals(description, rName, session, pLen, vni),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName),
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "description", description),
resource.TestCheckResourceAttr(resourceName, "packet_length", strconv.Itoa(pLen)),
resource.TestCheckResourceAttr(resourceName, "session_number", strconv.Itoa(session)),
Expand All @@ -55,9 +57,9 @@ func TestAccAWSEc2TrafficMirrorSession_basic(t *testing.T) {
},
// removal of description, packet length and VNI
{
Config: testAccTrafficMirrorSessionConfig(lbName, session),
Config: testAccTrafficMirrorSessionConfig(rName, session),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName),
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "description", ""),
resource.TestCheckResourceAttr(resourceName, "packet_length", "0"),
resource.TestCheckResourceAttr(resourceName, "session_number", strconv.Itoa(session)),
Expand All @@ -74,7 +76,81 @@ func TestAccAWSEc2TrafficMirrorSession_basic(t *testing.T) {
})
}

func testAccCheckAWSEc2TrafficMirrorSessionExists(name string) resource.TestCheckFunc {
func TestAccAWSEc2TrafficMirrorSession_tags(t *testing.T) {
var v ec2.TrafficMirrorSession
resourceName := "aws_ec2_traffic_mirror_session.test"
session := acctest.RandIntRange(1, 32766)
rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAWSEc2TrafficMirrorSession(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEc2TrafficMirrorSessionDestroy,
Steps: []resource.TestStep{
{
Config: testAccTrafficMirrorSessionConfigTags1(rName, "key1", "value1", session),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccTrafficMirrorSessionConfigTags2(rName, "key1", "value1updated", "key2", "value2", session),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "2"),
resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"),
resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"),
),
},
{
Config: testAccTrafficMirrorSessionConfigTags1(rName, "key2", "value2", session),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"),
),
},
},
})
}

func TestAccAWSEc2TrafficMirrorSession_disappears(t *testing.T) {
var v ec2.TrafficMirrorSession
resourceName := "aws_ec2_traffic_mirror_session.test"
session := acctest.RandIntRange(1, 32766)
rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAWSEc2TrafficMirrorSession(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEc2TrafficMirrorSessionDestroy,
Steps: []resource.TestStep{
{
Config: testAccTrafficMirrorSessionConfig(rName, session),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEc2TrafficMirrorSessionExists(resourceName, &v),
testAccCheckAWSEc2TrafficMirrorSessionDisappears(&v),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckAWSEc2TrafficMirrorSessionExists(name string, session *ec2.TrafficMirrorSession) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
Expand All @@ -99,11 +175,24 @@ func testAccCheckAWSEc2TrafficMirrorSessionExists(name string) resource.TestChec
return fmt.Errorf("Traffic mirror session %s not found", rs.Primary.ID)
}

*session = *out.TrafficMirrorSessions[0]

return nil
}
}

func testAccTrafficMirrorSessionConfigBase(lbName string) string {
func testAccCheckAWSEc2TrafficMirrorSessionDisappears(session *ec2.TrafficMirrorSession) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ec2conn
_, err := conn.DeleteTrafficMirrorSession(&ec2.DeleteTrafficMirrorSessionInput{
TrafficMirrorSessionId: session.TrafficMirrorSessionId,
})

return err
}
}

func testAccTrafficMirrorSessionConfigBase(rName string) string {
return fmt.Sprintf(`
data "aws_availability_zones" "azs" {
state = "available"
Expand All @@ -127,35 +216,52 @@ data "aws_ami" "amzn-linux" {

resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"

tags = {
Name = %[1]q
}
}

resource "aws_subnet" "sub1" {
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "10.0.0.0/24"
availability_zone = "${data.aws_availability_zones.azs.names[0]}"

tags = {
Name = %[1]q
}
}

resource "aws_subnet" "sub2" {
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "${data.aws_availability_zones.azs.names[1]}"

tags = {
Name = %[1]q
}
}

resource "aws_instance" "src" {
ami = "${data.aws_ami.amzn-linux.id}"
instance_type = "m5.large" # m5.large required because only Nitro instances support mirroring
subnet_id = "${aws_subnet.sub1.id}"

tags = {
Name = %[1]q
}
}

resource "aws_lb" "lb" {
name = "%s"
name = %[1]q
internal = true
load_balancer_type = "network"
subnets = ["${aws_subnet.sub1.id}", "${aws_subnet.sub2.id}"]

enable_deletion_protection = false

tags = {
Name = %[1]q
Environment = "production"
}
}
Expand All @@ -167,27 +273,56 @@ resource "aws_ec2_traffic_mirror_target" "target" {
network_load_balancer_arn = "${aws_lb.lb.arn}"
}

`, lbName)
`, rName)
}

func testAccTrafficMirrorSessionConfig(lbName string, session int) string {
return fmt.Sprintf(`
%s

resource "aws_ec2_traffic_mirror_session" "session" {
func testAccTrafficMirrorSessionConfig(rName string, session int) string {
return testAccTrafficMirrorSessionConfigBase(rName) + fmt.Sprintf(`
resource "aws_ec2_traffic_mirror_session" "test" {
traffic_mirror_filter_id = "${aws_ec2_traffic_mirror_filter.filter.id}"
traffic_mirror_target_id = "${aws_ec2_traffic_mirror_target.target.id}"
network_interface_id = "${aws_instance.src.primary_network_interface_id}"
session_number = %d
}
`, testAccTrafficMirrorSessionConfigBase(lbName), session)
`, session)
}

func testAccTrafficMirrorSessionConfigTags1(rName, tagKey1, tagValue1 string, session int) string {
return testAccTrafficMirrorSessionConfigBase(rName) + fmt.Sprintf(`
resource "aws_ec2_traffic_mirror_session" "test" {
traffic_mirror_filter_id = "${aws_ec2_traffic_mirror_filter.filter.id}"
traffic_mirror_target_id = "${aws_ec2_traffic_mirror_target.target.id}"
network_interface_id = "${aws_instance.src.primary_network_interface_id}"
session_number = %[3]d

tags = {
%[1]q = %[2]q
}
}
`, tagKey1, tagValue1, session)
}

func testAccTrafficMirrorSessionConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string, session int) string {
return testAccTrafficMirrorSessionConfigBase(rName) + fmt.Sprintf(`
resource "aws_ec2_traffic_mirror_session" "test" {
traffic_mirror_filter_id = "${aws_ec2_traffic_mirror_filter.filter.id}"
traffic_mirror_target_id = "${aws_ec2_traffic_mirror_target.target.id}"
network_interface_id = "${aws_instance.src.primary_network_interface_id}"
session_number = %[5]d

tags = {
%[1]q = %[2]q
%[3]q = %[4]q
}
}
`, tagKey1, tagValue1, tagKey2, tagValue2, session)
}

func testAccTrafficMirrorSessionConfigWithOptionals(description string, lbName string, session, pLen, vni int) string {
func testAccTrafficMirrorSessionConfigWithOptionals(description string, rName string, session, pLen, vni int) string {
return fmt.Sprintf(`
%s

resource "aws_ec2_traffic_mirror_session" "session" {
resource "aws_ec2_traffic_mirror_session" "test" {
description = "%s"
traffic_mirror_filter_id = "${aws_ec2_traffic_mirror_filter.filter.id}"
traffic_mirror_target_id = "${aws_ec2_traffic_mirror_target.target.id}"
Expand All @@ -196,7 +331,7 @@ resource "aws_ec2_traffic_mirror_session" "session" {
packet_length = %d
virtual_network_id = %d
}
`, testAccTrafficMirrorSessionConfigBase(lbName), description, session, pLen, vni)
`, testAccTrafficMirrorSessionConfigBase(rName), description, session, pLen, vni)
}

func testAccPreCheckAWSEc2TrafficMirrorSession(t *testing.T) {
Expand All @@ -205,7 +340,7 @@ func testAccPreCheckAWSEc2TrafficMirrorSession(t *testing.T) {
_, err := conn.DescribeTrafficMirrorSessions(&ec2.DescribeTrafficMirrorSessionsInput{})

if testAccPreCheckSkipError(err) {
t.Skip("skipping traffic mirror sessions acceprance test: ", err)
t.Skip("skipping traffic mirror sessions acceptance test: ", err)
}

if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion website/docs/r/ec2_traffic_mirror_session.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ subcategory: "EC2"
layout: "aws"
page_title: "AWS: aws_ec2_traffic_mirror_session"
description: |-
Provides an Traffic mirror session
Provides a Traffic mirror session
---

# Resource: aws_ec2_traffic_mirror_session
Expand Down Expand Up @@ -44,6 +44,7 @@ The following arguments are supported:
* `packet_length` - (Optional) The number of bytes in each packet to mirror. These are bytes after the VXLAN header. Do not specify this parameter when you want to mirror the entire packet. To mirror a subset of the packet, set this to the length (in bytes) that you want to mirror.
* `session_number` - (Required) - The session number determines the order in which sessions are evaluated when an interface is used by multiple sessions. The first session with a matching filter is the one that mirrors the packets.
* `virtual_network_id` - (Optional) - The VXLAN ID for the Traffic Mirror session. For more information about the VXLAN protocol, see RFC 7348. If you do not specify a VirtualNetworkId, an account-wide unique id is chosen at random.
* `tags` - (Optional) Key-value mapping of resource tags.

## Attributes Reference

Expand Down