From 9fb0420f92dfb2fe2b0f1366616b6f32d880aee4 Mon Sep 17 00:00:00 2001 From: Subham Mukhopadhyay Date: Sat, 11 Oct 2025 03:20:38 +0530 Subject: [PATCH 01/11] d/aws_ec2_vpn_connection: Add a new data source. % make testacc TESTS=TestAccEC2VpnConnectionDataSource_ PKG=ec2 make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: :herb: f-aws_ec2_vpn_connection-new-data-source :herb:... TF_ACC=1 go1.24.6 test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2VpnConnectionDataSource_' -timeout 360m -vet=off 2025/10/09 20:21:06 Creating Terraform AWS Provider (SDKv2-style)... 2025/10/09 20:21:06 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccEC2VpnConnectionDataSource_basic === PAUSE TestAccEC2VpnConnectionDataSource_basic === RUN TestAccEC2VpnConnectionDataSource_byFilter === PAUSE TestAccEC2VpnConnectionDataSource_byFilter === RUN TestAccEC2VpnConnectionDataSource_nonExistentId === PAUSE TestAccEC2VpnConnectionDataSource_nonExistentId === RUN TestAccEC2VpnConnectionDataSource_noInput === PAUSE TestAccEC2VpnConnectionDataSource_noInput === CONT TestAccEC2VpnConnectionDataSource_basic === CONT TestAccEC2VpnConnectionDataSource_nonExistentId === CONT TestAccEC2VpnConnectionDataSource_noInput === CONT TestAccEC2VpnConnectionDataSource_byFilter --- PASS: TestAccEC2VpnConnectionDataSource_noInput (3.85s) --- PASS: TestAccEC2VpnConnectionDataSource_nonExistentId (5.41s) --- PASS: TestAccEC2VpnConnectionDataSource_byFilter (258.74s) --- PASS: TestAccEC2VpnConnectionDataSource_basic (593.10s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 597.880s --- go.mod | 1 + go.sum | 3 +- internal/service/ec2/service_package_gen.go | 6 + .../service/ec2/vpn_connection_data_source.go | 169 +++++++++++++++ .../ec2/vpn_connection_data_source_test.go | 196 ++++++++++++++++++ .../docs/d/ec2_vpn_connection.html.markdown | 71 +++++++ 6 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 internal/service/ec2/vpn_connection_data_source.go create mode 100644 internal/service/ec2/vpn_connection_data_source_test.go create mode 100644 website/docs/d/ec2_vpn_connection.html.markdown diff --git a/go.mod b/go.mod index 013d61a84b1b..54f0db8902b2 100644 --- a/go.mod +++ b/go.mod @@ -383,6 +383,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/grpc v1.75.1 // indirect google.golang.org/protobuf v1.36.9 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) replace github.com/hashicorp/terraform-plugin-log => github.com/gdavison/terraform-plugin-log v0.0.0-20230928191232-6c653d8ef8fb diff --git a/go.sum b/go.sum index 0659acfcbd97..1b6493894d42 100644 --- a/go.sum +++ b/go.sum @@ -886,7 +886,8 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index adede89c4d55..adca6c9989a6 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -38,6 +38,12 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S Name: "Capacity Block Offering", Region: unique.Make(inttypes.ResourceRegionDefault()), }, + { + Factory: newDataSourceVPNConnection, + TypeName: "aws_ec2_vpn_connection", + Name: "VPN Connection", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, { Factory: newSpotDataFeedSubscriptionDataSource, TypeName: "aws_spot_datafeed_subscription", diff --git a/internal/service/ec2/vpn_connection_data_source.go b/internal/service/ec2/vpn_connection_data_source.go new file mode 100644 index 000000000000..21a55dd2edf7 --- /dev/null +++ b/internal/service/ec2/vpn_connection_data_source.go @@ -0,0 +1,169 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + "errors" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/smerr" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkDataSource("aws_ec2_vpn_connection", name="VPN Connection") +func newDataSourceVPNConnection(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceVPNConnection{}, nil +} + +const ( + DSNameVPNConnection = "VPN Connection Data Source" +) + +type dataSourceVPNConnection struct { + framework.DataSourceWithModel[dataSourceVPNConnectionModel] +} + +func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "vpn_connection_id": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "category": schema.StringAttribute{ + Computed: true, + }, + "core_network_arn": schema.StringAttribute{ + Computed: true, + }, + "core_network_attachment_arn": schema.StringAttribute{ + Computed: true, + }, + "customer_gateway_configuration": schema.StringAttribute{ + Computed: true, + }, + "customer_gateway_id": schema.StringAttribute{ + Computed: true, + }, + "gateway_association_state": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.GatewayAssociationState](), + Computed: true, + }, + "pre_shared_key_arn": schema.StringAttribute{ + Computed: true, + }, + names.AttrState: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.VpnState](), + Computed: true, + }, + "transit_gateway_id": schema.StringAttribute{ + Computed: true, + }, + names.AttrType: schema.StringAttribute{ + Computed: true, + }, + "vpn_gateway_id": schema.StringAttribute{ + Computed: true, + }, + names.AttrID: framework.IDAttribute(), + names.AttrTags: tftags.TagsAttributeComputedOnly(), + "routes": framework.DataSourceComputedListOfObjectAttribute[routeModel](ctx), + "vgw_telemetries": framework.DataSourceComputedListOfObjectAttribute[vgwTelemetryModel](ctx), + }, + Blocks: map[string]schema.Block{ + names.AttrFilter: customFiltersBlock(ctx), + }, + } +} + +func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + + conn := d.Meta().EC2Client(ctx) + + var data dataSourceVPNConnectionModel + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Config.Get(ctx, &data)) + if resp.Diagnostics.HasError() { + return + } + + input := &ec2.DescribeVpnConnectionsInput{ + Filters: newCustomFilterListFramework(ctx, data.Filters), + VpnConnectionIds: []string{data.VpnConnectionId.ValueString()}, + } + + if len(input.Filters) == 0 { + // Don't send an empty filters list; the EC2 API won't accept it. + input.Filters = nil + } + + if input.VpnConnectionIds[0] == "" { + // Don't send an empty ID; the EC2 API won't accept it. + input.VpnConnectionIds = nil + } + + if input.Filters == nil && input.VpnConnectionIds == nil { + smerr.AddError(ctx, &resp.Diagnostics, errors.New("Missing input"), smerr.ID) + return + } + + out, err := findVPNConnection(ctx, conn, input) + if err != nil { + smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID) + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &data), smerr.ID, data.VpnConnectionId.String()) + if resp.Diagnostics.HasError() { + return + } + data.ID = types.StringValue(aws.ToString(out.VpnConnectionId)) + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &data), smerr.ID, data.VpnConnectionId.String()) +} + +type dataSourceVPNConnectionModel struct { + framework.WithRegionModel + Filters customFilters `tfsdk:"filter"` + VpnConnectionId types.String `tfsdk:"vpn_connection_id"` + ID types.String `tfsdk:"id"` + + Category types.String `tfsdk:"category"` + CoreNetworkArn types.String `tfsdk:"core_network_arn"` + CoreNetworkAttachmentArn types.String `tfsdk:"core_network_attachment_arn"` + CustomerGatewayConfiguration types.String `tfsdk:"customer_gateway_configuration"` + CustomerGatewayID types.String `tfsdk:"customer_gateway_id"` + GatewayAssociationState fwtypes.StringEnum[awstypes.GatewayAssociationState] `tfsdk:"gateway_association_state"` + PreSharedKeyArn types.String `tfsdk:"pre_shared_key_arn"` + State fwtypes.StringEnum[awstypes.VpnState] `tfsdk:"state"` + TransitGatewayId types.String `tfsdk:"transit_gateway_id"` + Type types.String `tfsdk:"type"` + VpnGatewayId types.String `tfsdk:"vpn_gateway_id"` + Routes fwtypes.ListNestedObjectValueOf[routeModel] `tfsdk:"routes"` + VgwTelemetries fwtypes.ListNestedObjectValueOf[vgwTelemetryModel] `tfsdk:"vgw_telemetries"` + Tags tftags.Map `tfsdk:"tags"` +} + +type routeModel struct { + DestinationCidrBlock types.String `tfsdk:"destination_cidr_block"` + Source types.String `tfsdk:"source"` + State fwtypes.StringEnum[awstypes.VpnState] `tfsdk:"state"` +} + +type vgwTelemetryModel struct { + AcceptedRouteCount types.Int64 `tfsdk:"accepted_route_count"` + LastStatusChange timetypes.RFC3339 `tfsdk:"last_status_change"` + Status fwtypes.StringEnum[awstypes.TelemetryStatus] `tfsdk:"status"` + StatusMessage types.String `tfsdk:"status_message"` + OutsideIpAddress types.String `tfsdk:"outside_ip_address"` +} diff --git a/internal/service/ec2/vpn_connection_data_source_test.go b/internal/service/ec2/vpn_connection_data_source_test.go new file mode 100644 index 000000000000..e234f5fa7f7e --- /dev/null +++ b/internal/service/ec2/vpn_connection_data_source_test.go @@ -0,0 +1,196 @@ +// 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 TestAccEC2VpnConnectionDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rBgpAsn := sdkacctest.RandIntRange(64512, 65534) + dataSourceName := "data.aws_ec2_vpn_connection.test" + resourceName := "aws_vpn_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPNConnectionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVpnConnectionDataSourceConfig_byId(rName, rBgpAsn), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID), + resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", resourceName, names.AttrID), + resource.TestCheckResourceAttrPair(dataSourceName, "customer_gateway_id", resourceName, "customer_gateway_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpn_gateway_id", resourceName, "vpn_gateway_id"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrType, resourceName, names.AttrType), + resource.TestCheckResourceAttrSet(dataSourceName, names.AttrState), + resource.TestCheckResourceAttrSet(dataSourceName, "customer_gateway_configuration"), + resource.TestCheckResourceAttrSet(dataSourceName, "category"), + resource.TestCheckResourceAttr(dataSourceName, "routes.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "vgw_telemetries.#", "2"), + ), + }, + }, + }) +} + +func TestAccEC2VpnConnectionDataSource_byFilter(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rBgpAsn := sdkacctest.RandIntRange(64512, 65534) + dataSourceName := "data.aws_ec2_vpn_connection.test" + resourceName := "aws_vpn_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPNConnectionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVpnConnectionDataSourceConfig_byFilter(rName, rBgpAsn), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID), + resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", resourceName, names.AttrID), + resource.TestCheckResourceAttrPair(dataSourceName, "customer_gateway_id", resourceName, "customer_gateway_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpn_gateway_id", resourceName, "vpn_gateway_id"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrType, resourceName, names.AttrType), + resource.TestCheckResourceAttrSet(dataSourceName, names.AttrState), + resource.TestCheckResourceAttrSet(dataSourceName, "customer_gateway_configuration"), + ), + }, + }, + }) +} + +func TestAccEC2VpnConnectionDataSource_nonExistentId(t *testing.T) { + ctx := acctest.Context(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccVpnConnectionDataSourceConfig_nonExistentId(), + ExpectError: regexache.MustCompile(`couldn't find resource`), + }, + }, + }) +} + +func TestAccEC2VpnConnectionDataSource_noInput(t *testing.T) { + ctx := acctest.Context(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccVpnConnectionDataSourceConfig_noInput(), + ExpectError: regexache.MustCompile(`Missing input`), + }, + }, + }) +} + +func testAccVpnConnectionDataSourceConfig_byId(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_vpn_gateway" "test" { + tags = { + Name = %[1]q + } +} + +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d + ip_address = "178.0.0.1" + type = "ipsec.1" + + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_connection" "test" { + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id + type = "ipsec.1" +} + +data "aws_ec2_vpn_connection" "test" { + vpn_connection_id = aws_vpn_connection.test.id + + depends_on = [aws_vpn_connection.test] +} +`, rName, rBgpAsn) +} + +func testAccVpnConnectionDataSourceConfig_byFilter(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_vpn_gateway" "test" { + tags = { + Name = %[1]q + } +} + +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d + ip_address = "178.0.0.1" + type = "ipsec.1" + + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_connection" "test" { + vpn_gateway_id = aws_vpn_gateway.test.id + customer_gateway_id = aws_customer_gateway.test.id + type = "ipsec.1" +} + +data "aws_ec2_vpn_connection" "test" { + filter { + name = "customer-gateway-id" + values = [aws_customer_gateway.test.id] + } + + filter { + name = "vpn-gateway-id" + values = [aws_vpn_gateway.test.id] + } + + depends_on = [aws_vpn_connection.test] +} +`, rName, rBgpAsn) +} + +func testAccVpnConnectionDataSourceConfig_nonExistentId() string { + return ` +data "aws_ec2_vpn_connection" "test" { + vpn_connection_id = "vpn-12345678901234567" +} +` +} + +func testAccVpnConnectionDataSourceConfig_noInput() string { + return ` +data "aws_ec2_vpn_connection" "test" { + # No vpn_connection_id or filter specified +} +` +} diff --git a/website/docs/d/ec2_vpn_connection.html.markdown b/website/docs/d/ec2_vpn_connection.html.markdown new file mode 100644 index 000000000000..706a93f48b79 --- /dev/null +++ b/website/docs/d/ec2_vpn_connection.html.markdown @@ -0,0 +1,71 @@ +--- +subcategory: "EC2 (Elastic Compute Cloud)" +layout: "aws" +page_title: "AWS: aws_ec2_vpn_connection" +description: |- + Provides details about an AWS EC2 (Elastic Compute Cloud) VPN Connection. +--- + +# Data Source: aws_ec2_vpn_connection + +Provides details about an AWS EC2 (Elastic Compute Cloud) VPN Connection. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_ec2_vpn_connection" "example" { + filter { + name = "customer-gateway-id" + values = ["cgw-1234567890"] + } +} + +output "vpn_connection_id" { + value = aws_ec2_vpn_connection.example.vpn_connection_id +} +``` + +```terraform +data "aws_ec2_vpn_connection" "example" { + vpn_connection_id = "" +} + +output "gateway_association_state" { + value = aws_ec2_vpn_connection.example.gateway_association_state +} +``` +## Argument Reference + +The following arguments are optional, either of the arguments should be present: + +* `vpn_connection_id` - (Optional) Identifier of the EC2 VPN Connection. +* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. + +### filter Configuration Block + +The `filter` configuration block supports the following arguments: + +* `name` - (Required) Name of the filter field. Valid values can be found in the [EC2 DescribeVPNConnections API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpnConnections.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `category` - Category of the VPN connection. A value of VPN indicates an AWS VPN connection. A value of VPN-Classic indicates an AWS Classic VPN connection. +* `core_network_arn` - ARN of the core network. +* `core_network_attachment_arn` - ARN of the core network attachment. +* `customer_gateway_configuration` - Configuration information for the VPN connection's customer gateway (in the native XML format). +* `customer_gateway_id` - ID of the customer gateway at your end of the VPN connection. +* `gateway_association_state` - Current state of the gateway association. +* `pre_shared_key_arn` - (ARN) of the Secrets Manager secret storing the pre-shared key(s) for the VPN connection. +* `state` - Current state of the VPN connection. +* `transit_gateway_id` - ID of a transit gateway associated with the VPN connection. +* `type` - Type of VPN connection. Currently the only supported type is ipsec.1. +* `vpn_gateway_id` - ID of a virtual private gateway associated with the VPN connection. +* `id` - EC2 VPN Connection identifier. +* `tags` - Tags associated to the VPN Connection. +* `routes` - List of static routes associated with the VPN connection. +* `vgw_telemetries` - List of objects containing information about the VPN tunnel. \ No newline at end of file From 14e90e9ec166c8944dffbe68109399e70291a9a8 Mon Sep 17 00:00:00 2001 From: Subham Mukhopadhyay Date: Mon, 13 Oct 2025 20:22:17 +0530 Subject: [PATCH 02/11] fix failing checks --- .../service/ec2/vpn_connection_data_source.go | 11 ++++---- .../ec2/vpn_connection_data_source_test.go | 26 +++++++++---------- .../docs/d/ec2_vpn_connection.html.markdown | 5 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/service/ec2/vpn_connection_data_source.go b/internal/service/ec2/vpn_connection_data_source.go index 21a55dd2edf7..387bb0233d0e 100644 --- a/internal/service/ec2/vpn_connection_data_source.go +++ b/internal/service/ec2/vpn_connection_data_source.go @@ -68,7 +68,7 @@ func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.Sch CustomType: fwtypes.StringEnumType[awstypes.VpnState](), Computed: true, }, - "transit_gateway_id": schema.StringAttribute{ + names.AttrTransitGatewayID: schema.StringAttribute{ Computed: true, }, names.AttrType: schema.StringAttribute{ @@ -89,16 +89,15 @@ func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.Sch } func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - conn := d.Meta().EC2Client(ctx) - + var data dataSourceVPNConnectionModel smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Config.Get(ctx, &data)) if resp.Diagnostics.HasError() { return } - input := &ec2.DescribeVpnConnectionsInput{ + input := ec2.DescribeVpnConnectionsInput{ Filters: newCustomFilterListFramework(ctx, data.Filters), VpnConnectionIds: []string{data.VpnConnectionId.ValueString()}, } @@ -114,11 +113,11 @@ func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadR } if input.Filters == nil && input.VpnConnectionIds == nil { - smerr.AddError(ctx, &resp.Diagnostics, errors.New("Missing input"), smerr.ID) + smerr.AddError(ctx, &resp.Diagnostics, errors.New("missing input"), smerr.ID) return } - out, err := findVPNConnection(ctx, conn, input) + out, err := findVPNConnection(ctx, conn, &input) if err != nil { smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID) return diff --git a/internal/service/ec2/vpn_connection_data_source_test.go b/internal/service/ec2/vpn_connection_data_source_test.go index e234f5fa7f7e..cfb19232b44a 100644 --- a/internal/service/ec2/vpn_connection_data_source_test.go +++ b/internal/service/ec2/vpn_connection_data_source_test.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccEC2VpnConnectionDataSource_basic(t *testing.T) { +func TestAccEC2VPNConnectionDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rBgpAsn := sdkacctest.RandIntRange(64512, 65534) @@ -28,7 +28,7 @@ func TestAccEC2VpnConnectionDataSource_basic(t *testing.T) { CheckDestroy: testAccCheckVPNConnectionDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVpnConnectionDataSourceConfig_byId(rName, rBgpAsn), + Config: testAccVPNConnectionDataSourceConfig_byId(rName, rBgpAsn), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID), resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", resourceName, names.AttrID), @@ -46,7 +46,7 @@ func TestAccEC2VpnConnectionDataSource_basic(t *testing.T) { }) } -func TestAccEC2VpnConnectionDataSource_byFilter(t *testing.T) { +func TestAccEC2VPNConnectionDataSource_byFilter(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rBgpAsn := sdkacctest.RandIntRange(64512, 65534) @@ -60,7 +60,7 @@ func TestAccEC2VpnConnectionDataSource_byFilter(t *testing.T) { CheckDestroy: testAccCheckVPNConnectionDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVpnConnectionDataSourceConfig_byFilter(rName, rBgpAsn), + Config: testAccVPNConnectionDataSourceConfig_byFilter(rName, rBgpAsn), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID), resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", resourceName, names.AttrID), @@ -75,7 +75,7 @@ func TestAccEC2VpnConnectionDataSource_byFilter(t *testing.T) { }) } -func TestAccEC2VpnConnectionDataSource_nonExistentId(t *testing.T) { +func TestAccEC2VPNConnectionDataSource_nonExistentId(t *testing.T) { ctx := acctest.Context(t) resource.ParallelTest(t, resource.TestCase{ @@ -84,14 +84,14 @@ func TestAccEC2VpnConnectionDataSource_nonExistentId(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccVpnConnectionDataSourceConfig_nonExistentId(), + Config: testAccVPNConnectionDataSourceConfig_nonExistentId(), ExpectError: regexache.MustCompile(`couldn't find resource`), }, }, }) } -func TestAccEC2VpnConnectionDataSource_noInput(t *testing.T) { +func TestAccEC2VPNConnectionDataSource_noInput(t *testing.T) { ctx := acctest.Context(t) resource.ParallelTest(t, resource.TestCase{ @@ -100,14 +100,14 @@ func TestAccEC2VpnConnectionDataSource_noInput(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccVpnConnectionDataSourceConfig_noInput(), - ExpectError: regexache.MustCompile(`Missing input`), + Config: testAccVPNConnectionDataSourceConfig_noInput(), + ExpectError: regexache.MustCompile(`missing input`), }, }, }) } -func testAccVpnConnectionDataSourceConfig_byId(rName string, rBgpAsn int) string { +func testAccVPNConnectionDataSourceConfig_byId(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_vpn_gateway" "test" { tags = { @@ -139,7 +139,7 @@ data "aws_ec2_vpn_connection" "test" { `, rName, rBgpAsn) } -func testAccVpnConnectionDataSourceConfig_byFilter(rName string, rBgpAsn int) string { +func testAccVPNConnectionDataSourceConfig_byFilter(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_vpn_gateway" "test" { tags = { @@ -179,7 +179,7 @@ data "aws_ec2_vpn_connection" "test" { `, rName, rBgpAsn) } -func testAccVpnConnectionDataSourceConfig_nonExistentId() string { +func testAccVPNConnectionDataSourceConfig_nonExistentId() string { return ` data "aws_ec2_vpn_connection" "test" { vpn_connection_id = "vpn-12345678901234567" @@ -187,7 +187,7 @@ data "aws_ec2_vpn_connection" "test" { ` } -func testAccVpnConnectionDataSourceConfig_noInput() string { +func testAccVPNConnectionDataSourceConfig_noInput() string { return ` data "aws_ec2_vpn_connection" "test" { # No vpn_connection_id or filter specified diff --git a/website/docs/d/ec2_vpn_connection.html.markdown b/website/docs/d/ec2_vpn_connection.html.markdown index 706a93f48b79..09d6e4accfc0 100644 --- a/website/docs/d/ec2_vpn_connection.html.markdown +++ b/website/docs/d/ec2_vpn_connection.html.markdown @@ -36,9 +36,10 @@ output "gateway_association_state" { value = aws_ec2_vpn_connection.example.gateway_association_state } ``` + ## Argument Reference -The following arguments are optional, either of the arguments should be present: +This data source supports the following arguments: * `vpn_connection_id` - (Optional) Identifier of the EC2 VPN Connection. * `filter` - (Optional) Configuration block(s) for filtering. Detailed below. @@ -68,4 +69,4 @@ This data source exports the following attributes in addition to the arguments a * `id` - EC2 VPN Connection identifier. * `tags` - Tags associated to the VPN Connection. * `routes` - List of static routes associated with the VPN connection. -* `vgw_telemetries` - List of objects containing information about the VPN tunnel. \ No newline at end of file +* `vgw_telemetries` - List of objects containing information about the VPN tunnel. From cc8ee5a1bb85ad28c5ffec0ff47c1463ed680847 Mon Sep 17 00:00:00 2001 From: Subham Mukhopadhyay Date: Mon, 13 Oct 2025 20:39:16 +0530 Subject: [PATCH 03/11] fix linting --- internal/service/ec2/vpn_connection_data_source.go | 1 - website/docs/d/ec2_vpn_connection.html.markdown | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/service/ec2/vpn_connection_data_source.go b/internal/service/ec2/vpn_connection_data_source.go index 387bb0233d0e..60eebbda59d7 100644 --- a/internal/service/ec2/vpn_connection_data_source.go +++ b/internal/service/ec2/vpn_connection_data_source.go @@ -90,7 +90,6 @@ func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.Sch func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { conn := d.Meta().EC2Client(ctx) - var data dataSourceVPNConnectionModel smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Config.Get(ctx, &data)) if resp.Diagnostics.HasError() { diff --git a/website/docs/d/ec2_vpn_connection.html.markdown b/website/docs/d/ec2_vpn_connection.html.markdown index 09d6e4accfc0..a97bc54a28a5 100644 --- a/website/docs/d/ec2_vpn_connection.html.markdown +++ b/website/docs/d/ec2_vpn_connection.html.markdown @@ -16,20 +16,20 @@ Provides details about an AWS EC2 (Elastic Compute Cloud) VPN Connection. ```terraform data "aws_ec2_vpn_connection" "example" { - filter { - name = "customer-gateway-id" - values = ["cgw-1234567890"] - } + filter { + name = "customer-gateway-id" + values = ["cgw-1234567890"] + } } output "vpn_connection_id" { - value = aws_ec2_vpn_connection.example.vpn_connection_id + value = aws_ec2_vpn_connection.example.vpn_connection_id } ``` ```terraform data "aws_ec2_vpn_connection" "example" { - vpn_connection_id = "" + vpn_connection_id = "" } output "gateway_association_state" { From 43913e18b095273e5009c228f18591f94dda9a28 Mon Sep 17 00:00:00 2001 From: Subham Mukhopadhyay Date: Tue, 14 Oct 2025 03:12:46 +0530 Subject: [PATCH 04/11] use autoflex, improve tests, fix documentation --- .../service/ec2/vpn_connection_data_source.go | 49 +++++++++---------- .../ec2/vpn_connection_data_source_test.go | 6 +-- .../docs/d/ec2_vpn_connection.html.markdown | 11 +++-- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/internal/service/ec2/vpn_connection_data_source.go b/internal/service/ec2/vpn_connection_data_source.go index 60eebbda59d7..0fda9c4e4744 100644 --- a/internal/service/ec2/vpn_connection_data_source.go +++ b/internal/service/ec2/vpn_connection_data_source.go @@ -5,14 +5,15 @@ package ec2 import ( "context" - "errors" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" @@ -38,10 +39,6 @@ type dataSourceVPNConnection struct { func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "vpn_connection_id": schema.StringAttribute{ - Optional: true, - Computed: true, - }, "category": schema.StringAttribute{ Computed: true, }, @@ -61,26 +58,30 @@ func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.Sch CustomType: fwtypes.StringEnumType[awstypes.GatewayAssociationState](), Computed: true, }, + names.AttrID: framework.IDAttribute(), "pre_shared_key_arn": schema.StringAttribute{ Computed: true, }, + "routes": framework.DataSourceComputedListOfObjectAttribute[routeModel](ctx), names.AttrState: schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.VpnState](), Computed: true, }, + names.AttrTags: tftags.TagsAttributeComputedOnly(), names.AttrTransitGatewayID: schema.StringAttribute{ Computed: true, }, names.AttrType: schema.StringAttribute{ Computed: true, }, + "vgw_telemetries": framework.DataSourceComputedListOfObjectAttribute[vgwTelemetryModel](ctx), + "vpn_connection_id": schema.StringAttribute{ + Optional: true, + Computed: true, + }, "vpn_gateway_id": schema.StringAttribute{ Computed: true, }, - names.AttrID: framework.IDAttribute(), - names.AttrTags: tftags.TagsAttributeComputedOnly(), - "routes": framework.DataSourceComputedListOfObjectAttribute[routeModel](ctx), - "vgw_telemetries": framework.DataSourceComputedListOfObjectAttribute[vgwTelemetryModel](ctx), }, Blocks: map[string]schema.Block{ names.AttrFilter: customFiltersBlock(ctx), @@ -96,24 +97,11 @@ func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadR return } - input := ec2.DescribeVpnConnectionsInput{ - Filters: newCustomFilterListFramework(ctx, data.Filters), - VpnConnectionIds: []string{data.VpnConnectionId.ValueString()}, - } - - if len(input.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. - input.Filters = nil - } + input := ec2.DescribeVpnConnectionsInput{} + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Expand(ctx, data, &input, flex.WithIgnoredFieldNamesAppend("VpnConnectionId")), smerr.ID) - if input.VpnConnectionIds[0] == "" { - // Don't send an empty ID; the EC2 API won't accept it. - input.VpnConnectionIds = nil - } - - if input.Filters == nil && input.VpnConnectionIds == nil { - smerr.AddError(ctx, &resp.Diagnostics, errors.New("missing input"), smerr.ID) - return + if !data.VpnConnectionId.IsNull() && !data.VpnConnectionId.IsUnknown() { + input.VpnConnectionIds = []string{data.VpnConnectionId.ValueString()} } out, err := findVPNConnection(ctx, conn, &input) @@ -130,6 +118,15 @@ func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadR smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &data), smerr.ID, data.VpnConnectionId.String()) } +func (d *dataSourceVPNConnection) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.AtLeastOneOf( + path.MatchRoot("vpn_connection_id"), + path.MatchRoot(names.AttrFilter), + ), + } +} + type dataSourceVPNConnectionModel struct { framework.WithRegionModel Filters customFilters `tfsdk:"filter"` diff --git a/internal/service/ec2/vpn_connection_data_source_test.go b/internal/service/ec2/vpn_connection_data_source_test.go index cfb19232b44a..ed3b1d243be0 100644 --- a/internal/service/ec2/vpn_connection_data_source_test.go +++ b/internal/service/ec2/vpn_connection_data_source_test.go @@ -17,7 +17,7 @@ import ( func TestAccEC2VPNConnectionDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - rBgpAsn := sdkacctest.RandIntRange(64512, 65534) + rBgpAsn := sdkacctest.RandIntRange(65501, 65534) dataSourceName := "data.aws_ec2_vpn_connection.test" resourceName := "aws_vpn_connection.test" @@ -49,7 +49,7 @@ func TestAccEC2VPNConnectionDataSource_basic(t *testing.T) { func TestAccEC2VPNConnectionDataSource_byFilter(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - rBgpAsn := sdkacctest.RandIntRange(64512, 65534) + rBgpAsn := sdkacctest.RandIntRange(65501, 65534) dataSourceName := "data.aws_ec2_vpn_connection.test" resourceName := "aws_vpn_connection.test" @@ -101,7 +101,7 @@ func TestAccEC2VPNConnectionDataSource_noInput(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPNConnectionDataSourceConfig_noInput(), - ExpectError: regexache.MustCompile(`missing input`), + ExpectError: regexache.MustCompile(`Missing Attribute Configuration`), }, }, }) diff --git a/website/docs/d/ec2_vpn_connection.html.markdown b/website/docs/d/ec2_vpn_connection.html.markdown index a97bc54a28a5..a14905b462ef 100644 --- a/website/docs/d/ec2_vpn_connection.html.markdown +++ b/website/docs/d/ec2_vpn_connection.html.markdown @@ -23,17 +23,19 @@ data "aws_ec2_vpn_connection" "example" { } output "vpn_connection_id" { - value = aws_ec2_vpn_connection.example.vpn_connection_id + value = data.aws_ec2_vpn_connection.example.vpn_connection_id } ``` +### Find by VPN Connection ID + ```terraform data "aws_ec2_vpn_connection" "example" { - vpn_connection_id = "" + vpn_connection_id = "vpn-abcd1234567890" } output "gateway_association_state" { - value = aws_ec2_vpn_connection.example.gateway_association_state + value = data.aws_ec2_vpn_connection.example.gateway_association_state } ``` @@ -43,8 +45,9 @@ This data source supports the following arguments: * `vpn_connection_id` - (Optional) Identifier of the EC2 VPN Connection. * `filter` - (Optional) Configuration block(s) for filtering. Detailed below. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). -### filter Configuration Block +### Filter Configuration Block The `filter` configuration block supports the following arguments: From 3edc5697521d0681f603a415d0be68c2573c6cbe Mon Sep 17 00:00:00 2001 From: Subham Mukhopadhyay Date: Tue, 14 Oct 2025 03:15:35 +0530 Subject: [PATCH 05/11] add changelog file --- .changelog/44622.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/44622.txt diff --git a/.changelog/44622.txt b/.changelog/44622.txt new file mode 100644 index 000000000000..13905fbbc4f2 --- /dev/null +++ b/.changelog/44622.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_ec2_vpn_connection +``` \ No newline at end of file From 9c3022f4fbdc76fabe399047978a75638730b426 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 14 Oct 2025 10:28:05 -0400 Subject: [PATCH 06/11] chore: revert mod changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ```console % make t K=ec2 T=TestAccEC2VPNConnectionDataSource_ make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_ec2_vpn_connection-new-data-source 🌿... TF_ACC=1 go1.24.8 test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2VPNConnectionDataSource_' -timeout 360m -vet=off 2025/10/14 10:23:05 Creating Terraform AWS Provider (SDKv2-style)... 2025/10/14 10:23:05 Initializing Terraform AWS Provider (SDKv2-style)... --- PASS: TestAccEC2VPNConnectionDataSource_noInput (1.62s) --- PASS: TestAccEC2VPNConnectionDataSource_nonExistentId (2.57s) --- PASS: TestAccEC2VPNConnectionDataSource_byFilter (252.11s) --- PASS: TestAccEC2VPNConnectionDataSource_basic (252.37s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 259.363s ``` --- go.mod | 1 - go.sum | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 54f0db8902b2..013d61a84b1b 100644 --- a/go.mod +++ b/go.mod @@ -383,7 +383,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/grpc v1.75.1 // indirect google.golang.org/protobuf v1.36.9 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect ) replace github.com/hashicorp/terraform-plugin-log => github.com/gdavison/terraform-plugin-log v0.0.0-20230928191232-6c653d8ef8fb diff --git a/go.sum b/go.sum index 1b6493894d42..0659acfcbd97 100644 --- a/go.sum +++ b/go.sum @@ -886,8 +886,7 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 6690fd5c78dc8fbb78a024e962da17f7d159e6a2 Mon Sep 17 00:00:00 2001 From: Subham Mukhopadhyay Date: Wed, 15 Oct 2025 00:40:33 +0530 Subject: [PATCH 07/11] fixed testnames, filenames --- .changelog/44622.txt | 2 +- internal/service/ec2/service_package_gen.go | 12 +++++------ .../service/ec2/vpn_connection_data_source.go | 2 +- .../ec2/vpn_connection_data_source_test.go | 20 +++++++++---------- ....markdown => vpn_connection.html.markdown} | 18 ++++++++--------- 5 files changed, 27 insertions(+), 27 deletions(-) rename website/docs/d/{ec2_vpn_connection.html.markdown => vpn_connection.html.markdown} (79%) diff --git a/.changelog/44622.txt b/.changelog/44622.txt index 13905fbbc4f2..78ec6b6baca4 100644 --- a/.changelog/44622.txt +++ b/.changelog/44622.txt @@ -1,3 +1,3 @@ ```release-note:new-data-source -aws_ec2_vpn_connection +aws_vpn_connection ``` \ No newline at end of file diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index adca6c9989a6..c2ad226a5fc1 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -38,12 +38,6 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S Name: "Capacity Block Offering", Region: unique.Make(inttypes.ResourceRegionDefault()), }, - { - Factory: newDataSourceVPNConnection, - TypeName: "aws_ec2_vpn_connection", - Name: "VPN Connection", - Region: unique.Make(inttypes.ResourceRegionDefault()), - }, { Factory: newSpotDataFeedSubscriptionDataSource, TypeName: "aws_spot_datafeed_subscription", @@ -81,6 +75,12 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S Name: "Security Group Rules", Region: unique.Make(inttypes.ResourceRegionDefault()), }, + { + Factory: newDataSourceVPNConnection, + TypeName: "aws_vpn_connection", + Name: "VPN Connection", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, } } diff --git a/internal/service/ec2/vpn_connection_data_source.go b/internal/service/ec2/vpn_connection_data_source.go index 0fda9c4e4744..62b36c613593 100644 --- a/internal/service/ec2/vpn_connection_data_source.go +++ b/internal/service/ec2/vpn_connection_data_source.go @@ -23,7 +23,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkDataSource("aws_ec2_vpn_connection", name="VPN Connection") +// @FrameworkDataSource("aws_vpn_connection", name="VPN Connection") func newDataSourceVPNConnection(context.Context) (datasource.DataSourceWithConfigure, error) { return &dataSourceVPNConnection{}, nil } diff --git a/internal/service/ec2/vpn_connection_data_source_test.go b/internal/service/ec2/vpn_connection_data_source_test.go index ed3b1d243be0..0efa0451406a 100644 --- a/internal/service/ec2/vpn_connection_data_source_test.go +++ b/internal/service/ec2/vpn_connection_data_source_test.go @@ -14,11 +14,11 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccEC2VPNConnectionDataSource_basic(t *testing.T) { +func TestAccVPNConnectionDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rBgpAsn := sdkacctest.RandIntRange(65501, 65534) - dataSourceName := "data.aws_ec2_vpn_connection.test" + dataSourceName := "data.aws_vpn_connection.test" resourceName := "aws_vpn_connection.test" resource.ParallelTest(t, resource.TestCase{ @@ -46,11 +46,11 @@ func TestAccEC2VPNConnectionDataSource_basic(t *testing.T) { }) } -func TestAccEC2VPNConnectionDataSource_byFilter(t *testing.T) { +func TestAccVPNConnectionDataSource_byFilter(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rBgpAsn := sdkacctest.RandIntRange(65501, 65534) - dataSourceName := "data.aws_ec2_vpn_connection.test" + dataSourceName := "data.aws_vpn_connection.test" resourceName := "aws_vpn_connection.test" resource.ParallelTest(t, resource.TestCase{ @@ -75,7 +75,7 @@ func TestAccEC2VPNConnectionDataSource_byFilter(t *testing.T) { }) } -func TestAccEC2VPNConnectionDataSource_nonExistentId(t *testing.T) { +func TestAccVPNConnectionDataSource_nonExistentId(t *testing.T) { ctx := acctest.Context(t) resource.ParallelTest(t, resource.TestCase{ @@ -91,7 +91,7 @@ func TestAccEC2VPNConnectionDataSource_nonExistentId(t *testing.T) { }) } -func TestAccEC2VPNConnectionDataSource_noInput(t *testing.T) { +func TestAccVPNConnectionDataSource_noInput(t *testing.T) { ctx := acctest.Context(t) resource.ParallelTest(t, resource.TestCase{ @@ -131,7 +131,7 @@ resource "aws_vpn_connection" "test" { type = "ipsec.1" } -data "aws_ec2_vpn_connection" "test" { +data "aws_vpn_connection" "test" { vpn_connection_id = aws_vpn_connection.test.id depends_on = [aws_vpn_connection.test] @@ -163,7 +163,7 @@ resource "aws_vpn_connection" "test" { type = "ipsec.1" } -data "aws_ec2_vpn_connection" "test" { +data "aws_vpn_connection" "test" { filter { name = "customer-gateway-id" values = [aws_customer_gateway.test.id] @@ -181,7 +181,7 @@ data "aws_ec2_vpn_connection" "test" { func testAccVPNConnectionDataSourceConfig_nonExistentId() string { return ` -data "aws_ec2_vpn_connection" "test" { +data "aws_vpn_connection" "test" { vpn_connection_id = "vpn-12345678901234567" } ` @@ -189,7 +189,7 @@ data "aws_ec2_vpn_connection" "test" { func testAccVPNConnectionDataSourceConfig_noInput() string { return ` -data "aws_ec2_vpn_connection" "test" { +data "aws_vpn_connection" "test" { # No vpn_connection_id or filter specified } ` diff --git a/website/docs/d/ec2_vpn_connection.html.markdown b/website/docs/d/vpn_connection.html.markdown similarity index 79% rename from website/docs/d/ec2_vpn_connection.html.markdown rename to website/docs/d/vpn_connection.html.markdown index a14905b462ef..4674ab4c2eb2 100644 --- a/website/docs/d/ec2_vpn_connection.html.markdown +++ b/website/docs/d/vpn_connection.html.markdown @@ -1,21 +1,21 @@ --- -subcategory: "EC2 (Elastic Compute Cloud)" +subcategory: "VPN (Site-to-Site)" layout: "aws" -page_title: "AWS: aws_ec2_vpn_connection" +page_title: "AWS: aws_vpn_connection" description: |- - Provides details about an AWS EC2 (Elastic Compute Cloud) VPN Connection. + Fetches details of a Site-to-Site VPN connection. A Site-to-Site VPN connection is an Internet Protocol security (IPsec) VPN connection between a VPC and an on-premises network. --- -# Data Source: aws_ec2_vpn_connection +# Data Source: aws_vpn_connection -Provides details about an AWS EC2 (Elastic Compute Cloud) VPN Connection. +Fetches details of a Site-to-Site VPN connection. A Site-to-Site VPN connection is an Internet Protocol security (IPsec) VPN connection between a VPC and an on-premises network. ## Example Usage ### Basic Usage ```terraform -data "aws_ec2_vpn_connection" "example" { +data "aws_vpn_connection" "example" { filter { name = "customer-gateway-id" values = ["cgw-1234567890"] @@ -23,19 +23,19 @@ data "aws_ec2_vpn_connection" "example" { } output "vpn_connection_id" { - value = data.aws_ec2_vpn_connection.example.vpn_connection_id + value = data.aws_vpn_connection.example.vpn_connection_id } ``` ### Find by VPN Connection ID ```terraform -data "aws_ec2_vpn_connection" "example" { +data "aws_vpn_connection" "example" { vpn_connection_id = "vpn-abcd1234567890" } output "gateway_association_state" { - value = data.aws_ec2_vpn_connection.example.gateway_association_state + value = data.aws_vpn_connection.example.gateway_association_state } ``` From b5e010edcfd5e5068c354ae65afc68342f2be013 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 15 Oct 2025 15:54:47 -0400 Subject: [PATCH 08/11] d/vpn_connection: match file naming with resource --- ...onnection_data_source.go => vpnsite_connection_data_source.go} | 0 ...data_source_test.go => vpnsite_connection_data_source_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename internal/service/ec2/{vpn_connection_data_source.go => vpnsite_connection_data_source.go} (100%) rename internal/service/ec2/{vpn_connection_data_source_test.go => vpnsite_connection_data_source_test.go} (100%) diff --git a/internal/service/ec2/vpn_connection_data_source.go b/internal/service/ec2/vpnsite_connection_data_source.go similarity index 100% rename from internal/service/ec2/vpn_connection_data_source.go rename to internal/service/ec2/vpnsite_connection_data_source.go diff --git a/internal/service/ec2/vpn_connection_data_source_test.go b/internal/service/ec2/vpnsite_connection_data_source_test.go similarity index 100% rename from internal/service/ec2/vpn_connection_data_source_test.go rename to internal/service/ec2/vpnsite_connection_data_source_test.go From a13572cfee9988af4cfbf55c1c45b87e7bde88fa Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 15 Oct 2025 16:56:49 -0400 Subject: [PATCH 09/11] d/vpn_connection(test): tweak test config setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ```console % make t K=ec2 T=TestAccVPNConnectionDataSource_ make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_ec2_vpn_connection-new-data-source 🌿... TF_ACC=1 go1.24.8 test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccVPNConnectionDataSource_' -timeout 360m -vet=off 2025/10/15 16:51:14 Creating Terraform AWS Provider (SDKv2-style)... 2025/10/15 16:51:14 Initializing Terraform AWS Provider (SDKv2-style)... --- PASS: TestAccVPNConnectionDataSource_noInput (1.42s) --- PASS: TestAccVPNConnectionDataSource_nonExistentId (2.32s) --- PASS: TestAccVPNConnectionDataSource_byFilter (243.04s) --- PASS: TestAccVPNConnectionDataSource_basic (243.18s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 250.058s ``` --- .../vpnsite_connection_data_source_test.go | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/internal/service/ec2/vpnsite_connection_data_source_test.go b/internal/service/ec2/vpnsite_connection_data_source_test.go index 0efa0451406a..75f720cbd179 100644 --- a/internal/service/ec2/vpnsite_connection_data_source_test.go +++ b/internal/service/ec2/vpnsite_connection_data_source_test.go @@ -107,7 +107,7 @@ func TestAccVPNConnectionDataSource_noInput(t *testing.T) { }) } -func testAccVPNConnectionDataSourceConfig_byId(rName string, rBgpAsn int) string { +func testAccVPNConnectionDataSourceConfigBase(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_vpn_gateway" "test" { tags = { @@ -130,39 +130,23 @@ resource "aws_vpn_connection" "test" { customer_gateway_id = aws_customer_gateway.test.id type = "ipsec.1" } +`, rName, rBgpAsn) +} +func testAccVPNConnectionDataSourceConfig_byId(rName string, rBgpAsn int) string { + return acctest.ConfigCompose( + testAccVPNConnectionDataSourceConfigBase(rName, rBgpAsn), + ` data "aws_vpn_connection" "test" { vpn_connection_id = aws_vpn_connection.test.id - - depends_on = [aws_vpn_connection.test] } -`, rName, rBgpAsn) +`) } func testAccVPNConnectionDataSourceConfig_byFilter(rName string, rBgpAsn int) string { - return fmt.Sprintf(` -resource "aws_vpn_gateway" "test" { - tags = { - Name = %[1]q - } -} - -resource "aws_customer_gateway" "test" { - bgp_asn = %[2]d - ip_address = "178.0.0.1" - type = "ipsec.1" - - tags = { - Name = %[1]q - } -} - -resource "aws_vpn_connection" "test" { - vpn_gateway_id = aws_vpn_gateway.test.id - customer_gateway_id = aws_customer_gateway.test.id - type = "ipsec.1" -} - + return acctest.ConfigCompose( + testAccVPNConnectionDataSourceConfigBase(rName, rBgpAsn), + ` data "aws_vpn_connection" "test" { filter { name = "customer-gateway-id" @@ -176,7 +160,7 @@ data "aws_vpn_connection" "test" { depends_on = [aws_vpn_connection.test] } -`, rName, rBgpAsn) +`) } func testAccVPNConnectionDataSourceConfig_nonExistentId() string { From 867263a0f58032b9d6244899f64b4080fffa168b Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 15 Oct 2025 17:07:27 -0400 Subject: [PATCH 10/11] d/vpn_connection: remove `id` attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ```console % make t K=ec2 T=TestAccVPNConnectionDataSource_ make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_ec2_vpn_connection-new-data-source 🌿... TF_ACC=1 go1.24.8 test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccVPNConnectionDataSource_' -timeout 360m -vet=off 2025/10/15 17:01:59 Creating Terraform AWS Provider (SDKv2-style)... 2025/10/15 17:01:59 Initializing Terraform AWS Provider (SDKv2-style)... --- PASS: TestAccVPNConnectionDataSource_noInput (1.61s) --- PASS: TestAccVPNConnectionDataSource_nonExistentId (2.56s) --- PASS: TestAccVPNConnectionDataSource_byFilter (298.01s) --- PASS: TestAccVPNConnectionDataSource_basic (588.72s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 595.637s ``` --- internal/service/ec2/vpnsite_connection_data_source.go | 9 ++------- .../service/ec2/vpnsite_connection_data_source_test.go | 2 -- website/docs/d/vpn_connection.html.markdown | 9 ++++----- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/internal/service/ec2/vpnsite_connection_data_source.go b/internal/service/ec2/vpnsite_connection_data_source.go index 62b36c613593..d25fa5ecf1f0 100644 --- a/internal/service/ec2/vpnsite_connection_data_source.go +++ b/internal/service/ec2/vpnsite_connection_data_source.go @@ -6,7 +6,6 @@ package ec2 import ( "context" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" @@ -58,7 +57,6 @@ func (d *dataSourceVPNConnection) Schema(ctx context.Context, req datasource.Sch CustomType: fwtypes.StringEnumType[awstypes.GatewayAssociationState](), Computed: true, }, - names.AttrID: framework.IDAttribute(), "pre_shared_key_arn": schema.StringAttribute{ Computed: true, }, @@ -114,7 +112,6 @@ func (d *dataSourceVPNConnection) Read(ctx context.Context, req datasource.ReadR if resp.Diagnostics.HasError() { return } - data.ID = types.StringValue(aws.ToString(out.VpnConnectionId)) smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &data), smerr.ID, data.VpnConnectionId.String()) } @@ -129,15 +126,12 @@ func (d *dataSourceVPNConnection) ConfigValidators(_ context.Context) []datasour type dataSourceVPNConnectionModel struct { framework.WithRegionModel - Filters customFilters `tfsdk:"filter"` - VpnConnectionId types.String `tfsdk:"vpn_connection_id"` - ID types.String `tfsdk:"id"` - Category types.String `tfsdk:"category"` CoreNetworkArn types.String `tfsdk:"core_network_arn"` CoreNetworkAttachmentArn types.String `tfsdk:"core_network_attachment_arn"` CustomerGatewayConfiguration types.String `tfsdk:"customer_gateway_configuration"` CustomerGatewayID types.String `tfsdk:"customer_gateway_id"` + Filters customFilters `tfsdk:"filter"` GatewayAssociationState fwtypes.StringEnum[awstypes.GatewayAssociationState] `tfsdk:"gateway_association_state"` PreSharedKeyArn types.String `tfsdk:"pre_shared_key_arn"` State fwtypes.StringEnum[awstypes.VpnState] `tfsdk:"state"` @@ -146,6 +140,7 @@ type dataSourceVPNConnectionModel struct { VpnGatewayId types.String `tfsdk:"vpn_gateway_id"` Routes fwtypes.ListNestedObjectValueOf[routeModel] `tfsdk:"routes"` VgwTelemetries fwtypes.ListNestedObjectValueOf[vgwTelemetryModel] `tfsdk:"vgw_telemetries"` + VpnConnectionId types.String `tfsdk:"vpn_connection_id"` Tags tftags.Map `tfsdk:"tags"` } diff --git a/internal/service/ec2/vpnsite_connection_data_source_test.go b/internal/service/ec2/vpnsite_connection_data_source_test.go index 75f720cbd179..7cdffdec6cf8 100644 --- a/internal/service/ec2/vpnsite_connection_data_source_test.go +++ b/internal/service/ec2/vpnsite_connection_data_source_test.go @@ -30,7 +30,6 @@ func TestAccVPNConnectionDataSource_basic(t *testing.T) { { Config: testAccVPNConnectionDataSourceConfig_byId(rName, rBgpAsn), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID), resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", resourceName, names.AttrID), resource.TestCheckResourceAttrPair(dataSourceName, "customer_gateway_id", resourceName, "customer_gateway_id"), resource.TestCheckResourceAttrPair(dataSourceName, "vpn_gateway_id", resourceName, "vpn_gateway_id"), @@ -62,7 +61,6 @@ func TestAccVPNConnectionDataSource_byFilter(t *testing.T) { { Config: testAccVPNConnectionDataSourceConfig_byFilter(rName, rBgpAsn), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID), resource.TestCheckResourceAttrPair(dataSourceName, "vpn_connection_id", resourceName, names.AttrID), resource.TestCheckResourceAttrPair(dataSourceName, "customer_gateway_id", resourceName, "customer_gateway_id"), resource.TestCheckResourceAttrPair(dataSourceName, "vpn_gateway_id", resourceName, "vpn_gateway_id"), diff --git a/website/docs/d/vpn_connection.html.markdown b/website/docs/d/vpn_connection.html.markdown index 4674ab4c2eb2..62c8f77c3d68 100644 --- a/website/docs/d/vpn_connection.html.markdown +++ b/website/docs/d/vpn_connection.html.markdown @@ -51,7 +51,7 @@ This data source supports the following arguments: The `filter` configuration block supports the following arguments: -* `name` - (Required) Name of the filter field. Valid values can be found in the [EC2 DescribeVPNConnections API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpnConnections.html). +* `name` - (Required) Name of the filter field. Valid values can be found in the [EC2 `DescribeVPNConnections` API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpnConnections.html). * `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. ## Attribute Reference @@ -65,11 +65,10 @@ This data source exports the following attributes in addition to the arguments a * `customer_gateway_id` - ID of the customer gateway at your end of the VPN connection. * `gateway_association_state` - Current state of the gateway association. * `pre_shared_key_arn` - (ARN) of the Secrets Manager secret storing the pre-shared key(s) for the VPN connection. +* `routes` - List of static routes associated with the VPN connection. * `state` - Current state of the VPN connection. +* `tags` - Tags associated to the VPN Connection. * `transit_gateway_id` - ID of a transit gateway associated with the VPN connection. * `type` - Type of VPN connection. Currently the only supported type is ipsec.1. -* `vpn_gateway_id` - ID of a virtual private gateway associated with the VPN connection. -* `id` - EC2 VPN Connection identifier. -* `tags` - Tags associated to the VPN Connection. -* `routes` - List of static routes associated with the VPN connection. * `vgw_telemetries` - List of objects containing information about the VPN tunnel. +* `vpn_gateway_id` - ID of a virtual private gateway associated with the VPN connection. From db3ac2f30059839b1146c06f1f05aa22d690d11f Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 15 Oct 2025 17:17:20 -0400 Subject: [PATCH 11/11] chore: fix semgrep findings --- .../service/ec2/vpnsite_connection_data_source_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/ec2/vpnsite_connection_data_source_test.go b/internal/service/ec2/vpnsite_connection_data_source_test.go index 7cdffdec6cf8..305ded782967 100644 --- a/internal/service/ec2/vpnsite_connection_data_source_test.go +++ b/internal/service/ec2/vpnsite_connection_data_source_test.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccVPNConnectionDataSource_basic(t *testing.T) { +func TestAccSiteVPNConnectionDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rBgpAsn := sdkacctest.RandIntRange(65501, 65534) @@ -45,7 +45,7 @@ func TestAccVPNConnectionDataSource_basic(t *testing.T) { }) } -func TestAccVPNConnectionDataSource_byFilter(t *testing.T) { +func TestAccSiteVPNConnectionDataSource_byFilter(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rBgpAsn := sdkacctest.RandIntRange(65501, 65534) @@ -73,7 +73,7 @@ func TestAccVPNConnectionDataSource_byFilter(t *testing.T) { }) } -func TestAccVPNConnectionDataSource_nonExistentId(t *testing.T) { +func TestAccSiteVPNConnectionDataSource_nonExistentId(t *testing.T) { ctx := acctest.Context(t) resource.ParallelTest(t, resource.TestCase{ @@ -89,7 +89,7 @@ func TestAccVPNConnectionDataSource_nonExistentId(t *testing.T) { }) } -func TestAccVPNConnectionDataSource_noInput(t *testing.T) { +func TestAccSiteVPNConnectionDataSource_noInput(t *testing.T) { ctx := acctest.Context(t) resource.ParallelTest(t, resource.TestCase{