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

aws_vpclattice_listener #37964

Merged
merged 9 commits into from
Jul 16, 2024
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
3 changes: 3 additions & 0 deletions .changelog/37964.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_vpclattice_listener: Support `TLS_PASSTHROUGH` as a valid value for `protocol`
```
2 changes: 2 additions & 0 deletions internal/service/vpclattice/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package vpclattice
// Exports for use in tests only.
var (
FindAccessLogSubscriptionByID = findAccessLogSubscriptionByID
FindListenerByTwoPartKey = findListenerByTwoPartKey
FindServiceByID = findServiceByID
FindServiceNetworkByID = findServiceNetworkByID
FindServiceNetworkServiceAssociationByID = findServiceNetworkServiceAssociationByID
Expand All @@ -17,6 +18,7 @@ var (
SuppressEquivalentIDOrARN = suppressEquivalentIDOrARN

ResourceAccessLogSubscription = resourceAccessLogSubscription
ResourceListener = resourceListener
ResourceService = resourceService
ResourceServiceNetwork = resourceServiceNetwork
ResourceServiceNetworkServiceAssociation = resourceServiceNetworkServiceAssociation
Expand Down
53 changes: 24 additions & 29 deletions internal/service/vpclattice/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package vpclattice

import (
"context"
"errors"
"fmt"
"log"
"strings"
Expand All @@ -20,17 +19,18 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/enum"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
"github.com/hashicorp/terraform-provider-aws/names"
)

// Function annotations are used for resource registration to the Provider. DO NOT EDIT.
// @SDKResource("aws_vpclattice_listener", name="Listener")
// @Tags(identifierAttribute="arn")
func ResourceListener() *schema.Resource {
func resourceListener() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceListenerCreate,
ReadWithoutTimeout: resourceListenerRead,
Expand Down Expand Up @@ -137,10 +137,10 @@ func ResourceListener() *schema.Resource {
ValidateFunc: validation.IsPortNumber,
},
names.AttrProtocol: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"HTTP", "HTTPS"}, true),
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: enum.Validate[types.ListenerProtocol](),
},
"service_arn": {
Type: schema.TypeString,
Expand Down Expand Up @@ -194,14 +194,11 @@ func resourceListenerCreate(ctx context.Context, d *schema.ResourceData, meta in
}

out, err := conn.CreateListener(ctx, in)

if err != nil {
return create.AppendDiagError(diags, names.VPCLattice, create.ErrActionCreating, ResNameListener, d.Get(names.AttrName).(string), err)
}

if out == nil || out.Arn == nil {
return create.AppendDiagError(diags, names.VPCLattice, create.ErrActionCreating, ResNameListener, d.Get(names.AttrName).(string), errors.New("empty output"))
}

// Id returned by GetListener does not contain required service name
// Create a composite ID using service ID and listener ID
d.Set("listener_id", out.Id)
Expand All @@ -225,7 +222,7 @@ func resourceListenerRead(ctx context.Context, d *schema.ResourceData, meta inte
serviceId := d.Get("service_identifier").(string)
listenerId := d.Get("listener_id").(string)

out, err := findListenerByIdAndServiceId(ctx, conn, listenerId, serviceId)
out, err := findListenerByTwoPartKey(ctx, conn, listenerId, serviceId)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] VPCLattice Listener (%s) not found, removing from state", d.Id())
Expand Down Expand Up @@ -286,43 +283,41 @@ func resourceListenerDelete(ctx context.Context, d *schema.ResourceData, meta in
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).VPCLatticeClient(ctx)

log.Printf("[INFO] Deleting VPC Lattice Listener %s", d.Id())

serviceId := d.Get("service_identifier").(string)
listenerId := d.Get("listener_id").(string)

log.Printf("[INFO] Deleting VPCLattice Listener %s", d.Id())
_, err := conn.DeleteListener(ctx, &vpclattice.DeleteListenerInput{
ListenerIdentifier: aws.String(listenerId),
ServiceIdentifier: aws.String(serviceId),
})

if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return diags
}
if errs.IsA[*types.ResourceNotFoundException](err) {
return diags
}

if err != nil {
return create.AppendDiagError(diags, names.VPCLattice, create.ErrActionDeleting, ResNameListener, d.Id(), err)
}

return diags
}

func findListenerByIdAndServiceId(ctx context.Context, conn *vpclattice.Client, id string, serviceId string) (*vpclattice.GetListenerOutput, error) {
func findListenerByTwoPartKey(ctx context.Context, conn *vpclattice.Client, listenerID, serviceID string) (*vpclattice.GetListenerOutput, error) {
in := &vpclattice.GetListenerInput{
ListenerIdentifier: aws.String(id),
ServiceIdentifier: aws.String(serviceId),
ListenerIdentifier: aws.String(listenerID),
ServiceIdentifier: aws.String(serviceID),
}
out, err := conn.GetListener(ctx, in)
if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: in,
}

if errs.IsA[*types.ResourceNotFoundException](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: in,
}
}

if err != nil {
return nil, err
}

Expand Down
103 changes: 87 additions & 16 deletions internal/service/vpclattice/listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ import (
"testing"

"github.com/YakDriver/regexache"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/vpclattice"
"github.com/aws/aws-sdk-go-v2/service/vpclattice/types"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
tfvpclattice "github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

Expand Down Expand Up @@ -154,6 +153,47 @@ func TestAccVPCLatticeListener_fixedResponseHTTPS(t *testing.T) {
})
}

func TestAccVPCLatticeListener_forwardTLSPassthrough(t *testing.T) {
ctx := acctest.Context(t)

var listener vpclattice.GetListenerOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_vpclattice_listener.test"
serviceName := "aws_vpclattice_service.test"
targetGroupResourceName := "aws_vpclattice_target_group.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckListenerDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccListenerConfig_forwardTLSPassthrough(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckListenerExists(ctx, resourceName, &listener),
resource.TestCheckResourceAttr(resourceName, names.AttrName, rName),
resource.TestCheckResourceAttr(resourceName, names.AttrPort, "8443"),
resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, "TLS_PASSTHROUGH"),
resource.TestCheckResourceAttrPair(resourceName, "service_identifier", serviceName, names.AttrID),
resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, names.AttrID),
resource.TestCheckResourceAttr(resourceName, "default_action.0.forward.0.target_groups.0.weight", "80"),
acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "vpc-lattice", regexache.MustCompile(`service\/svc-.*\/listener\/listener-.+`)),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccVPCLatticeListener_forwardHTTPTargetGroup(t *testing.T) {
ctx := acctest.Context(t)

Expand Down Expand Up @@ -458,19 +498,17 @@ func testAccCheckListenerDestroy(ctx context.Context) resource.TestCheckFunc {
continue
}

_, err := conn.GetListener(ctx, &vpclattice.GetListenerInput{
ListenerIdentifier: aws.String(rs.Primary.Attributes["listener_id"]),
ServiceIdentifier: aws.String(rs.Primary.Attributes["service_identifier"]),
})
_, err := tfvpclattice.FindListenerByTwoPartKey(ctx, conn, rs.Primary.Attributes["listener_id"], rs.Primary.Attributes["service_identifier"])

if tfresource.NotFound(err) {
continue
}

if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return nil
}
return err
}

return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameListener, rs.Primary.ID, errors.New("not destroyed"))
return fmt.Errorf("VPC Lattice Listener %s still exists", rs.Primary.ID)
}

return nil
Expand All @@ -489,13 +527,10 @@ func testAccCheckListenerExists(ctx context.Context, name string, listener *vpcl
}

conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient(ctx)
resp, err := conn.GetListener(ctx, &vpclattice.GetListenerInput{
ListenerIdentifier: aws.String(rs.Primary.Attributes["listener_id"]),
ServiceIdentifier: aws.String(rs.Primary.Attributes["service_identifier"]),
})
resp, err := tfvpclattice.FindListenerByTwoPartKey(ctx, conn, rs.Primary.Attributes["listener_id"], rs.Primary.Attributes["service_identifier"])

if err != nil {
return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameListener, rs.Primary.ID, err)
return err
}

*listener = *resp
Expand Down Expand Up @@ -553,6 +588,42 @@ resource "aws_vpclattice_listener" "test" {
`, rName))
}

func testAccListenerConfig_forwardTLSPassthrough(rName string) string {
return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 0), fmt.Sprintf(`
resource "aws_vpclattice_service" "test" {
name = %[1]q
auth_type = "AWS_IAM"
custom_domain_name = "example.com"
}

resource "aws_vpclattice_target_group" "test" {
name = %[1]q
type = "INSTANCE"

config {
port = 80
protocol = "TCP"
vpc_identifier = aws_vpc.test.id
}
}

resource "aws_vpclattice_listener" "test" {
name = %[1]q
protocol = "TLS_PASSTHROUGH"
port = 8443
service_identifier = aws_vpclattice_service.test.id
default_action {
forward {
target_groups {
target_group_identifier = aws_vpclattice_target_group.test.id
weight = 80
}
}
}
}
`, rName))
}

func testAccListenerConfig_forwardMultiTargetGroupHTTP(rName string, targetGroupName1 string) string {
return acctest.ConfigCompose(testAccListenerConfig_basic(rName), fmt.Sprintf(`
resource "aws_vpclattice_target_group" "test1" {
Expand Down
2 changes: 1 addition & 1 deletion internal/service/vpclattice/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion website/docs/r/vpclattice_listener.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ This resource supports the following arguments:
* `default_action` - (Required) Default action block for the default listener rule. Default action blocks are defined below.
* `name` - (Required, Forces new resource) Name of the listener. A listener name must be unique within a service. Valid characters are a-z, 0-9, and hyphens (-). You can't use a hyphen as the first or last character, or immediately after another hyphen.
* `port` - (Optional, Forces new resource) Listener port. You can specify a value from 1 to 65535. If `port` is not specified and `protocol` is HTTP, the value will default to 80. If `port` is not specified and `protocol` is HTTPS, the value will default to 443.
* `protocol` - (Required, Forces new resource) Protocol for the listener. Supported values are `HTTP` or `HTTPS`
* `protocol` - (Required, Forces new resource) Protocol for the listener. Supported values are `HTTP`, `HTTPS` or `TLS_PASSTHROUGH`
* `service_arn` - (Optional) Amazon Resource Name (ARN) of the VPC Lattice service. You must include either the `service_arn` or `service_identifier` arguments.
* `service_identifier` - (Optional) ID of the VPC Lattice service. You must include either the `service_arn` or `service_identifier` arguments.
-> **NOTE:** You must specify one of the following arguments: `service_arn` or `service_identifier`.
Expand Down
Loading