Skip to content

Commit

Permalink
r/aws_vpc_endpoint_service_private_dns_verification: new resource
Browse files Browse the repository at this point in the history
This resource will allow practitioners to start the verification process for a VPC endpoint service private DNS name via Terraform.

```console
% make testacc PKG=ec2 TESTS="TestAccVPCEndpointServicePrivateDNSVerification_"
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.22.2 test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccVPCEndpointServicePrivateDNSVerification_'  -timeout 360m

--- PASS: TestAccVPCEndpointServicePrivateDNSVerification_basic (218.59s)
--- PASS: TestAccVPCEndpointServicePrivateDNSVerification_waitForVerification (262.01s)
PASS
ok      github.com/hashicorp/terraform-provider-aws/internal/service/ec2        267.248s
```
  • Loading branch information
jar-b committed May 17, 2024
1 parent 03f6641 commit 41abde1
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/37176.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_vpc_endpoint_service_private_dns_verification
```
9 changes: 9 additions & 0 deletions internal/service/ec2/findv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,15 @@ func findVPCEndpointServiceConfigurationByIDV2(ctx context.Context, conn *ec2.Cl
return output, nil
}

func findVPCEndpointServicePrivateDNSNameConfigurationByIDV2(ctx context.Context, conn *ec2.Client, id string) (*awstypes.PrivateDnsNameConfiguration, error) {
out, err := findVPCEndpointServiceConfigurationByIDV2(ctx, conn, id)
if err != nil {
return nil, err
}

return out.PrivateDnsNameConfiguration, nil
}

func findVPCEndpointServicePermissionsV2(ctx context.Context, conn *ec2.Client, input *ec2.DescribeVpcEndpointServicePermissionsInput) ([]awstypes.AllowedPrincipal, error) {
var output []awstypes.AllowedPrincipal

Expand Down
4 changes: 4 additions & 0 deletions internal/service/ec2/service_package_gen.go

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

15 changes: 15 additions & 0 deletions internal/service/ec2/statusv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,18 @@ func statusVPCEndpointConnectionVPCEndpointStateV2(ctx context.Context, conn *ec
return output, string(output.VpcEndpointState), nil
}
}

func statusVPCEndpointServicePrivateDNSNameConfigurationV2(ctx context.Context, conn *ec2.Client, id string) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
out, err := findVPCEndpointServicePrivateDNSNameConfigurationByIDV2(ctx, conn, id)
if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return out, string(out.State), nil
}
}
124 changes: 124 additions & 0 deletions internal/service/ec2/vpc_endpoint_service_private_dns_verification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ec2

import (
"context"
"errors"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkResource("aws_vpc_endpoint_service_private_dns_verification", name="Endpoint Service Private DNS Verification")
func newResourceEndpointServicePrivateDNSVerification(_ context.Context) (resource.ResourceWithConfigure, error) {
r := &resourceEndpointServicePrivateDNSVerification{}
r.SetDefaultCreateTimeout(30 * time.Minute)

return r, nil
}

const (
ResNameEndpointServicePrivateDNSVerification = "Endpoint Service Private DNS Verification"
)

type resourceEndpointServicePrivateDNSVerification struct {
framework.ResourceWithConfigure
framework.WithNoOpRead
framework.WithNoUpdate
framework.WithNoOpDelete
framework.WithTimeouts
}

func (r *resourceEndpointServicePrivateDNSVerification) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = "aws_vpc_endpoint_service_private_dns_verification"
}

func (r *resourceEndpointServicePrivateDNSVerification) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"service_id": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"wait_for_verification": schema.BoolAttribute{
Optional: true,
},
},
Blocks: map[string]schema.Block{
"timeouts": timeouts.Block(ctx, timeouts.Opts{
Create: true,
}),
},
}
}

func (r *resourceEndpointServicePrivateDNSVerification) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
conn := r.Meta().EC2Client(ctx)

var plan resourceEndpointServicePrivateDNSVerificationData
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

in := &ec2.StartVpcEndpointServicePrivateDnsVerificationInput{
ServiceId: aws.String(plan.ServiceID.ValueString()),
}

out, err := conn.StartVpcEndpointServicePrivateDnsVerification(ctx, in)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.EC2, create.ErrActionCreating, ResNameEndpointServicePrivateDNSVerification, plan.ServiceID.String(), err),
err.Error(),
)
return
}
if out == nil || out.ReturnValue == nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.EC2, create.ErrActionCreating, ResNameEndpointServicePrivateDNSVerification, plan.ServiceID.String(), nil),
errors.New("empty output").Error(),
)
return
}
if !aws.ToBool(out.ReturnValue) {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.EC2, create.ErrActionCreating, ResNameEndpointServicePrivateDNSVerification, plan.ServiceID.String(), nil),
errors.New("request failed").Error(),
)
return
}

if plan.WaitForVerification.ValueBool() {
createTimeout := r.CreateTimeout(ctx, plan.Timeouts)
_, err := waitVPCEndpointServicePrivateDNSNameVerifiedV2(ctx, conn, plan.ServiceID.ValueString(), createTimeout)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.EC2, create.ErrActionWaitingForCreation, ResNameEndpointServicePrivateDNSVerification, plan.ServiceID.String(), err),
err.Error(),
)
return
}
}

resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
}

type resourceEndpointServicePrivateDNSVerificationData struct {
ServiceID types.String `tfsdk:"service_id"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
WaitForVerification types.Bool `tfsdk:"wait_for_verification"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ec2_test

import (
"fmt"
"testing"

"github.com/YakDriver/regexache"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccVPCEndpointServicePrivateDNSVerification_basic(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

rName := sdkacctest.RandomWithPrefix("tfacctest") // 32 character limit
domainName := acctest.RandomDomainName()
resourceName := "aws_vpc_endpoint_service_private_dns_verification.test"
endpointServiceResourceName := "aws_vpc_endpoint_service.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.EC2)
},
ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccVPCEndpointServicePrivateDNSVerificationConfig_basic(rName, domainName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, "service_id", endpointServiceResourceName, names.AttrID),
),
},
},
})
}

func TestAccVPCEndpointServicePrivateDNSVerification_waitForVerification(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

rName := sdkacctest.RandomWithPrefix("tfacctest") // 32 character limit
domainName := acctest.RandomDomainName()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.EC2)
},
ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccVPCEndpointServicePrivateDNSVerificationConfig_waitForVerification(rName, domainName),
// Expect an error as private DNS setup and verification is not
// included in this configuration. This test simply verifies the
// create waiter functions as expected.
ExpectError: regexache.MustCompile("waiting for creation"),
},
},
})
}

func testAccVPCEndpointServicePrivateDNSVerificationConfigBase(rName, domainName string, count int) string {
return acctest.ConfigCompose(
acctest.ConfigVPCWithSubnets(rName, 2),
fmt.Sprintf(`
resource "aws_lb" "test" {
count = %[3]d
load_balancer_type = "network"
name = "%[1]s-${count.index}"
subnets = aws_subnet.test[*].id
internal = true
idle_timeout = 60
enable_deletion_protection = false
tags = {
Name = %[1]q
}
}
resource "aws_vpc_endpoint_service" "test" {
acceptance_required = false
network_load_balancer_arns = aws_lb.test[*].arn
private_dns_name = %[2]q
}
`, rName, domainName, count))
}

func testAccVPCEndpointServicePrivateDNSVerificationConfig_basic(rName, domainName string) string {
return acctest.ConfigCompose(
testAccVPCEndpointServicePrivateDNSVerificationConfigBase(rName, domainName, 1),
`
resource "aws_vpc_endpoint_service_private_dns_verification" "test" {
service_id = aws_vpc_endpoint_service.test.id
}
`)
}

func testAccVPCEndpointServicePrivateDNSVerificationConfig_waitForVerification(rName, domainName string) string {
return acctest.ConfigCompose(
testAccVPCEndpointServicePrivateDNSVerificationConfigBase(rName, domainName, 1),
`
resource "aws_vpc_endpoint_service_private_dns_verification" "test" {
service_id = aws_vpc_endpoint_service.test.id
wait_for_verification = true
timeouts {
create = "1m"
}
}
`)
}
17 changes: 17 additions & 0 deletions internal/service/ec2/waitv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,20 @@ func waitVPCEndpointConnectionAcceptedV2(ctx context.Context, conn *ec2.Client,

return nil, err
}

func waitVPCEndpointServicePrivateDNSNameVerifiedV2(ctx context.Context, conn *ec2.Client, id string, timeout time.Duration) (*types.PrivateDnsNameConfiguration, error) {
stateConf := &retry.StateChangeConf{
Pending: enum.Slice(types.DnsNameStatePendingVerification),
Target: enum.Slice(types.DnsNameStateVerified),
Refresh: statusVPCEndpointServicePrivateDNSNameConfigurationV2(ctx, conn, id),
Timeout: timeout,
ContinuousTargetOccurence: 2,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)
if out, ok := outputRaw.(*types.PrivateDnsNameConfiguration); ok {
return out, err
}

return nil, err
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
subcategory: "VPC (Virtual Private Cloud)"
layout: "aws"
page_title: "AWS: aws_vpc_endpoint_service_private_dns_verification"
description: |-
Terraform resource for managing an AWS VPC (Virtual Private Cloud) Endpoint Service Private DNS Verification.
---
# Resource: aws_vpc_endpoint_service_private_dns_verification

Terraform resource for managing an AWS VPC (Virtual Private Cloud) Endpoint Service Private DNS Verification.

~> Destruction of this resource will not stop the verification process, only remove the resource from state.

## Example Usage

### Basic Usage

```terraform
resource "aws_vpc_endpoint_service_private_dns_verification" "example" {
service_id = aws_vpc_endpoint_service.example.id
}
```

## Argument Reference

The following arguments are required:

* `service_id` - (Required) ID of the endpoint service.

The following arguments are optional:

* `wait_for_verification` - (Optional) Whether to wait until the endpoint service returns a `Verified` status for the configured private DNS name.

## Attribute Reference

This resource exports no additional attributes.

## Timeouts

[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts):

* `create` - (Default `30m`)

## Import

You cannot import this resource.

0 comments on commit 41abde1

Please sign in to comment.