From a7fad01b42fb1b9c78368d9da0590697ccc7747f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:09:50 -0400 Subject: [PATCH 01/25] r/aws_eip_association: Reduce visibility. --- internal/service/ec2/ec2_eip.go | 2 +- internal/service/ec2/ec2_eip_association.go | 8 ++++---- internal/service/ec2/exports_test.go | 2 ++ internal/service/ec2/find.go | 2 +- internal/service/ec2/service_package_gen.go | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index c8a99402997..b365504f187 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -344,7 +344,7 @@ func associateEIP(ctx context.Context, conn *ec2.EC2, allocationID, instanceID, _, err = tfresource.RetryWhen(ctx, ec2PropagationTimeout, func() (interface{}, error) { - return FindEIPByAssociationID(ctx, conn, aws.StringValue(output.AssociationId)) + return findEIPByAssociationID(ctx, conn, aws.StringValue(output.AssociationId)) }, func(err error) (bool, error) { if tfresource.NotFound(err) { diff --git a/internal/service/ec2/ec2_eip_association.go b/internal/service/ec2/ec2_eip_association.go index f2ea615c3b2..dbaca94db9f 100644 --- a/internal/service/ec2/ec2_eip_association.go +++ b/internal/service/ec2/ec2_eip_association.go @@ -18,8 +18,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -// @SDKResource("aws_eip_association") -func ResourceEIPAssociation() *schema.Resource { +// @SDKResource("aws_eip_association", name="EIP Association") +func resourceEIPAssociation() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEIPAssociationCreate, ReadWithoutTimeout: resourceEIPAssociationRead, @@ -109,7 +109,7 @@ func resourceEIPAssociationCreate(ctx context.Context, d *schema.ResourceData, m _, err = tfresource.RetryWhen(ctx, ec2PropagationTimeout, func() (interface{}, error) { - return FindEIPByAssociationID(ctx, conn, d.Id()) + return findEIPByAssociationID(ctx, conn, d.Id()) }, func(err error) (bool, error) { if tfresource.NotFound(err) { @@ -140,7 +140,7 @@ func resourceEIPAssociationRead(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, ec2.DomainTypeStandard) } - address, err := FindEIPByAssociationID(ctx, conn, d.Id()) + address, err := findEIPByAssociationID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EC2 EIP Association (%s) not found, removing from state", d.Id()) diff --git a/internal/service/ec2/exports_test.go b/internal/service/ec2/exports_test.go index 5459bd22ee9..35cbe22e788 100644 --- a/internal/service/ec2/exports_test.go +++ b/internal/service/ec2/exports_test.go @@ -9,6 +9,7 @@ var ( ResourceDefaultNetworkACL = resourceDefaultNetworkACL ResourceDefaultRouteTable = resourceDefaultRouteTable ResourceEBSFastSnapshotRestore = newEBSFastSnapshotRestoreResource + ResourceEIPAssociation = resourceEIPAssociation ResourceInstanceConnectEndpoint = newInstanceConnectEndpointResource ResourceInstanceMetadataDefaults = newInstanceMetadataDefaultsResource ResourceKeyPair = resourceKeyPair @@ -28,6 +29,7 @@ var ( ResourceVPNGatewayRoutePropagation = resourceVPNGatewayRoutePropagation CustomFiltersSchema = customFiltersSchema + FindEIPByAssociationID = findEIPByAssociationID FindFastSnapshotRestoreByTwoPartKey = findFastSnapshotRestoreByTwoPartKey FindInstanceMetadataDefaults = findInstanceMetadataDefaults FindKeyPairByName = findKeyPairByName diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 59407fc4e6e..0092d63ea48 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -694,7 +694,7 @@ func FindEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2. return output, nil } -func FindEIPByAssociationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Address, error) { +func findEIPByAssociationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Address, error) { input := &ec2.DescribeAddressesInput{ Filters: newAttributeFilterList(map[string]string{ "association-id": id, diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 88b1b95947b..c69b68fa80c 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -816,8 +816,9 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { - Factory: ResourceEIPAssociation, + Factory: resourceEIPAssociation, TypeName: "aws_eip_association", + Name: "EIP Association", }, { Factory: ResourceFlowLog, From 4c4d126c12fa18d1312b736137f9d6e5ac8c006e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:13:25 -0400 Subject: [PATCH 02/25] r/aws_eip: Reduce visibility. --- internal/service/ec2/service_package_gen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index c69b68fa80c..ad17f030be7 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -808,7 +808,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { - Factory: ResourceEIP, + Factory: resourceEIP, TypeName: "aws_eip", Name: "EIP", Tags: &types.ServicePackageResourceTags{ From a32766888a1480a16d43702c893c96b5b55b8000 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:15:46 -0400 Subject: [PATCH 03/25] d/aws_eips: Reduce visibility. --- internal/service/ec2/ec2_eip.go | 7 ++++--- internal/service/ec2/ec2_eips_data_source.go | 8 ++++---- internal/service/ec2/exports_test.go | 2 ++ internal/service/ec2/find.go | 6 +++--- internal/service/ec2/service_package_gen.go | 3 ++- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index b365504f187..b67079117a4 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -27,12 +27,13 @@ import ( // @SDKResource("aws_eip", name="EIP") // @Tags(identifierAttribute="id") -func ResourceEIP() *schema.Resource { +func resourceEIP() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEIPCreate, ReadWithoutTimeout: resourceEIPRead, UpdateWithoutTimeout: resourceEIPUpdate, DeleteWithoutTimeout: resourceEIPDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -176,7 +177,7 @@ func resourceEIPCreate(ctx context.Context, d *schema.ResourceData, meta interfa d.SetId(aws.StringValue(output.AllocationId)) _, err = tfresource.RetryWhenNotFound(ctx, d.Timeout(schema.TimeoutCreate), func() (interface{}, error) { - return FindEIPByAllocationID(ctx, conn, d.Id()) + return findEIPByAllocationID(ctx, conn, d.Id()) }) if err != nil { @@ -206,7 +207,7 @@ func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface } outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, ec2PropagationTimeout, func() (interface{}, error) { - return FindEIPByAllocationID(ctx, conn, d.Id()) + return findEIPByAllocationID(ctx, conn, d.Id()) }, d.IsNewResource()) if !d.IsNewResource() && tfresource.NotFound(err) { diff --git a/internal/service/ec2/ec2_eips_data_source.go b/internal/service/ec2/ec2_eips_data_source.go index 35f24039572..06c462f7926 100644 --- a/internal/service/ec2/ec2_eips_data_source.go +++ b/internal/service/ec2/ec2_eips_data_source.go @@ -16,8 +16,8 @@ import ( tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) -// @SDKDataSource("aws_eips") -func DataSourceEIPs() *schema.Resource { +// @SDKDataSource("aws_eips", name="EIPs") +func dataSourceEIPs() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceEIPsRead, @@ -37,7 +37,7 @@ func DataSourceEIPs() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "tags": tftags.TagsSchemaComputed(), + "tags": tftags.TagsSchema(), }, } } @@ -63,7 +63,7 @@ func dataSourceEIPsRead(ctx context.Context, d *schema.ResourceData, meta interf input.Filters = nil } - output, err := FindEIPs(ctx, conn, input) + output, err := findEIPs(ctx, conn, input) if err != nil { return sdkdiag.AppendErrorf(diags, "reading EC2 EIPs: %s", err) diff --git a/internal/service/ec2/exports_test.go b/internal/service/ec2/exports_test.go index 35cbe22e788..8785fb05f77 100644 --- a/internal/service/ec2/exports_test.go +++ b/internal/service/ec2/exports_test.go @@ -9,6 +9,7 @@ var ( ResourceDefaultNetworkACL = resourceDefaultNetworkACL ResourceDefaultRouteTable = resourceDefaultRouteTable ResourceEBSFastSnapshotRestore = newEBSFastSnapshotRestoreResource + ResourceEIP = resourceEIP ResourceEIPAssociation = resourceEIPAssociation ResourceInstanceConnectEndpoint = newInstanceConnectEndpointResource ResourceInstanceMetadataDefaults = newInstanceMetadataDefaultsResource @@ -29,6 +30,7 @@ var ( ResourceVPNGatewayRoutePropagation = resourceVPNGatewayRoutePropagation CustomFiltersSchema = customFiltersSchema + FindEIPByAllocationID = findEIPByAllocationID FindEIPByAssociationID = findEIPByAssociationID FindFastSnapshotRestoreByTwoPartKey = findFastSnapshotRestoreByTwoPartKey FindInstanceMetadataDefaults = findInstanceMetadataDefaults diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 0092d63ea48..c03811786ff 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -637,7 +637,7 @@ func FindEBSVolumeAttachment(ctx context.Context, conn *ec2.EC2, volumeID, insta return nil, &retry.NotFoundError{} } -func FindEIPs(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) ([]*ec2.Address, error) { +func findEIPs(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) ([]*ec2.Address, error) { var addresses []*ec2.Address output, err := conn.DescribeAddressesWithContext(ctx, input) @@ -664,7 +664,7 @@ func FindEIPs(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesIn } func FindEIP(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) (*ec2.Address, error) { - output, err := FindEIPs(ctx, conn, input) + output, err := findEIPs(ctx, conn, input) if err != nil { return nil, err @@ -673,7 +673,7 @@ func FindEIP(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInp return tfresource.AssertSinglePtrResult(output) } -func FindEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Address, error) { +func findEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Address, error) { input := &ec2.DescribeAddressesInput{ AllocationIds: aws.StringSlice([]string{id}), } diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index ad17f030be7..847eb14b4d9 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -274,8 +274,9 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac TypeName: "aws_eip", }, { - Factory: DataSourceEIPs, + Factory: dataSourceEIPs, TypeName: "aws_eips", + Name: "EIPs", }, { Factory: DataSourceInstance, From e735c8be40e7582fe4b1389cd2948cb72b09f6ab Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:17:13 -0400 Subject: [PATCH 04/25] d/aws_eip: Reduce visibility. --- internal/service/ec2/ec2_eip_data_source.go | 6 +++--- internal/service/ec2/find.go | 6 +++--- internal/service/ec2/service_package_gen.go | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/service/ec2/ec2_eip_data_source.go b/internal/service/ec2/ec2_eip_data_source.go index fabe72f3094..2278b6785f3 100644 --- a/internal/service/ec2/ec2_eip_data_source.go +++ b/internal/service/ec2/ec2_eip_data_source.go @@ -17,8 +17,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -// @SDKDataSource("aws_eip") -func DataSourceEIP() *schema.Resource { +// @SDKDataSource("aws_eip", name="EIP) +func dataSourceEIP() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceEIPRead, @@ -119,7 +119,7 @@ func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interfa input.Filters = nil } - eip, err := FindEIP(ctx, conn, input) + eip, err := findEIP(ctx, conn, input) if err != nil { return sdkdiag.AppendFromErr(diags, tfresource.SingularDataSourceFindError("EC2 EIP", err)) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index c03811786ff..b9d5c65d5bd 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -663,7 +663,7 @@ func findEIPs(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesIn return addresses, nil } -func FindEIP(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) (*ec2.Address, error) { +func findEIP(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) (*ec2.Address, error) { output, err := findEIPs(ctx, conn, input) if err != nil { @@ -678,7 +678,7 @@ func findEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2. AllocationIds: aws.StringSlice([]string{id}), } - output, err := FindEIP(ctx, conn, input) + output, err := findEIP(ctx, conn, input) if err != nil { return nil, err @@ -701,7 +701,7 @@ func findEIPByAssociationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2 }), } - output, err := FindEIP(ctx, conn, input) + output, err := findEIP(ctx, conn, input) if err != nil { return nil, err diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 847eb14b4d9..a1e8c4cc183 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -270,8 +270,9 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac TypeName: "aws_ec2_transit_gateway_vpn_attachment", }, { - Factory: DataSourceEIP, + Factory: dataSourceEIP, TypeName: "aws_eip", + Name: "EIP", }, { Factory: dataSourceEIPs, From c4e674a1fee1c68ac38f8381c4a86dafa55cf353 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:31:34 -0400 Subject: [PATCH 05/25] d/aws_eips: Migrate to AWS SDK for Go v2. --- internal/service/ec2/ec2_eips_data_source.go | 19 +++++----- internal/service/ec2/filters.go | 12 ++++--- internal/service/ec2/find.go | 38 +++++++++----------- internal/service/ec2/sweep.go | 2 +- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/internal/service/ec2/ec2_eips_data_source.go b/internal/service/ec2/ec2_eips_data_source.go index 06c462f7926..dbc2eac45d3 100644 --- a/internal/service/ec2/ec2_eips_data_source.go +++ b/internal/service/ec2/ec2_eips_data_source.go @@ -7,8 +7,9 @@ import ( "context" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -44,19 +45,19 @@ func dataSourceEIPs() *schema.Resource { func dataSourceEIPsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) input := &ec2.DescribeAddressesInput{} if tags, tagsOk := d.GetOk("tags"); tagsOk { - input.Filters = append(input.Filters, newTagFilterList( - Tags(tftags.New(ctx, tags.(map[string]interface{}))), + input.Filters = append(input.Filters, newTagFilterListV2( + TagsV2(tftags.New(ctx, tags.(map[string]interface{}))), )...) } if filters, filtersOk := d.GetOk("filter"); filtersOk { input.Filters = append(input.Filters, - newCustomFilterList(filters.(*schema.Set))...) + newCustomFilterListV2(filters.(*schema.Set))...) } if len(input.Filters) == 0 { @@ -73,10 +74,10 @@ func dataSourceEIPsRead(ctx context.Context, d *schema.ResourceData, meta interf var publicIPs []string for _, v := range output { - publicIPs = append(publicIPs, aws.StringValue(v.PublicIp)) + publicIPs = append(publicIPs, aws.ToString(v.PublicIp)) - if aws.StringValue(v.Domain) == ec2.DomainTypeVpc { - allocationIDs = append(allocationIDs, aws.StringValue(v.AllocationId)) + if v.Domain == types.DomainTypeVpc { + allocationIDs = append(allocationIDs, aws.ToString(v.AllocationId)) } } diff --git a/internal/service/ec2/filters.go b/internal/service/ec2/filters.go index 534dbc14dce..8abc32b84fa 100644 --- a/internal/service/ec2/filters.go +++ b/internal/service/ec2/filters.go @@ -61,6 +61,12 @@ func newTagFilterList(tags []*ec2_sdkv1.Tag) []*ec2_sdkv1.Filter { }) } +func newTagFilterListV2(tags []awstypes.Tag) []awstypes.Filter { + return tfslices.ApplyToAll(tags, func(tag awstypes.Tag) awstypes.Filter { + return newFilterV2("tag:"+aws_sdkv2.ToString(tag.Key), []string{aws_sdkv2.ToString(tag.Value)}) + }) +} + // attributeFiltersFromMultimap returns an array of EC2 Filter objects to be used when listing resources. // // The keys of the specified map are the resource attributes names used in the filter - see the documentation @@ -85,11 +91,7 @@ func attributeFiltersFromMultimap(m map[string][]string) []*ec2_sdkv1.Filter { // tagFilters returns an array of EC2 Filter objects to be used when listing resources by tag. func tagFilters(ctx context.Context) []awstypes.Filter { - tags := getTagsIn(ctx) - - return tfslices.ApplyToAll(tags, func(tag *ec2_sdkv1.Tag) awstypes.Filter { - return newFilterV2("tag:"+aws_sdkv1.StringValue(tag.Key), []string{aws_sdkv1.StringValue(tag.Value)}) - }) + return newTagFilterListV2(getTagsInV2(ctx)) } // customFiltersSchema returns a *schema.Schema that represents diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index b9d5c65d5bd..e41407484ad 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -637,13 +637,11 @@ func FindEBSVolumeAttachment(ctx context.Context, conn *ec2.EC2, volumeID, insta return nil, &retry.NotFoundError{} } -func findEIPs(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) ([]*ec2.Address, error) { - var addresses []*ec2.Address +func findEIPs(ctx context.Context, conn *ec2_sdkv2.Client, input *ec2_sdkv2.DescribeAddressesInput) ([]awstypes.Address, error) { + output, err := conn.DescribeAddresses(ctx, input) - output, err := conn.DescribeAddressesWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, errCodeInvalidAddressNotFound, errCodeInvalidAllocationIDNotFound) || - tfawserr.ErrMessageContains(err, errCodeAuthFailure, "does not belong to you") { + if tfawserr_sdkv2.ErrCodeEquals(err, errCodeInvalidAddressNotFound, errCodeInvalidAllocationIDNotFound) || + tfawserr_sdkv2.ErrMessageContains(err, errCodeAuthFailure, "does not belong to you") { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -654,28 +652,26 @@ func findEIPs(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesIn return nil, err } - for _, v := range output.Addresses { - if v != nil { - addresses = append(addresses, v) - } + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } - return addresses, nil + return output.Addresses, nil } -func findEIP(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeAddressesInput) (*ec2.Address, error) { +func findEIP(ctx context.Context, conn *ec2_sdkv2.Client, input *ec2_sdkv2.DescribeAddressesInput) (*awstypes.Address, error) { output, err := findEIPs(ctx, conn, input) if err != nil { return nil, err } - return tfresource.AssertSinglePtrResult(output) + return tfresource.AssertSingleValueResult(output) } -func findEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Address, error) { - input := &ec2.DescribeAddressesInput{ - AllocationIds: aws.StringSlice([]string{id}), +func findEIPByAllocationID(ctx context.Context, conn *ec2_sdkv2.Client, id string) (*awstypes.Address, error) { + input := &ec2_sdkv2.DescribeAddressesInput{ + AllocationIds: []string{id}, } output, err := findEIP(ctx, conn, input) @@ -685,7 +681,7 @@ func findEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2. } // Eventual consistency check. - if aws.StringValue(output.AllocationId) != id { + if aws_sdkv2.ToString(output.AllocationId) != id { return nil, &retry.NotFoundError{ LastRequest: input, } @@ -694,9 +690,9 @@ func findEIPByAllocationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2. return output, nil } -func findEIPByAssociationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Address, error) { - input := &ec2.DescribeAddressesInput{ - Filters: newAttributeFilterList(map[string]string{ +func findEIPByAssociationID(ctx context.Context, conn *ec2_sdkv2.Client, id string) (*awstypes.Address, error) { + input := &ec2_sdkv2.DescribeAddressesInput{ + Filters: newAttributeFilterListV2(map[string]string{ "association-id": id, }), } @@ -708,7 +704,7 @@ func findEIPByAssociationID(ctx context.Context, conn *ec2.EC2, id string) (*ec2 } // Eventual consistency check. - if aws.StringValue(output.AssociationId) != id { + if aws_sdkv2.ToString(output.AssociationId) != id { return nil, &retry.NotFoundError{ LastRequest: input, } diff --git a/internal/service/ec2/sweep.go b/internal/service/ec2/sweep.go index a9b92996e4c..09343df2e97 100644 --- a/internal/service/ec2/sweep.go +++ b/internal/service/ec2/sweep.go @@ -881,7 +881,7 @@ func sweepEIPs(region string) error { continue } - r := ResourceEIP() + r := resourceEIP() d := r.Data(nil) if address.AllocationId != nil { d.SetId(aws.StringValue(address.AllocationId)) From fe563a12a37cb30d7057b5f5f7a366e29a4f23b0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:38:21 -0400 Subject: [PATCH 06/25] d/aws_eip: Migrate to AWS SDK for Go v2. --- internal/service/ec2/ec2_eip_data_source.go | 38 +++++++++---------- internal/service/ec2/ec2_eips_data_source.go | 3 +- .../service/ec2/ec2_key_pair_data_source.go | 2 +- internal/service/ec2/service_package_gen.go | 9 ++--- .../ec2/vpc_network_interface_data_source.go | 2 +- 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/internal/service/ec2/ec2_eip_data_source.go b/internal/service/ec2/ec2_eip_data_source.go index 2278b6785f3..77416a00b71 100644 --- a/internal/service/ec2/ec2_eip_data_source.go +++ b/internal/service/ec2/ec2_eip_data_source.go @@ -7,17 +7,20 @@ import ( "context" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "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/names" ) // @SDKDataSource("aws_eip", name="EIP) +// @Tags func dataSourceEIP() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceEIPRead, @@ -86,31 +89,30 @@ func dataSourceEIP() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "tags": tftags.TagsSchemaComputed(), + names.AttrTags: tftags.TagsSchemaComputed(), }, } } func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) - ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + conn := meta.(*conns.AWSClient).EC2Client(ctx) input := &ec2.DescribeAddressesInput{} if v, ok := d.GetOk("id"); ok { - input.AllocationIds = aws.StringSlice([]string{v.(string)}) + input.AllocationIds = []string{v.(string)} } if v, ok := d.GetOk("public_ip"); ok { - input.PublicIps = aws.StringSlice([]string{v.(string)}) + input.PublicIps = []string{v.(string)} } - input.Filters = append(input.Filters, newTagFilterList( - Tags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))), + input.Filters = append(input.Filters, newTagFilterListV2( + TagsV2(tftags.New(ctx, d.Get("tags").(map[string]interface{}))), )...) - input.Filters = append(input.Filters, newCustomFilterList( + input.Filters = append(input.Filters, newCustomFilterListV2( d.Get("filter").(*schema.Set), )...) @@ -125,10 +127,10 @@ func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interfa return sdkdiag.AppendFromErr(diags, tfresource.SingularDataSourceFindError("EC2 EIP", err)) } - if aws.StringValue(eip.Domain) == ec2.DomainTypeVpc { - d.SetId(aws.StringValue(eip.AllocationId)) + if eip.Domain == types.DomainTypeVpc { + d.SetId(aws.ToString(eip.AllocationId)) } else { - d.SetId(aws.StringValue(eip.PublicIp)) + d.SetId(aws.ToString(eip.PublicIp)) } d.Set("association_id", eip.AssociationId) d.Set("carrier_ip", eip.CarrierIp) @@ -139,20 +141,16 @@ func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interfa d.Set("network_interface_id", eip.NetworkInterfaceId) d.Set("network_interface_owner_id", eip.NetworkInterfaceOwnerId) d.Set("public_ipv4_pool", eip.PublicIpv4Pool) - d.Set("private_ip", eip.PrivateIpAddress) - if v := aws.StringValue(eip.PrivateIpAddress); v != "" { + if v := aws.ToString(eip.PrivateIpAddress); v != "" { d.Set("private_dns", PrivateDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) } - d.Set("public_ip", eip.PublicIp) - if v := aws.StringValue(eip.PublicIp); v != "" { + if v := aws.ToString(eip.PublicIp); v != "" { d.Set("public_dns", PublicDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) } - if err := d.Set("tags", KeyValueTags(ctx, eip.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) - } + setTagsOutV2(ctx, eip.Tags) return diags } diff --git a/internal/service/ec2/ec2_eips_data_source.go b/internal/service/ec2/ec2_eips_data_source.go index dbc2eac45d3..81863102379 100644 --- a/internal/service/ec2/ec2_eips_data_source.go +++ b/internal/service/ec2/ec2_eips_data_source.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKDataSource("aws_eips", name="EIPs") @@ -38,7 +39,7 @@ func dataSourceEIPs() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "tags": tftags.TagsSchema(), + names.AttrTags: tftags.TagsSchema(), }, } } diff --git a/internal/service/ec2/ec2_key_pair_data_source.go b/internal/service/ec2/ec2_key_pair_data_source.go index 454ca1c54bc..5039f35e2d5 100644 --- a/internal/service/ec2/ec2_key_pair_data_source.go +++ b/internal/service/ec2/ec2_key_pair_data_source.go @@ -20,7 +20,7 @@ import ( ) // @SDKDataSource("aws_key_pair", name="Key Pair") -// @Tags(identifierAttribute="key_pair_id") +// @Tags func dataSourceKeyPair() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceKeyPairRead, diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index a1e8c4cc183..b8bf9f36959 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -273,6 +273,7 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac Factory: dataSourceEIP, TypeName: "aws_eip", Name: "EIP", + Tags: &types.ServicePackageResourceTags{}, }, { Factory: dataSourceEIPs, @@ -295,9 +296,7 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac Factory: dataSourceKeyPair, TypeName: "aws_key_pair", Name: "Key Pair", - Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: "key_pair_id", - }, + Tags: &types.ServicePackageResourceTags{}, }, { Factory: DataSourceLaunchTemplate, @@ -319,9 +318,7 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac Factory: dataSourceNetworkInterface, TypeName: "aws_network_interface", Name: "Network Interface", - Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: "id", - }, + Tags: &types.ServicePackageResourceTags{}, }, { Factory: DataSourceNetworkInterfaces, diff --git a/internal/service/ec2/vpc_network_interface_data_source.go b/internal/service/ec2/vpc_network_interface_data_source.go index d09f7e93b94..c1b3e74e3ca 100644 --- a/internal/service/ec2/vpc_network_interface_data_source.go +++ b/internal/service/ec2/vpc_network_interface_data_source.go @@ -21,7 +21,7 @@ import ( ) // @SDKDataSource("aws_network_interface", name="Network Interface") -// @Tags(identifierAttribute="id") +// @Tags func dataSourceNetworkInterface() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceNetworkInterfaceRead, From c923a9337bc85476704537f8e7b0e102233d5b84 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:42:07 -0400 Subject: [PATCH 07/25] r/aws_eip_association: Migrate to AWS SDK for Go v2. --- internal/service/ec2/ec2_eip_association.go | 23 ++++++++++--------- .../service/ec2/ec2_eip_association_test.go | 22 ++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/internal/service/ec2/ec2_eip_association.go b/internal/service/ec2/ec2_eip_association.go index dbaca94db9f..ead8ac3340e 100644 --- a/internal/service/ec2/ec2_eip_association.go +++ b/internal/service/ec2/ec2_eip_association.go @@ -8,9 +8,10 @@ import ( "log" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -71,7 +72,7 @@ func resourceEIPAssociation() *schema.Resource { func resourceEIPAssociationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) input := &ec2.AssociateAddressInput{} @@ -99,13 +100,13 @@ func resourceEIPAssociationCreate(ctx context.Context, d *schema.ResourceData, m input.PublicIp = aws.String(v.(string)) } - output, err := conn.AssociateAddressWithContext(ctx, input) + output, err := conn.AssociateAddress(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating EC2 EIP Association: %s", err) } - d.SetId(aws.StringValue(output.AssociationId)) + d.SetId(aws.ToString(output.AssociationId)) _, err = tfresource.RetryWhen(ctx, ec2PropagationTimeout, func() (interface{}, error) { @@ -134,10 +135,10 @@ func resourceEIPAssociationCreate(ctx context.Context, d *schema.ResourceData, m func resourceEIPAssociationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) if !eipAssociationID(d.Id()).IsVPC() { - return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, ec2.DomainTypeStandard) + return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, types.DomainTypeStandard) } address, err := findEIPByAssociationID(ctx, conn, d.Id()) @@ -163,10 +164,10 @@ func resourceEIPAssociationRead(ctx context.Context, d *schema.ResourceData, met func resourceEIPAssociationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) if !eipAssociationID(d.Id()).IsVPC() { - return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, ec2.DomainTypeStandard) + return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, types.DomainTypeStandard) } input := &ec2.DisassociateAddressInput{ @@ -174,7 +175,7 @@ func resourceEIPAssociationDelete(ctx context.Context, d *schema.ResourceData, m } log.Printf("[DEBUG] Deleting EC2 EIP Association: %s", d.Id()) - _, err := conn.DisassociateAddressWithContext(ctx, input) + _, err := conn.DisassociateAddress(ctx, input) if tfawserr.ErrCodeEquals(err, errCodeInvalidAssociationIDNotFound) { return diags diff --git a/internal/service/ec2/ec2_eip_association_test.go b/internal/service/ec2/ec2_eip_association_test.go index aab61648e83..893c799285f 100644 --- a/internal/service/ec2/ec2_eip_association_test.go +++ b/internal/service/ec2/ec2_eip_association_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/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" @@ -21,7 +21,7 @@ import ( func TestAccEC2EIPAssociation_basic(t *testing.T) { ctx := acctest.Context(t) - var a ec2.Address + var a types.Address resourceName := "aws_eip_association.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -48,7 +48,7 @@ func TestAccEC2EIPAssociation_basic(t *testing.T) { func TestAccEC2EIPAssociation_disappears(t *testing.T) { ctx := acctest.Context(t) - var a ec2.Address + var a types.Address resourceName := "aws_eip_association.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -72,7 +72,7 @@ func TestAccEC2EIPAssociation_disappears(t *testing.T) { func TestAccEC2EIPAssociation_instance(t *testing.T) { ctx := acctest.Context(t) - var a ec2.Address + var a types.Address resource1Name := "aws_eip_association.test1" resource2Name := "aws_eip_association.test2" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -96,7 +96,7 @@ func TestAccEC2EIPAssociation_instance(t *testing.T) { func TestAccEC2EIPAssociation_networkInterface(t *testing.T) { ctx := acctest.Context(t) - var a ec2.Address + var a types.Address resourceName := "aws_eip_association.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -123,7 +123,7 @@ func TestAccEC2EIPAssociation_networkInterface(t *testing.T) { func TestAccEC2EIPAssociation_spotInstance(t *testing.T) { ctx := acctest.Context(t) - var a ec2.Address + var a types.Address resourceName := "aws_eip_association.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) publicKey, _, err := sdkacctest.RandSSHKeyPair(acctest.DefaultEmailAddress) @@ -154,18 +154,14 @@ func TestAccEC2EIPAssociation_spotInstance(t *testing.T) { }) } -func testAccCheckEIPAssociationExists(ctx context.Context, n string, v *ec2.Address) resource.TestCheckFunc { +func testAccCheckEIPAssociationExists(ctx context.Context, n string, v *types.Address) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No EC2 EIP Association ID is set") - } - - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) output, err := tfec2.FindEIPByAssociationID(ctx, conn, rs.Primary.ID) @@ -181,7 +177,7 @@ func testAccCheckEIPAssociationExists(ctx context.Context, n string, v *ec2.Addr func testAccCheckEIPAssociationDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_eip_association" { From f344e941e8679482880fc9650fab19c2fc969540 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:47:40 -0400 Subject: [PATCH 08/25] r/aws_eip: Migrate to AWS SDK for Go v2. --- internal/service/ec2/ec2_eip.go | 69 ++++++++++++++-------------- internal/service/ec2/ec2_eip_test.go | 52 ++++++++++----------- 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index b67079117a4..00b2dfe6598 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -11,13 +11,14 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" "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" @@ -77,12 +78,12 @@ func resourceEIP() *schema.Resource { Optional: true, }, "domain": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(ec2.DomainType_Values(), false), - ConflictsWith: []string{"vpc"}, + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ValidateDiagFunc: enum.Validate[types.DomainType](), + ConflictsWith: []string{"vpc"}, }, "instance": { Type: schema.TypeString, @@ -138,10 +139,10 @@ func resourceEIP() *schema.Resource { func resourceEIPCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) input := &ec2.AllocateAddressInput{ - TagSpecifications: getTagSpecificationsIn(ctx, ec2.ResourceTypeElasticIp), + TagSpecifications: getTagSpecificationsInV2(ctx, types.ResourceTypeElasticIp), } if v, ok := d.GetOk("address"); ok { @@ -153,11 +154,11 @@ func resourceEIPCreate(ctx context.Context, d *schema.ResourceData, meta interfa } if v := d.Get("domain"); v != nil && v.(string) != "" { - input.Domain = aws.String(v.(string)) + input.Domain = types.DomainType(v.(string)) } if v := d.Get("vpc"); v != nil && v.(bool) { - input.Domain = aws.String(ec2.DomainTypeVpc) + input.Domain = types.DomainTypeVpc } if v, ok := d.GetOk("network_border_group"); ok { @@ -168,13 +169,13 @@ func resourceEIPCreate(ctx context.Context, d *schema.ResourceData, meta interfa input.PublicIpv4Pool = aws.String(v.(string)) } - output, err := conn.AllocateAddressWithContext(ctx, input) + output, err := conn.AllocateAddress(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating EC2 EIP: %s", err) } - d.SetId(aws.StringValue(output.AllocationId)) + d.SetId(aws.ToString(output.AllocationId)) _, err = tfresource.RetryWhenNotFound(ctx, d.Timeout(schema.TimeoutCreate), func() (interface{}, error) { return findEIPByAllocationID(ctx, conn, d.Id()) @@ -200,10 +201,10 @@ func resourceEIPCreate(ctx context.Context, d *schema.ResourceData, meta interfa func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) if !eipID(d.Id()).IsVPC() { - return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, ec2.DomainTypeStandard) + return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, types.DomainTypeStandard) } outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, ec2PropagationTimeout, func() (interface{}, error) { @@ -220,7 +221,7 @@ func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface return sdkdiag.AppendErrorf(diags, "reading EC2 EIP (%s): %s", d.Id(), err) } - address := outputRaw.(*ec2.Address) + address := outputRaw.(*types.Address) d.Set("allocation_id", address.AllocationId) d.Set("association_id", address.AssociationId) d.Set("carrier_ip", address.CarrierIp) @@ -232,29 +233,29 @@ func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface d.Set("network_interface", address.NetworkInterfaceId) d.Set("public_ipv4_pool", address.PublicIpv4Pool) d.Set("private_ip", address.PrivateIpAddress) - if v := aws.StringValue(address.PrivateIpAddress); v != "" { + if v := aws.ToString(address.PrivateIpAddress); v != "" { d.Set("private_dns", PrivateDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) } d.Set("public_ip", address.PublicIp) - if v := aws.StringValue(address.PublicIp); v != "" { + if v := aws.ToString(address.PublicIp); v != "" { d.Set("public_dns", PublicDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) } - d.Set("vpc", aws.StringValue(address.Domain) == ec2.DomainTypeVpc) + d.Set("vpc", address.Domain == types.DomainTypeVpc) // Force ID to be an Allocation ID if we're on a VPC. // This allows users to import the EIP based on the IP if they are in a VPC. - if aws.StringValue(address.Domain) == ec2.DomainTypeVpc && net.ParseIP(d.Id()) != nil { - d.SetId(aws.StringValue(address.AllocationId)) + if address.Domain == types.DomainTypeVpc && net.ParseIP(d.Id()) != nil { + d.SetId(aws.ToString(address.AllocationId)) } - setTagsOut(ctx, address.Tags) + setTagsOutV2(ctx, address.Tags) return diags } func resourceEIPUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) if d.HasChanges("associate_with_private_ip", "instance", "network_interface") { o, n := d.GetChange("instance") @@ -278,10 +279,10 @@ func resourceEIPUpdate(ctx context.Context, d *schema.ResourceData, meta interfa func resourceEIPDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) + conn := meta.(*conns.AWSClient).EC2Client(ctx) if !eipID(d.Id()).IsVPC() { - return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, ec2.DomainTypeStandard) + return sdkdiag.AppendErrorf(diags, `with the retirement of EC2-Classic %s domain EC2 EIPs are no longer supported`, types.DomainTypeStandard) } // If we are attached to an instance or interface, detach first. @@ -300,7 +301,7 @@ func resourceEIPDelete(ctx context.Context, d *schema.ResourceData, meta interfa } log.Printf("[INFO] Deleting EC2 EIP: %s", d.Id()) - _, err := conn.ReleaseAddressWithContext(ctx, input) + _, err := conn.ReleaseAddress(ctx, input) if tfawserr.ErrCodeEquals(err, errCodeInvalidAllocationIDNotFound) { return diags @@ -320,7 +321,7 @@ func (id eipID) IsVPC() bool { return strings.HasPrefix(string(id), "eipalloc-") } -func associateEIP(ctx context.Context, conn *ec2.EC2, allocationID, instanceID, networkInterfaceID, privateIPAddress string) error { +func associateEIP(ctx context.Context, conn *ec2.Client, allocationID, instanceID, networkInterfaceID, privateIPAddress string) error { input := &ec2.AssociateAddressInput{ AllocationId: aws.String(allocationID), } @@ -337,7 +338,7 @@ func associateEIP(ctx context.Context, conn *ec2.EC2, allocationID, instanceID, input.PrivateIpAddress = aws.String(privateIPAddress) } - output, err := conn.AssociateAddressWithContext(ctx, input) + output, err := conn.AssociateAddress(ctx, input) if err != nil { return fmt.Errorf("associating EC2 EIP (%s): %w", allocationID, err) @@ -345,7 +346,7 @@ func associateEIP(ctx context.Context, conn *ec2.EC2, allocationID, instanceID, _, err = tfresource.RetryWhen(ctx, ec2PropagationTimeout, func() (interface{}, error) { - return findEIPByAssociationID(ctx, conn, aws.StringValue(output.AssociationId)) + return findEIPByAssociationID(ctx, conn, aws.ToString(output.AssociationId)) }, func(err error) (bool, error) { if tfresource.NotFound(err) { @@ -368,7 +369,7 @@ func associateEIP(ctx context.Context, conn *ec2.EC2, allocationID, instanceID, return nil } -func disassociateEIP(ctx context.Context, conn *ec2.EC2, associationID string) error { +func disassociateEIP(ctx context.Context, conn *ec2.Client, associationID string) error { if associationID == "" { return nil } @@ -377,7 +378,7 @@ func disassociateEIP(ctx context.Context, conn *ec2.EC2, associationID string) e AssociationId: aws.String(associationID), } - _, err := conn.DisassociateAddressWithContext(ctx, input) + _, err := conn.DisassociateAddress(ctx, input) if tfawserr.ErrCodeEquals(err, errCodeInvalidAssociationIDNotFound) { return nil diff --git a/internal/service/ec2/ec2_eip_test.go b/internal/service/ec2/ec2_eip_test.go index 02a56a1c42e..5b5b9037185 100644 --- a/internal/service/ec2/ec2_eip_test.go +++ b/internal/service/ec2/ec2_eip_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/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" @@ -23,7 +23,7 @@ import ( func TestAccEC2EIP_basic(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" resource.ParallelTest(t, resource.TestCase{ @@ -52,7 +52,7 @@ func TestAccEC2EIP_basic(t *testing.T) { func TestAccEC2EIP_disappears(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" resource.ParallelTest(t, resource.TestCase{ @@ -75,7 +75,7 @@ func TestAccEC2EIP_disappears(t *testing.T) { func TestAccEC2EIP_migrateVPCToDomain(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" resource.ParallelTest(t, resource.TestCase{ @@ -109,7 +109,7 @@ func TestAccEC2EIP_migrateVPCToDomain(t *testing.T) { func TestAccEC2EIP_noVPC(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" resource.ParallelTest(t, resource.TestCase{ @@ -138,7 +138,7 @@ func TestAccEC2EIP_noVPC(t *testing.T) { func TestAccEC2EIP_tags(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" resource.ParallelTest(t, resource.TestCase{ @@ -183,7 +183,7 @@ func TestAccEC2EIP_tags(t *testing.T) { func TestAccEC2EIP_instance(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address instanceResourceName := "aws_instance.test" resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -215,7 +215,7 @@ func TestAccEC2EIP_instance(t *testing.T) { // https://github.com/hashicorp/terraform-provider-aws/issues/42) func TestAccEC2EIP_Instance_reassociate(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address instanceResourceName := "aws_instance.test" resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -249,7 +249,7 @@ func TestAccEC2EIP_Instance_reassociate(t *testing.T) { // associated Private EIPs of two instances func TestAccEC2EIP_Instance_associatedUserPrivateIP(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address instance1ResourceName := "aws_instance.test.1" instance2ResourceName := "aws_instance.test.0" resourceName := "aws_eip.test" @@ -291,7 +291,7 @@ func TestAccEC2EIP_Instance_associatedUserPrivateIP(t *testing.T) { func TestAccEC2EIP_Instance_notAssociated(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address instanceResourceName := "aws_instance.test" resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -331,7 +331,7 @@ func TestAccEC2EIP_Instance_notAssociated(t *testing.T) { func TestAccEC2EIP_networkInterface(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -362,7 +362,7 @@ func TestAccEC2EIP_networkInterface(t *testing.T) { func TestAccEC2EIP_NetworkInterface_twoEIPsOneInterface(t *testing.T) { ctx := acctest.Context(t) - var one, two ec2.Address + var one, two types.Address resource1Name := "aws_eip.test.0" resource2Name := "aws_eip.test.1" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -391,7 +391,7 @@ func TestAccEC2EIP_NetworkInterface_twoEIPsOneInterface(t *testing.T) { func TestAccEC2EIP_association(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address instanceResourceName := "aws_instance.test" eniResourceName := "aws_network_interface.test" resourceName := "aws_eip.test" @@ -439,7 +439,7 @@ func TestAccEC2EIP_association(t *testing.T) { func TestAccEC2EIP_PublicIPv4Pool_default(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -474,7 +474,7 @@ func TestAccEC2EIP_PublicIPv4Pool_custom(t *testing.T) { t.Skipf("Environment variable %s is not set", key) } - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -503,7 +503,7 @@ func TestAccEC2EIP_PublicIPv4Pool_custom(t *testing.T) { func TestAccEC2EIP_customerOwnedIPv4Pool(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -532,7 +532,7 @@ func TestAccEC2EIP_customerOwnedIPv4Pool(t *testing.T) { func TestAccEC2EIP_networkBorderGroup(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -562,7 +562,7 @@ func TestAccEC2EIP_networkBorderGroup(t *testing.T) { func TestAccEC2EIP_carrierIP(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -592,7 +592,7 @@ func TestAccEC2EIP_carrierIP(t *testing.T) { func TestAccEC2EIP_BYOIPAddress_default(t *testing.T) { ctx := acctest.Context(t) - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -621,7 +621,7 @@ func TestAccEC2EIP_BYOIPAddress_custom(t *testing.T) { t.Skipf("Environment variable %s is not set", key) } - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -656,7 +656,7 @@ func TestAccEC2EIP_BYOIPAddress_customWithPublicIPv4Pool(t *testing.T) { t.Skipf("Environment variable %s is not set", key) } - var conf ec2.Address + var conf types.Address resourceName := "aws_eip.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -678,18 +678,14 @@ func TestAccEC2EIP_BYOIPAddress_customWithPublicIPv4Pool(t *testing.T) { }) } -func testAccCheckEIPExists(ctx context.Context, n string, v *ec2.Address) resource.TestCheckFunc { +func testAccCheckEIPExists(ctx context.Context, n string, v *types.Address) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No EC2 EIP ID is set") - } - - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) output, err := tfec2.FindEIPByAllocationID(ctx, conn, rs.Primary.ID) @@ -705,7 +701,7 @@ func testAccCheckEIPExists(ctx context.Context, n string, v *ec2.Address) resour func testAccCheckEIPDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_eip" { From 46679e370cdcf4b94c6a3d5f354e64275684d5a0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 08:56:18 -0400 Subject: [PATCH 09/25] Move 'RegionalPublicDNSSuffix'. --- internal/service/ec2/ec2_eip.go | 8 ++++++++ internal/service/ec2/vpc_default_vpc_dhcp_options.go | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index 00b2dfe6598..26fdd00d011 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -402,3 +402,11 @@ func PrivateDNSNameForIP(ctx context.Context, client *conns.AWSClient, ip string func PublicDNSNameForIP(ctx context.Context, client *conns.AWSClient, ip string) string { return client.PartitionHostname(ctx, fmt.Sprintf("ec2-%s.%s", ConvertIPToDashIP(ip), RegionalPublicDNSSuffix(client.Region))) } + +func RegionalPublicDNSSuffix(region string) string { + if region == names.USEast1RegionID { + return "compute-1" + } + + return fmt.Sprintf("%s.compute", region) +} diff --git a/internal/service/ec2/vpc_default_vpc_dhcp_options.go b/internal/service/ec2/vpc_default_vpc_dhcp_options.go index c942d5f4d4d..d60a095794f 100644 --- a/internal/service/ec2/vpc_default_vpc_dhcp_options.go +++ b/internal/service/ec2/vpc_default_vpc_dhcp_options.go @@ -120,11 +120,3 @@ func RegionalPrivateDNSSuffix(region string) string { return fmt.Sprintf("%s.compute.internal", region) } - -func RegionalPublicDNSSuffix(region string) string { - if region == endpoints.UsEast1RegionID { - return "compute-1" - } - - return fmt.Sprintf("%s.compute", region) -} From c888012edb0cb1bca22db9c0bbfd19c85810b90f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 09:23:03 -0400 Subject: [PATCH 10/25] Add 'EC2PrivateDNSNameForIP' and 'EC2PublicDNSNameForIP' to 'AWSClient'. --- internal/conns/awsclient.go | 35 +++++++++++++ internal/conns/awsclient_test.go | 88 ++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/internal/conns/awsclient.go b/internal/conns/awsclient.go index e993e6bbb11..e9ce0525daf 100644 --- a/internal/conns/awsclient.go +++ b/internal/conns/awsclient.go @@ -9,6 +9,7 @@ import ( "maps" "net/http" "os" + "strings" "sync" aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" @@ -250,6 +251,40 @@ func (c *AWSClient) ReverseDNSPrefix(ctx context.Context) string { return names.ReverseDNS(c.DNSSuffix(ctx)) } +// EC2RegionalPrivateDNSSuffix returns the EC2 private DNS suffix for the configured AWS Region. +func (c *AWSClient) EC2RegionalPrivateDNSSuffix(context.Context) string { + region := c.Region + if region == names.USEast1RegionID { + return "ec2.internal" + } + + return fmt.Sprintf("%s.compute.internal", region) +} + +// EC2RegionalPublicDNSSuffix returns the EC2 public DNS suffix for the configured AWS Region. +func (c *AWSClient) EC2RegionalPublicDNSSuffix(context.Context) string { + region := c.Region + if region == names.USEast1RegionID { + return "compute-1" + } + + return fmt.Sprintf("%s.compute", region) +} + +// EC2PrivateDNSNameForIP returns a EC2 private DNS name in the configured AWS Region. +func (c *AWSClient) EC2PrivateDNSNameForIP(ctx context.Context, ip string) string { + return fmt.Sprintf("ip-%s.%s", convertIPToDashIP(ip), c.EC2RegionalPrivateDNSSuffix(ctx)) +} + +// EC2PublicDNSNameForIP returns a EC2 public DNS name in the configured AWS Region. +func (c *AWSClient) EC2PublicDNSNameForIP(ctx context.Context, ip string) string { + return c.PartitionHostname(ctx, fmt.Sprintf("ec2-%s.%s", convertIPToDashIP(ip), c.EC2RegionalPublicDNSSuffix(ctx))) +} + +func convertIPToDashIP(ip string) string { + return strings.Replace(ip, ".", "-", -1) +} + // apiClientConfig returns the AWS API client configuration parameters for the specified service. func (c *AWSClient) apiClientConfig(ctx context.Context, servicePackageName string) map[string]any { m := map[string]any{ diff --git a/internal/conns/awsclient_test.go b/internal/conns/awsclient_test.go index 4026675c4af..e69694f9897 100644 --- a/internal/conns/awsclient_test.go +++ b/internal/conns/awsclient_test.go @@ -93,3 +93,91 @@ func TestAWSClientRegionalHostname(t *testing.T) { // nosemgrep:ci.aws-in-func-n }) } } + +func TestAWSClientEC2PrivateDNSNameForIP(t *testing.T) { // nosemgrep:ci.aws-in-func-name + t.Parallel() + + ctx := context.TODO() + testCases := []struct { + Name string + AWSClient *AWSClient + IP string + Expected string + }{ + { + Name: "us-west-2", + AWSClient: &AWSClient{ + dnsSuffix: "amazonaws.com", + Region: "us-west-2", //lintignore:AWSAT003 + }, + IP: "10.20.30.40", + Expected: "ip-10-20-30-40.us-west-2.compute.internal", //lintignore:AWSAT003 + }, + { + Name: "us-east-1", + AWSClient: &AWSClient{ + dnsSuffix: "amazonaws.com", + Region: "us-east-1", //lintignore:AWSAT003 + }, + IP: "10.20.30.40", + Expected: "ip-10-20-30-40.ec2.internal", + }, + } + + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.Name, func(t *testing.T) { + t.Parallel() + + got := testCase.AWSClient.EC2PrivateDNSNameForIP(ctx, testCase.IP) + + if got != testCase.Expected { + t.Errorf("got %s, expected %s", got, testCase.Expected) + } + }) + } +} + +func TestAWSClientEC2PublicDNSNameForIP(t *testing.T) { // nosemgrep:ci.aws-in-func-name + t.Parallel() + + ctx := context.TODO() + testCases := []struct { + Name string + AWSClient *AWSClient + IP string + Expected string + }{ + { + Name: "us-west-2", + AWSClient: &AWSClient{ + dnsSuffix: "amazonaws.com", + Region: "us-west-2", //lintignore:AWSAT003 + }, + IP: "10.20.30.40", + Expected: "ec2-10-20-30-40.us-west-2.compute.amazonaws.com", //lintignore:AWSAT003 + }, + { + Name: "us-east-1", + AWSClient: &AWSClient{ + dnsSuffix: "amazonaws.com", + Region: "us-east-1", //lintignore:AWSAT003 + }, + IP: "10.20.30.40", + Expected: "ec2-10-20-30-40.compute-1.amazonaws.com", + }, + } + + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.Name, func(t *testing.T) { + t.Parallel() + + got := testCase.AWSClient.EC2PublicDNSNameForIP(ctx, testCase.IP) + + if got != testCase.Expected { + t.Errorf("got %s, expected %s", got, testCase.Expected) + } + }) + } +} From 92946dfe47b142f31bcbef902eb47cd59ea9f3e8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 09:26:46 -0400 Subject: [PATCH 11/25] Use 'AWSClient.EC2RegionalPrivateDNSSuffix'. --- internal/service/ec2/sweep.go | 2 +- internal/service/ec2/vpc_default_vpc_dhcp_options.go | 12 +----------- .../service/ec2/vpc_default_vpc_dhcp_options_test.go | 5 ++--- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/internal/service/ec2/sweep.go b/internal/service/ec2/sweep.go index 09343df2e97..7696673bd66 100644 --- a/internal/service/ec2/sweep.go +++ b/internal/service/ec2/sweep.go @@ -2257,7 +2257,7 @@ func sweepVPCDHCPOptions(region string) error { continue } - if aws.StringValue(v.Values[0].Value) == RegionalPrivateDNSSuffix(region) { + if aws.StringValue(v.Values[0].Value) == client.EC2RegionalPrivateDNSSuffix(ctx) { defaultDomainNameFound = true } } else if aws.StringValue(v.Key) == "domain-name-servers" { diff --git a/internal/service/ec2/vpc_default_vpc_dhcp_options.go b/internal/service/ec2/vpc_default_vpc_dhcp_options.go index d60a095794f..3c7f72cccf7 100644 --- a/internal/service/ec2/vpc_default_vpc_dhcp_options.go +++ b/internal/service/ec2/vpc_default_vpc_dhcp_options.go @@ -5,10 +5,8 @@ package ec2 import ( "context" - "fmt" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -91,7 +89,7 @@ func resourceDefaultVPCDHCPOptionsCreate(ctx context.Context, d *schema.Resource input.Filters = append(input.Filters, newFilter("key", []string{"domain-name"}), - newFilter("value", []string{RegionalPrivateDNSSuffix(meta.(*conns.AWSClient).Region)}), + newFilter("value", []string{meta.(*conns.AWSClient).EC2RegionalPrivateDNSSuffix(ctx)}), newFilter("key", []string{"domain-name-servers"}), newFilter("value", []string{"AmazonProvidedDNS"}), ) @@ -112,11 +110,3 @@ func resourceDefaultVPCDHCPOptionsCreate(ctx context.Context, d *schema.Resource return append(diags, resourceVPCDHCPOptionsUpdate(ctx, d, meta)...) } - -func RegionalPrivateDNSSuffix(region string) string { - if region == endpoints.UsEast1RegionID { - return "ec2.internal" - } - - return fmt.Sprintf("%s.compute.internal", region) -} diff --git a/internal/service/ec2/vpc_default_vpc_dhcp_options_test.go b/internal/service/ec2/vpc_default_vpc_dhcp_options_test.go index d8256fca772..7ed3d215eeb 100644 --- a/internal/service/ec2/vpc_default_vpc_dhcp_options_test.go +++ b/internal/service/ec2/vpc_default_vpc_dhcp_options_test.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/acctest" - tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -42,7 +41,7 @@ func testAccDefaultVPCDHCPOptions_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckDHCPOptionsExists(ctx, resourceName, &d), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexache.MustCompile(`dhcp-options/dopt-.+`)), - resource.TestCheckResourceAttr(resourceName, "domain_name", tfec2.RegionalPrivateDNSSuffix(acctest.Region())), + resource.TestCheckResourceAttrSet(resourceName, "domain_name"), resource.TestCheckResourceAttr(resourceName, "domain_name_servers", "AmazonProvidedDNS"), acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -69,7 +68,7 @@ func testAccDefaultVPCDHCPOptions_owner(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckDHCPOptionsExists(ctx, resourceName, &d), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexache.MustCompile(`dhcp-options/dopt-.+`)), - resource.TestCheckResourceAttr(resourceName, "domain_name", tfec2.RegionalPrivateDNSSuffix(acctest.Region())), + resource.TestCheckResourceAttrSet(resourceName, "domain_name"), resource.TestCheckResourceAttr(resourceName, "domain_name_servers", "AmazonProvidedDNS"), acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), From d72663b93e8ee1291cdeb5d0ab7bb1fb7ccd2f99 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 09:32:59 -0400 Subject: [PATCH 12/25] Use 'AWSClient.EC2PrivateDNSNameForIP' and 'AWSClient.EC2PublicDNSNameForIP'. --- internal/service/ec2/ec2_eip.go | 24 ++------------------ internal/service/ec2/ec2_eip_data_source.go | 4 ++-- internal/service/ec2/ec2_eip_test.go | 25 +++++++-------------- 3 files changed, 12 insertions(+), 41 deletions(-) diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index 26fdd00d011..1b528a71343 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -234,11 +234,11 @@ func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface d.Set("public_ipv4_pool", address.PublicIpv4Pool) d.Set("private_ip", address.PrivateIpAddress) if v := aws.ToString(address.PrivateIpAddress); v != "" { - d.Set("private_dns", PrivateDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) + d.Set("private_dns", meta.(*conns.AWSClient).EC2PrivateDNSNameForIP(ctx, v)) } d.Set("public_ip", address.PublicIp) if v := aws.ToString(address.PublicIp); v != "" { - d.Set("public_dns", PublicDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) + d.Set("public_dns", meta.(*conns.AWSClient).EC2PublicDNSNameForIP(ctx, v)) } d.Set("vpc", address.Domain == types.DomainTypeVpc) @@ -390,23 +390,3 @@ func disassociateEIP(ctx context.Context, conn *ec2.Client, associationID string return nil } - -func ConvertIPToDashIP(ip string) string { - return strings.Replace(ip, ".", "-", -1) -} - -func PrivateDNSNameForIP(ctx context.Context, client *conns.AWSClient, ip string) string { - return fmt.Sprintf("ip-%s.%s", ConvertIPToDashIP(ip), RegionalPrivateDNSSuffix(client.Region)) -} - -func PublicDNSNameForIP(ctx context.Context, client *conns.AWSClient, ip string) string { - return client.PartitionHostname(ctx, fmt.Sprintf("ec2-%s.%s", ConvertIPToDashIP(ip), RegionalPublicDNSSuffix(client.Region))) -} - -func RegionalPublicDNSSuffix(region string) string { - if region == names.USEast1RegionID { - return "compute-1" - } - - return fmt.Sprintf("%s.compute", region) -} diff --git a/internal/service/ec2/ec2_eip_data_source.go b/internal/service/ec2/ec2_eip_data_source.go index 77416a00b71..195aa81e0fa 100644 --- a/internal/service/ec2/ec2_eip_data_source.go +++ b/internal/service/ec2/ec2_eip_data_source.go @@ -143,11 +143,11 @@ func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interfa d.Set("public_ipv4_pool", eip.PublicIpv4Pool) d.Set("private_ip", eip.PrivateIpAddress) if v := aws.ToString(eip.PrivateIpAddress); v != "" { - d.Set("private_dns", PrivateDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) + d.Set("private_dns", meta.(*conns.AWSClient).EC2PrivateDNSNameForIP(ctx, v)) } d.Set("public_ip", eip.PublicIp) if v := aws.ToString(eip.PublicIp); v != "" { - d.Set("public_dns", PublicDNSNameForIP(ctx, meta.(*conns.AWSClient), v)) + d.Set("public_dns", meta.(*conns.AWSClient).EC2PublicDNSNameForIP(ctx, v)) } setTagsOutV2(ctx, eip.Tags) diff --git a/internal/service/ec2/ec2_eip_test.go b/internal/service/ec2/ec2_eip_test.go index 5b5b9037185..f3da83a4fe9 100644 --- a/internal/service/ec2/ec2_eip_test.go +++ b/internal/service/ec2/ec2_eip_test.go @@ -38,7 +38,7 @@ func TestAccEC2EIP_basic(t *testing.T) { testAccCheckEIPExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "domain", "vpc"), resource.TestCheckResourceAttrSet(resourceName, "public_ip"), - testAccCheckEIPPublicDNS(resourceName), + testAccCheckEIPPublicDNS(ctx, resourceName), ), }, { @@ -95,7 +95,7 @@ func TestAccEC2EIP_migrateVPCToDomain(t *testing.T) { testAccCheckEIPExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "domain", "vpc"), resource.TestCheckResourceAttrSet(resourceName, "public_ip"), - testAccCheckEIPPublicDNS(resourceName), + testAccCheckEIPPublicDNS(ctx, resourceName), ), }, { @@ -124,7 +124,7 @@ func TestAccEC2EIP_noVPC(t *testing.T) { testAccCheckEIPExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "domain", "vpc"), resource.TestCheckResourceAttrSet(resourceName, "public_ip"), - testAccCheckEIPPublicDNS(resourceName), + testAccCheckEIPPublicDNS(ctx, resourceName), ), }, { @@ -345,7 +345,7 @@ func TestAccEC2EIP_networkInterface(t *testing.T) { Config: testAccEIPConfig_networkInterface(rName), Check: resource.ComposeTestCheckFunc( testAccCheckEIPExists(ctx, resourceName, &conf), - testAccCheckEIPPrivateDNS(resourceName), + testAccCheckEIPPrivateDNS(ctx, resourceName), resource.TestCheckResourceAttrSet(resourceName, "allocation_id"), resource.TestCheckResourceAttrSet(resourceName, "association_id"), resource.TestCheckResourceAttrSet(resourceName, "public_ip"), @@ -725,7 +725,7 @@ func testAccCheckEIPDestroy(ctx context.Context) resource.TestCheckFunc { } } -func testAccCheckEIPPrivateDNS(resourceName string) resource.TestCheckFunc { +func testAccCheckEIPPrivateDNS(ctx context.Context, resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -733,11 +733,7 @@ func testAccCheckEIPPrivateDNS(resourceName string) resource.TestCheckFunc { } privateDNS := rs.Primary.Attributes["private_dns"] - expectedPrivateDNS := fmt.Sprintf( - "ip-%s.%s", - tfec2.ConvertIPToDashIP(rs.Primary.Attributes["private_ip"]), - tfec2.RegionalPrivateDNSSuffix(acctest.Region()), - ) + expectedPrivateDNS := acctest.Provider.Meta().(*conns.AWSClient).EC2PrivateDNSNameForIP(ctx, rs.Primary.Attributes["private_ip"]) if privateDNS != expectedPrivateDNS { return fmt.Errorf("expected private_dns value (%s), received: %s", expectedPrivateDNS, privateDNS) @@ -747,7 +743,7 @@ func testAccCheckEIPPrivateDNS(resourceName string) resource.TestCheckFunc { } } -func testAccCheckEIPPublicDNS(resourceName string) resource.TestCheckFunc { +func testAccCheckEIPPublicDNS(ctx context.Context, resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -755,12 +751,7 @@ func testAccCheckEIPPublicDNS(resourceName string) resource.TestCheckFunc { } publicDNS := rs.Primary.Attributes["public_dns"] - expectedPublicDNS := fmt.Sprintf( - "ec2-%s.%s.%s", - tfec2.ConvertIPToDashIP(rs.Primary.Attributes["public_ip"]), - tfec2.RegionalPublicDNSSuffix(acctest.Region()), - acctest.PartitionDNSSuffix(), - ) + expectedPublicDNS := acctest.Provider.Meta().(*conns.AWSClient).EC2PublicDNSNameForIP(ctx, rs.Primary.Attributes["public_ip"]) if publicDNS != expectedPublicDNS { return fmt.Errorf("expected public_dns value (%s), received: %s", expectedPublicDNS, publicDNS) From 39dec48dda971a0ee88ac7ca4eb1c1ccd80765e5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 10:41:01 -0400 Subject: [PATCH 13/25] Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCDefaultVPCDHCPOptions_serial\|TestAccEC2EIPAssociation_\|TestAccEC2EIPDataSource_\|TestAccEC2EIP_\|TestAccEC2EIPsDataSource_' PKG=ec2 ACCTEST_PARALLELISM=3 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go1.21.8 test ./internal/service/ec2/... -v -count 1 -parallel 3 -run=TestAccVPCDefaultVPCDHCPOptions_serial\|TestAccEC2EIPAssociation_\|TestAccEC2EIPDataSource_\|TestAccEC2EIP_\|TestAccEC2EIPsDataSource_ -timeout 360m === RUN TestAccEC2EIPAssociation_basic === PAUSE TestAccEC2EIPAssociation_basic === RUN TestAccEC2EIPAssociation_disappears === PAUSE TestAccEC2EIPAssociation_disappears === RUN TestAccEC2EIPAssociation_instance === PAUSE TestAccEC2EIPAssociation_instance === RUN TestAccEC2EIPAssociation_networkInterface === PAUSE TestAccEC2EIPAssociation_networkInterface === RUN TestAccEC2EIPAssociation_spotInstance === PAUSE TestAccEC2EIPAssociation_spotInstance === RUN TestAccEC2EIPDataSource_filter === PAUSE TestAccEC2EIPDataSource_filter === RUN TestAccEC2EIPDataSource_id === PAUSE TestAccEC2EIPDataSource_id === RUN TestAccEC2EIPDataSource_publicIP === PAUSE TestAccEC2EIPDataSource_publicIP === RUN TestAccEC2EIPDataSource_tags === PAUSE TestAccEC2EIPDataSource_tags === RUN TestAccEC2EIPDataSource_networkInterface === PAUSE TestAccEC2EIPDataSource_networkInterface === RUN TestAccEC2EIPDataSource_instance === PAUSE TestAccEC2EIPDataSource_instance === RUN TestAccEC2EIPDataSource_carrierIP === PAUSE TestAccEC2EIPDataSource_carrierIP === RUN TestAccEC2EIPDataSource_customerOwnedIPv4Pool === PAUSE TestAccEC2EIPDataSource_customerOwnedIPv4Pool === RUN TestAccEC2EIP_basic === PAUSE TestAccEC2EIP_basic === RUN TestAccEC2EIP_disappears === PAUSE TestAccEC2EIP_disappears === RUN TestAccEC2EIP_migrateVPCToDomain === PAUSE TestAccEC2EIP_migrateVPCToDomain === RUN TestAccEC2EIP_noVPC === PAUSE TestAccEC2EIP_noVPC === RUN TestAccEC2EIP_tags === PAUSE TestAccEC2EIP_tags === RUN TestAccEC2EIP_instance === PAUSE TestAccEC2EIP_instance === RUN TestAccEC2EIP_Instance_reassociate === PAUSE TestAccEC2EIP_Instance_reassociate === RUN TestAccEC2EIP_Instance_associatedUserPrivateIP === PAUSE TestAccEC2EIP_Instance_associatedUserPrivateIP === RUN TestAccEC2EIP_Instance_notAssociated === PAUSE TestAccEC2EIP_Instance_notAssociated === RUN TestAccEC2EIP_networkInterface === PAUSE TestAccEC2EIP_networkInterface === RUN TestAccEC2EIP_NetworkInterface_twoEIPsOneInterface === PAUSE TestAccEC2EIP_NetworkInterface_twoEIPsOneInterface === RUN TestAccEC2EIP_association === PAUSE TestAccEC2EIP_association === RUN TestAccEC2EIP_PublicIPv4Pool_default === PAUSE TestAccEC2EIP_PublicIPv4Pool_default === RUN TestAccEC2EIP_PublicIPv4Pool_custom ec2_eip_test.go:474: Environment variable AWS_EC2_EIP_PUBLIC_IPV4_POOL is not set --- SKIP: TestAccEC2EIP_PublicIPv4Pool_custom (0.00s) === RUN TestAccEC2EIP_customerOwnedIPv4Pool === PAUSE TestAccEC2EIP_customerOwnedIPv4Pool === RUN TestAccEC2EIP_networkBorderGroup === PAUSE TestAccEC2EIP_networkBorderGroup === RUN TestAccEC2EIP_carrierIP === PAUSE TestAccEC2EIP_carrierIP === RUN TestAccEC2EIP_BYOIPAddress_default === PAUSE TestAccEC2EIP_BYOIPAddress_default === RUN TestAccEC2EIP_BYOIPAddress_custom ec2_eip_test.go:621: Environment variable AWS_EC2_EIP_BYOIP_ADDRESS is not set --- SKIP: TestAccEC2EIP_BYOIPAddress_custom (0.00s) === RUN TestAccEC2EIP_BYOIPAddress_customWithPublicIPv4Pool ec2_eip_test.go:650: Environment variable AWS_EC2_EIP_BYOIP_ADDRESS is not set --- SKIP: TestAccEC2EIP_BYOIPAddress_customWithPublicIPv4Pool (0.00s) === RUN TestAccEC2EIPsDataSource_basic === PAUSE TestAccEC2EIPsDataSource_basic === RUN TestAccVPCDefaultVPCDHCPOptions_serial === PAUSE TestAccVPCDefaultVPCDHCPOptions_serial === CONT TestAccEC2EIPAssociation_basic === CONT TestAccEC2EIP_noVPC === CONT TestAccVPCDefaultVPCDHCPOptions_serial === RUN TestAccVPCDefaultVPCDHCPOptions_serial/v4.20.0_regression --- PASS: TestAccEC2EIP_noVPC (21.88s) === CONT TestAccEC2EIPsDataSource_basic --- PASS: TestAccEC2EIPsDataSource_basic (17.62s) === CONT TestAccEC2EIP_BYOIPAddress_default === RUN TestAccVPCDefaultVPCDHCPOptions_serial/basic --- PASS: TestAccEC2EIP_BYOIPAddress_default (17.53s) === CONT TestAccEC2EIP_carrierIP === RUN TestAccVPCDefaultVPCDHCPOptions_serial/owner --- PASS: TestAccEC2EIP_carrierIP (24.36s) === CONT TestAccEC2EIP_networkBorderGroup --- PASS: TestAccVPCDefaultVPCDHCPOptions_serial (84.35s) --- PASS: TestAccVPCDefaultVPCDHCPOptions_serial/v4.20.0_regression (51.16s) --- PASS: TestAccVPCDefaultVPCDHCPOptions_serial/basic (17.21s) --- PASS: TestAccVPCDefaultVPCDHCPOptions_serial/owner (15.98s) === CONT TestAccEC2EIP_customerOwnedIPv4Pool ec2_eip_test.go:511: skipping since no Outposts found --- SKIP: TestAccEC2EIP_customerOwnedIPv4Pool (0.44s) === CONT TestAccEC2EIP_PublicIPv4Pool_default --- PASS: TestAccEC2EIP_networkBorderGroup (21.83s) === CONT TestAccEC2EIP_association --- PASS: TestAccEC2EIP_PublicIPv4Pool_default (21.58s) === CONT TestAccEC2EIP_NetworkInterface_twoEIPsOneInterface --- PASS: TestAccEC2EIP_NetworkInterface_twoEIPsOneInterface (27.81s) === CONT TestAccEC2EIP_networkInterface --- PASS: TestAccEC2EIPAssociation_basic (148.26s) === CONT TestAccEC2EIP_Instance_notAssociated --- PASS: TestAccEC2EIP_networkInterface (31.03s) === CONT TestAccEC2EIP_Instance_associatedUserPrivateIP --- PASS: TestAccEC2EIP_association (175.77s) === CONT TestAccEC2EIP_Instance_reassociate --- PASS: TestAccEC2EIP_Instance_notAssociated (177.38s) === CONT TestAccEC2EIP_instance --- PASS: TestAccEC2EIP_Instance_associatedUserPrivateIP (190.10s) === CONT TestAccEC2EIP_tags --- PASS: TestAccEC2EIP_tags (45.63s) === CONT TestAccEC2EIPDataSource_tags --- PASS: TestAccEC2EIP_Instance_reassociate (136.43s) === CONT TestAccEC2EIP_migrateVPCToDomain --- PASS: TestAccEC2EIPDataSource_tags (17.50s) === CONT TestAccEC2EIP_disappears --- PASS: TestAccEC2EIP_disappears (18.54s) === CONT TestAccEC2EIP_basic --- PASS: TestAccEC2EIP_instance (131.28s) === CONT TestAccEC2EIPDataSource_customerOwnedIPv4Pool ec2_eip_data_source_test.go:186: skipping since no Outposts found --- SKIP: TestAccEC2EIPDataSource_customerOwnedIPv4Pool (0.37s) === CONT TestAccEC2EIPDataSource_carrierIP --- PASS: TestAccEC2EIP_basic (21.71s) === CONT TestAccEC2EIPDataSource_instance --- PASS: TestAccEC2EIPDataSource_carrierIP (20.76s) === CONT TestAccEC2EIPDataSource_networkInterface --- PASS: TestAccEC2EIP_migrateVPCToDomain (63.88s) === CONT TestAccEC2EIPAssociation_spotInstance --- PASS: TestAccEC2EIPDataSource_networkInterface (27.59s) === CONT TestAccEC2EIPDataSource_publicIP --- PASS: TestAccEC2EIPDataSource_publicIP (19.00s) === CONT TestAccEC2EIPDataSource_id --- PASS: TestAccEC2EIPDataSource_id (17.72s) === CONT TestAccEC2EIPDataSource_filter --- PASS: TestAccEC2EIPDataSource_filter (16.74s) === CONT TestAccEC2EIPAssociation_instance --- PASS: TestAccEC2EIPDataSource_instance (117.54s) === CONT TestAccEC2EIPAssociation_networkInterface --- PASS: TestAccEC2EIPAssociation_networkInterface (30.17s) === CONT TestAccEC2EIPAssociation_disappears --- PASS: TestAccEC2EIPAssociation_spotInstance (134.16s) --- PASS: TestAccEC2EIPAssociation_instance (116.03s) --- PASS: TestAccEC2EIPAssociation_disappears (83.65s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 701.826s From 9ca4c7763e66cf21cee77a617f6b2f586c7f5588 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 12:02:45 -0400 Subject: [PATCH 14/25] aws_eip: Add 'domain_name' attribute. --- .changelog/#####.txt | 7 +++ internal/sdkv2/suppress.go | 16 ++++++ internal/service/ec2/ec2_eip.go | 17 +++++++ internal/service/ec2/ec2_eip_data_source.go | 17 +++++++ .../service/ec2/ec2_eip_data_source_test.go | 1 + internal/service/ec2/find.go | 49 +++++++++++++++++++ .../fsx/ontap_storage_virtual_machine.go | 3 +- internal/verify/diff.go | 7 --- website/docs/d/eip.html.markdown | 7 +-- website/docs/r/eip.html.markdown | 1 + 10 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 .changelog/#####.txt create mode 100644 internal/sdkv2/suppress.go diff --git a/.changelog/#####.txt b/.changelog/#####.txt new file mode 100644 index 00000000000..cdb48e36dcc --- /dev/null +++ b/.changelog/#####.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +data-source/aws_eip: Add `domain_name` attribute +``` + +```release-note:enhancement +resource/aws_eip: Add `domain_name` argument +``` \ No newline at end of file diff --git a/internal/sdkv2/suppress.go b/internal/sdkv2/suppress.go new file mode 100644 index 00000000000..97b1a813a86 --- /dev/null +++ b/internal/sdkv2/suppress.go @@ -0,0 +1,16 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package sdkv2 + +import ( + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// SuppressEquivalentStringCaseInsensitive provides custom difference suppression +// for strings that are equal under case-insensitivity. +func SuppressEquivalentStringCaseInsensitive(k, old, new string, d *schema.ResourceData) bool { + return strings.EqualFold(old, new) +} diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index 1b528a71343..c29d00f130d 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" 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" @@ -85,6 +86,11 @@ func resourceEIP() *schema.Resource { ValidateDiagFunc: enum.Validate[types.DomainType](), ConflictsWith: []string{"vpc"}, }, + "domain_name": { + Type: schema.TypeString, + Computed: true, + DiffSuppressFunc: sdkv2.SuppressEquivalentStringCaseInsensitive, + }, "instance": { Type: schema.TypeString, Optional: true, @@ -248,6 +254,17 @@ func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface d.SetId(aws.ToString(address.AllocationId)) } + addressAttr, err := findEIPDomainNameAttributeByAllocationID(ctx, conn, d.Id()) + + switch { + case err == nil: + d.Set("domain_name", strings.TrimSuffix(aws.ToString(addressAttr.PtrRecord), ".")) + case tfresource.NotFound(err): + d.Set("domain_name", nil) + default: + return sdkdiag.AppendErrorf(diags, "reading EC2 EIP (%s) domain name attribute: %s", d.Id(), err) + } + setTagsOutV2(ctx, address.Tags) return diags diff --git a/internal/service/ec2/ec2_eip_data_source.go b/internal/service/ec2/ec2_eip_data_source.go index 195aa81e0fa..c6ff1a6d5a6 100644 --- a/internal/service/ec2/ec2_eip_data_source.go +++ b/internal/service/ec2/ec2_eip_data_source.go @@ -5,6 +5,7 @@ package ec2 import ( "context" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -50,6 +51,10 @@ func dataSourceEIP() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "domain_name": { + Type: schema.TypeString, + Computed: true, + }, "filter": customFiltersSchema(), "id": { Type: schema.TypeString, @@ -129,8 +134,20 @@ func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interfa if eip.Domain == types.DomainTypeVpc { d.SetId(aws.ToString(eip.AllocationId)) + + addressAttr, err := findEIPDomainNameAttributeByAllocationID(ctx, conn, d.Id()) + + switch { + case err == nil: + d.Set("domain_name", strings.TrimSuffix(aws.ToString(addressAttr.PtrRecord), ".")) + case tfresource.NotFound(err): + d.Set("domain_name", nil) + default: + return sdkdiag.AppendErrorf(diags, "reading EC2 EIP (%s) domain name attribute: %s", d.Id(), err) + } } else { d.SetId(aws.ToString(eip.PublicIp)) + d.Set("domain_name", nil) } d.Set("association_id", eip.AssociationId) d.Set("carrier_ip", eip.CarrierIp) diff --git a/internal/service/ec2/ec2_eip_data_source_test.go b/internal/service/ec2/ec2_eip_data_source_test.go index 40f8b6bdcdd..4374bb60c1e 100644 --- a/internal/service/ec2/ec2_eip_data_source_test.go +++ b/internal/service/ec2/ec2_eip_data_source_test.go @@ -27,6 +27,7 @@ func TestAccEC2EIPDataSource_filter(t *testing.T) { { Config: testAccEIPDataSourceConfig_filter(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "domain_name", resourceName, "domain_name"), resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), resource.TestCheckResourceAttrPair(dataSourceName, "public_dns", resourceName, "public_dns"), resource.TestCheckResourceAttrPair(dataSourceName, "public_ip", resourceName, "public_ip"), diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index e41407484ad..2b5bd3ed882 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -713,6 +713,55 @@ func findEIPByAssociationID(ctx context.Context, conn *ec2_sdkv2.Client, id stri return output, nil } +func findEIPAttributes(ctx context.Context, conn *ec2_sdkv2.Client, input *ec2_sdkv2.DescribeAddressesAttributeInput) ([]awstypes.AddressAttribute, error) { + var output []awstypes.AddressAttribute + + pages := ec2_sdkv2.NewDescribeAddressesAttributePaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if err != nil { + return nil, err + } + + output = append(output, page.Addresses...) + } + + return output, nil +} + +func findEIPAttribute(ctx context.Context, conn *ec2_sdkv2.Client, input *ec2_sdkv2.DescribeAddressesAttributeInput) (*awstypes.AddressAttribute, error) { + output, err := findEIPAttributes(ctx, conn, input) + + if err != nil { + return nil, err + } + + return tfresource.AssertSingleValueResult(output) +} + +func findEIPDomainNameAttributeByAllocationID(ctx context.Context, conn *ec2_sdkv2.Client, id string) (*awstypes.AddressAttribute, error) { + input := &ec2_sdkv2.DescribeAddressesAttributeInput{ + AllocationIds: []string{id}, + Attribute: awstypes.AddressAttributeNameDomainName, + } + + output, err := findEIPAttribute(ctx, conn, input) + + if err != nil { + return nil, err + } + + // Eventual consistency check. + if aws_sdkv2.ToString(output.AllocationId) != id { + return nil, &retry.NotFoundError{ + LastRequest: input, + } + } + + return output, nil +} + func FindHostByID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.Host, error) { input := &ec2.DescribeHostsInput{ HostIds: aws.StringSlice([]string{id}), diff --git a/internal/service/fsx/ontap_storage_virtual_machine.go b/internal/service/fsx/ontap_storage_virtual_machine.go index 26677d845a4..4eda033eee2 100644 --- a/internal/service/fsx/ontap_storage_virtual_machine.go +++ b/internal/service/fsx/ontap_storage_virtual_machine.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -65,7 +66,7 @@ func ResourceONTAPStorageVirtualMachine() *schema.Resource { "netbios_name": { Type: schema.TypeString, Optional: true, - DiffSuppressFunc: verify.SuppressEquivalentStringCaseInsensitive, + DiffSuppressFunc: sdkv2.SuppressEquivalentStringCaseInsensitive, ValidateFunc: validation.StringLenBetween(1, 15), }, "self_managed_active_directory_configuration": { diff --git a/internal/verify/diff.go b/internal/verify/diff.go index 776355f9004..0bc956a747d 100644 --- a/internal/verify/diff.go +++ b/internal/verify/diff.go @@ -6,7 +6,6 @@ package verify import ( "context" "fmt" - "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -104,12 +103,6 @@ func SetTagsDiff(ctx context.Context, diff *schema.ResourceDiff, meta interface{ return nil } -// SuppressEquivalentStringCaseInsensitive provides custom difference suppression -// for strings that are equal under case-insensitivity. -func SuppressEquivalentStringCaseInsensitive(k, old, new string, d *schema.ResourceData) bool { - return strings.EqualFold(old, new) -} - // SuppressEquivalentRoundedTime returns a difference suppression function that compares // two time value with the specified layout rounded to the specified duration. func SuppressEquivalentRoundedTime(layout string, d time.Duration) schema.SchemaDiffSuppressFunc { diff --git a/website/docs/d/eip.html.markdown b/website/docs/d/eip.html.markdown index f5e83274d2f..4e69eb2297c 100644 --- a/website/docs/d/eip.html.markdown +++ b/website/docs/d/eip.html.markdown @@ -65,7 +65,11 @@ Elastic IP whose data will be exported as attributes. This data source exports the following attributes in addition to the arguments above: * `association_id` - ID representing the association of the address with an instance in a VPC. +* `carrier_ip` - Carrier IP address. +* `customer_owned_ip` - Customer Owned IP. +* `customer_owned_ipv4_pool` - The ID of a Customer Owned IP Pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing) * `domain` - Whether the address is for use in EC2-Classic (standard) or in a VPC (vpc). +* `domain_name` - The DNS pointer (PTR) record for the IP address. * `id` - If VPC Elastic IP, the allocation identifier. If EC2-Classic Elastic IP, the public IP address. * `instance_id` - ID of the instance that the address is associated with (if any). * `network_interface_id` - The ID of the network interface. @@ -75,9 +79,6 @@ This data source exports the following attributes in addition to the arguments a * `public_ip` - Public IP address of Elastic IP. * `public_dns` - Public DNS associated with the Elastic IP address. * `public_ipv4_pool` - ID of an address pool. -* `carrier_ip` - Carrier IP address. -* `customer_owned_ipv4_pool` - The ID of a Customer Owned IP Pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing) -* `customer_owned_ip` - Customer Owned IP. * `tags` - Key-value map of tags associated with Elastic IP. ~> **Note:** The data source computes the `public_dns` and `private_dns` attributes according to the [VPC DNS Guide](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-hostnames) as they are not available with the EC2 API. diff --git a/website/docs/r/eip.html.markdown b/website/docs/r/eip.html.markdown index b99c7e38ef6..2df466eb524 100644 --- a/website/docs/r/eip.html.markdown +++ b/website/docs/r/eip.html.markdown @@ -101,6 +101,7 @@ This resource supports the following arguments: * `associate_with_private_ip` - (Optional) User-specified primary or secondary private IP address to associate with the Elastic IP address. If no private IP address is specified, the Elastic IP address is associated with the primary private IP address. * `customer_owned_ipv4_pool` - (Optional) ID of a customer-owned address pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing). * `domain` - Indicates if this EIP is for use in VPC (`vpc`). +* `domain_name` - The domain name for the IP address. * `instance` - (Optional) EC2 instance ID. * `network_border_group` - (Optional) Location from which the IP address is advertised. Use this parameter to limit the address to this location. * `network_interface` - (Optional) Network interface ID to associate with. From 7ebe305a9dc71d2de8be6f1b8c91014dec1a544c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 13:20:49 -0400 Subject: [PATCH 15/25] d/aws_eip: 'domain_name' -> 'ptr_record'. --- .changelog/#####.txt | 2 +- internal/service/ec2/ec2_eip.go | 2 +- internal/service/ec2/ec2_eip_data_source.go | 15 +++++++-------- internal/service/ec2/ec2_eip_data_source_test.go | 1 - website/docs/d/eip.html.markdown | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.changelog/#####.txt b/.changelog/#####.txt index cdb48e36dcc..7458017d809 100644 --- a/.changelog/#####.txt +++ b/.changelog/#####.txt @@ -1,5 +1,5 @@ ```release-note:enhancement -data-source/aws_eip: Add `domain_name` attribute +data-source/aws_eip: Add `ptr_record` attribute ``` ```release-note:enhancement diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index c29d00f130d..c821419cbd4 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -88,7 +88,7 @@ func resourceEIP() *schema.Resource { }, "domain_name": { Type: schema.TypeString, - Computed: true, + Optional: true, DiffSuppressFunc: sdkv2.SuppressEquivalentStringCaseInsensitive, }, "instance": { diff --git a/internal/service/ec2/ec2_eip_data_source.go b/internal/service/ec2/ec2_eip_data_source.go index c6ff1a6d5a6..d919acc9252 100644 --- a/internal/service/ec2/ec2_eip_data_source.go +++ b/internal/service/ec2/ec2_eip_data_source.go @@ -5,7 +5,6 @@ package ec2 import ( "context" - "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -51,10 +50,6 @@ func dataSourceEIP() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "domain_name": { - Type: schema.TypeString, - Computed: true, - }, "filter": customFiltersSchema(), "id": { Type: schema.TypeString, @@ -81,6 +76,10 @@ func dataSourceEIP() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "ptr_record": { + Type: schema.TypeString, + Computed: true, + }, "public_ip": { Type: schema.TypeString, Optional: true, @@ -139,15 +138,15 @@ func dataSourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interfa switch { case err == nil: - d.Set("domain_name", strings.TrimSuffix(aws.ToString(addressAttr.PtrRecord), ".")) + d.Set("ptr_record", addressAttr.PtrRecord) case tfresource.NotFound(err): - d.Set("domain_name", nil) + d.Set("ptr_record", nil) default: return sdkdiag.AppendErrorf(diags, "reading EC2 EIP (%s) domain name attribute: %s", d.Id(), err) } } else { d.SetId(aws.ToString(eip.PublicIp)) - d.Set("domain_name", nil) + d.Set("ptr_record", nil) } d.Set("association_id", eip.AssociationId) d.Set("carrier_ip", eip.CarrierIp) diff --git a/internal/service/ec2/ec2_eip_data_source_test.go b/internal/service/ec2/ec2_eip_data_source_test.go index 4374bb60c1e..40f8b6bdcdd 100644 --- a/internal/service/ec2/ec2_eip_data_source_test.go +++ b/internal/service/ec2/ec2_eip_data_source_test.go @@ -27,7 +27,6 @@ func TestAccEC2EIPDataSource_filter(t *testing.T) { { Config: testAccEIPDataSourceConfig_filter(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, "domain_name", resourceName, "domain_name"), resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), resource.TestCheckResourceAttrPair(dataSourceName, "public_dns", resourceName, "public_dns"), resource.TestCheckResourceAttrPair(dataSourceName, "public_ip", resourceName, "public_ip"), diff --git a/website/docs/d/eip.html.markdown b/website/docs/d/eip.html.markdown index 4e69eb2297c..bfcee229f45 100644 --- a/website/docs/d/eip.html.markdown +++ b/website/docs/d/eip.html.markdown @@ -69,13 +69,13 @@ This data source exports the following attributes in addition to the arguments a * `customer_owned_ip` - Customer Owned IP. * `customer_owned_ipv4_pool` - The ID of a Customer Owned IP Pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing) * `domain` - Whether the address is for use in EC2-Classic (standard) or in a VPC (vpc). -* `domain_name` - The DNS pointer (PTR) record for the IP address. * `id` - If VPC Elastic IP, the allocation identifier. If EC2-Classic Elastic IP, the public IP address. * `instance_id` - ID of the instance that the address is associated with (if any). * `network_interface_id` - The ID of the network interface. * `network_interface_owner_id` - The ID of the AWS account that owns the network interface. * `private_ip` - Private IP address associated with the Elastic IP address. * `private_dns` - Private DNS associated with the Elastic IP address. +* `ptr_record` - The DNS pointer (PTR) record for the IP address. * `public_ip` - Public IP address of Elastic IP. * `public_dns` - Public DNS associated with the Elastic IP address. * `public_ipv4_pool` - ID of an address pool. From 7f7bc55037efe774f13c704d983f3190c3b975b1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 14:15:29 -0400 Subject: [PATCH 16/25] r/aws_eip_domain_name: New resource. --- .changelog/#####.txt | 4 +- internal/service/ec2/consts.go | 5 + internal/service/ec2/ec2_eip_domain_name.go | 218 ++++++++++++++++++++ internal/service/ec2/service_package_gen.go | 4 + internal/service/ec2/status.go | 22 +- internal/service/ec2/wait.go | 25 ++- website/docs/r/eip.html.markdown | 1 - 7 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 internal/service/ec2/ec2_eip_domain_name.go diff --git a/.changelog/#####.txt b/.changelog/#####.txt index 7458017d809..7da0d6979ad 100644 --- a/.changelog/#####.txt +++ b/.changelog/#####.txt @@ -2,6 +2,6 @@ data-source/aws_eip: Add `ptr_record` attribute ``` -```release-note:enhancement -resource/aws_eip: Add `domain_name` argument +```release-note:new-resource +aws_eip_domain_name ``` \ No newline at end of file diff --git a/internal/service/ec2/consts.go b/internal/service/ec2/consts.go index 89720006fce..28ae7f01fca 100644 --- a/internal/service/ec2/consts.go +++ b/internal/service/ec2/consts.go @@ -96,6 +96,11 @@ const ( CustomerGatewayStatePending = "pending" ) +// See https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-address-attribute.html#examples. +const ( + PTRUpdateStatusPending = "PENDING" +) + const ( managedPrefixListAddressFamilyIPv4 = "IPv4" managedPrefixListAddressFamilyIPv6 = "IPv6" diff --git a/internal/service/ec2/ec2_eip_domain_name.go b/internal/service/ec2/ec2_eip_domain_name.go new file mode 100644 index 00000000000..aacad005205 --- /dev/null +++ b/internal/service/ec2/ec2_eip_domain_name.go @@ -0,0 +1,218 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + "fmt" + "time" + + "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-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/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource(name="EIP Domain Name") +func newEIPDomainNameResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &eipDomainNameResource{} + + r.SetDefaultCreateTimeout(10 * time.Minute) + r.SetDefaultUpdateTimeout(10 * time.Minute) + r.SetDefaultDeleteTimeout(10 * time.Minute) + + return r, nil +} + +type eipDomainNameResource struct { + framework.ResourceWithConfigure + framework.WithTimeouts +} + +func (*eipDomainNameResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_eip_domain_name" +} + +func (r *eipDomainNameResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "allocation_id": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "domain_name": schema.StringAttribute{ + Required: true, + }, + names.AttrID: framework.IDAttribute(), + "ptr_record": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "timeouts": timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), + }, + } +} + +func (r *eipDomainNameResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data eipDomainNameResourceModel + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + input := &ec2.ModifyAddressAttributeInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + if response.Diagnostics.HasError() { + return + } + + output, err := conn.ModifyAddressAttribute(ctx, input) + + if err != nil { + response.Diagnostics.AddError("creating EC2 EIP Domain Name", err.Error()) + + return + } + + // Set values for unknowns. + data.ID = fwflex.StringToFramework(ctx, output.Address.AllocationId) + + v, err := waitEIPDomainNameAttributeUpdated(ctx, conn, data.ID.ValueString(), r.CreateTimeout(ctx, data.Timeouts)) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for EC2 EIP Domain Name (%s) create", data.ID.ValueString()), err.Error()) + + return + } + + data.PTRRecord = fwflex.StringToFramework(ctx, v.PtrRecord) + + response.Diagnostics.Append(response.State.Set(ctx, data)...) +} + +func (r *eipDomainNameResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data eipDomainNameResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + output, err := findEIPDomainNameAttributeByAllocationID(ctx, conn, data.AllocationID.ValueString()) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading EC2 EIP Domain Name (%s)", data.ID.ValueString()), err.Error()) + + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *eipDomainNameResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var old, new eipDomainNameResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &old)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(request.Plan.Get(ctx, &new)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + if !new.DomainName.Equal(old.DomainName) { + input := &ec2.ModifyAddressAttributeInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, new, input)...) + if response.Diagnostics.HasError() { + return + } + + _, err := conn.ModifyAddressAttribute(ctx, input) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("updating EC2 EIP Domain Name (%s)", new.ID.ValueString()), err.Error()) + + return + } + + if _, err := waitEIPDomainNameAttributeUpdated(ctx, conn, new.ID.ValueString(), r.UpdateTimeout(ctx, new.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for EC2 EIP Domain Name (%s) update", new.ID.ValueString()), err.Error()) + + return + } + } + + response.Diagnostics.Append(response.State.Set(ctx, &new)...) +} + +func (r *eipDomainNameResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data eipDomainNameResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + _, err := conn.ResetAddressAttribute(ctx, &ec2.ResetAddressAttributeInput{ + AllocationId: fwflex.StringFromFramework(ctx, data.ID), + Attribute: awstypes.AddressAttributeNameDomainName, + }) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting EC2 EIP Domain Name (%s)", data.ID.ValueString()), err.Error()) + + return + } + + if _, err := waitEIPDomainNameAttributeUpdated(ctx, conn, data.ID.ValueString(), r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for EC2 EIP Domain Name (%s) delete", data.ID.ValueString()), err.Error()) + + return + } +} + +type eipDomainNameResourceModel struct { + AllocationID types.String `tfsdk:"allocation_id"` + ID types.String `tfsdk:"id"` + DomainName types.String `tfsdk:"domain_name"` + PTRRecord types.String `tfsdk:"ptr_record"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index b8bf9f36959..49cbedd80e1 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -36,6 +36,10 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic Factory: newEBSFastSnapshotRestoreResource, Name: "EBS Fast Snapshot Restore", }, + { + Factory: newEIPDomainNameResource, + Name: "EIP Domain Name", + }, { Factory: newInstanceConnectEndpointResource, Name: "Instance Connect Endpoint", diff --git a/internal/service/ec2/status.go b/internal/service/ec2/status.go index b80800b6ff2..c90bbc6c2fa 100644 --- a/internal/service/ec2/status.go +++ b/internal/service/ec2/status.go @@ -1107,6 +1107,26 @@ func StatusVPNGatewayState(ctx context.Context, conn *ec2.EC2, id string) retry. } } +func statusEIPDomainNameAttribute(ctx context.Context, conn *ec2_sdkv2.Client, allocationID string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findEIPDomainNameAttributeByAllocationID(ctx, conn, allocationID) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + if output.PtrRecordUpdate == nil { + return nil, "", nil + } + + return output, aws_sdkv2.ToString(output.PtrRecordUpdate.Status), nil + } +} + func StatusHostState(ctx context.Context, conn *ec2.EC2, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { output, err := FindHostByID(ctx, conn, id) @@ -1468,7 +1488,7 @@ func StatusIPAMScopeState(ctx context.Context, conn *ec2.EC2, id string) retry.S } } -func StatusInstanceConnectEndpointState(ctx context.Context, conn *ec2_sdkv2.Client, id string) retry.StateRefreshFunc { +func statusInstanceConnectEndpoint(ctx context.Context, conn *ec2_sdkv2.Client, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { output, err := FindInstanceConnectEndpointByID(ctx, conn, id) diff --git a/internal/service/ec2/wait.go b/internal/service/ec2/wait.go index 37a4c03dae9..c31de8d9465 100644 --- a/internal/service/ec2/wait.go +++ b/internal/service/ec2/wait.go @@ -2160,6 +2160,27 @@ func WaitVPNGatewayDeleted(ctx context.Context, conn *ec2.EC2, id string) (*ec2. return nil, err } +func waitEIPDomainNameAttributeUpdated(ctx context.Context, conn *ec2_sdkv2.Client, allocationID string, timeout time.Duration) (*awstypes.AddressAttribute, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{PTRUpdateStatusPending}, + Target: []string{}, + Timeout: timeout, + Refresh: statusEIPDomainNameAttribute(ctx, conn, allocationID), + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.AddressAttribute); ok { + if v := output.PtrRecordUpdate; v != nil { + tfresource.SetLastError(err, errors.New(aws_sdkv2.ToString(v.Reason))) + } + + return output, err + } + + return nil, err +} + func WaitHostCreated(ctx context.Context, conn *ec2.EC2, id string, timeout time.Duration) (*ec2.Host, error) { stateConf := &retry.StateChangeConf{ Pending: []string{ec2.AllocationStatePending}, @@ -3090,7 +3111,7 @@ func WaitInstanceConnectEndpointCreated(ctx context.Context, conn *ec2_sdkv2.Cli stateConf := &retry.StateChangeConf{ Pending: enum.Slice(awstypes.Ec2InstanceConnectEndpointStateCreateInProgress), Target: enum.Slice(awstypes.Ec2InstanceConnectEndpointStateCreateComplete), - Refresh: StatusInstanceConnectEndpointState(ctx, conn, id), + Refresh: statusInstanceConnectEndpoint(ctx, conn, id), Timeout: timeout, } @@ -3109,7 +3130,7 @@ func WaitInstanceConnectEndpointDeleted(ctx context.Context, conn *ec2_sdkv2.Cli stateConf := &retry.StateChangeConf{ Pending: enum.Slice(awstypes.Ec2InstanceConnectEndpointStateDeleteInProgress), Target: []string{}, - Refresh: StatusInstanceConnectEndpointState(ctx, conn, id), + Refresh: statusInstanceConnectEndpoint(ctx, conn, id), Timeout: timeout, } diff --git a/website/docs/r/eip.html.markdown b/website/docs/r/eip.html.markdown index 2df466eb524..b99c7e38ef6 100644 --- a/website/docs/r/eip.html.markdown +++ b/website/docs/r/eip.html.markdown @@ -101,7 +101,6 @@ This resource supports the following arguments: * `associate_with_private_ip` - (Optional) User-specified primary or secondary private IP address to associate with the Elastic IP address. If no private IP address is specified, the Elastic IP address is associated with the primary private IP address. * `customer_owned_ipv4_pool` - (Optional) ID of a customer-owned address pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing). * `domain` - Indicates if this EIP is for use in VPC (`vpc`). -* `domain_name` - The domain name for the IP address. * `instance` - (Optional) EC2 instance ID. * `network_border_group` - (Optional) Location from which the IP address is advertised. Use this parameter to limit the address to this location. * `network_interface` - (Optional) Network interface ID to associate with. From 7a684114160e6cacfe19eac240f4b5daa8460be7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 14:28:04 -0400 Subject: [PATCH 17/25] r/aws_eip_domain_name: Add documentation. --- website/docs/r/eip_domain_name.html.markdown | 53 ++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 website/docs/r/eip_domain_name.html.markdown diff --git a/website/docs/r/eip_domain_name.html.markdown b/website/docs/r/eip_domain_name.html.markdown new file mode 100644 index 00000000000..2107a1aaaca --- /dev/null +++ b/website/docs/r/eip_domain_name.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "EC2 (Elastic Compute Cloud)" +layout: "aws" +page_title: "AWS: aws_eip_domain_name" +description: |- + Assigns a static reverse DNS record to an Elastic IP addresses +--- + +# Resource: aws_eip_domain_name + +Assigns a static reverse DNS record to an Elastic IP addresses. See [Using reverse DNS for email applications](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#Using_Elastic_Addressing_Reverse_DNS). + +## Example Usage + +```terraform +resource "aws_eip" "example" { + domain = "vpc" +} + +resource "aws_route53_record" "example" { + zone_id = aws_route53_zone.main.zone_id + name = "reverse" + type = "A" + + records = [aws_eip.example.public_ip] +} + +resource "aws_eip_domain_name" "example" { + allocation_id = aws_eip.example.allocation_id + domain_name = aws_route53_record.example.fqdn +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `allocation_id` - (Required) The allocation ID. +* `domain_name` - (Required) The domain name to modify for the IP address. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `ptr_record` - The DNS pointer (PTR) record for the IP address. + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +- `create` - (Default `10m`) +- `update` - (Default `10m`) +- `delete` - (Default `10m`) From 886637d0996f0ad1e06585cadd91a01c89502cae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:05:37 -0400 Subject: [PATCH 18/25] Correct CHANGELOG entry. --- .changelog/36767.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/36767.txt b/.changelog/36767.txt index 5aadd08a783..cb44f146d4d 100644 --- a/.changelog/36767.txt +++ b/.changelog/36767.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/openzfs_file_system: Add `endpoint_ip_address` attribute +resource/aws_fsx_openzfs_file_system: Add `endpoint_ip_address` attribute ``` From 0b66cb3a46d57e9bac02324bdb754dd47f50a9bd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:06:24 -0400 Subject: [PATCH 19/25] r/aws_eip: Add 'ptr_record' attribute. --- .changelog/#####.txt | 4 ++++ internal/service/ec2/ec2_eip.go | 14 ++++++-------- internal/service/ec2/ec2_eip_test.go | 1 + website/docs/r/eip.html.markdown | 1 + 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.changelog/#####.txt b/.changelog/#####.txt index 7da0d6979ad..21f7bdf9a4a 100644 --- a/.changelog/#####.txt +++ b/.changelog/#####.txt @@ -2,6 +2,10 @@ data-source/aws_eip: Add `ptr_record` attribute ``` +```release-note:enhancement +resource/aws_eip: Add `ptr_record` attribute +``` + ```release-note:new-resource aws_eip_domain_name ``` \ No newline at end of file diff --git a/internal/service/ec2/ec2_eip.go b/internal/service/ec2/ec2_eip.go index c821419cbd4..1476bd416f3 100644 --- a/internal/service/ec2/ec2_eip.go +++ b/internal/service/ec2/ec2_eip.go @@ -20,7 +20,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" 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" @@ -86,11 +85,6 @@ func resourceEIP() *schema.Resource { ValidateDiagFunc: enum.Validate[types.DomainType](), ConflictsWith: []string{"vpc"}, }, - "domain_name": { - Type: schema.TypeString, - Optional: true, - DiffSuppressFunc: sdkv2.SuppressEquivalentStringCaseInsensitive, - }, "instance": { Type: schema.TypeString, Optional: true, @@ -115,6 +109,10 @@ func resourceEIP() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "ptr_record": { + Type: schema.TypeString, + Computed: true, + }, "public_dns": { Type: schema.TypeString, Computed: true, @@ -258,9 +256,9 @@ func resourceEIPRead(ctx context.Context, d *schema.ResourceData, meta interface switch { case err == nil: - d.Set("domain_name", strings.TrimSuffix(aws.ToString(addressAttr.PtrRecord), ".")) + d.Set("ptr_record", strings.TrimSuffix(aws.ToString(addressAttr.PtrRecord), ".")) case tfresource.NotFound(err): - d.Set("domain_name", nil) + d.Set("ptr_record", nil) default: return sdkdiag.AppendErrorf(diags, "reading EC2 EIP (%s) domain name attribute: %s", d.Id(), err) } diff --git a/internal/service/ec2/ec2_eip_test.go b/internal/service/ec2/ec2_eip_test.go index f3da83a4fe9..12507de6854 100644 --- a/internal/service/ec2/ec2_eip_test.go +++ b/internal/service/ec2/ec2_eip_test.go @@ -37,6 +37,7 @@ func TestAccEC2EIP_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckEIPExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "domain", "vpc"), + resource.TestCheckResourceAttr(resourceName, "ptr_record", ""), resource.TestCheckResourceAttrSet(resourceName, "public_ip"), testAccCheckEIPPublicDNS(ctx, resourceName), ), diff --git a/website/docs/r/eip.html.markdown b/website/docs/r/eip.html.markdown index b99c7e38ef6..feafb069321 100644 --- a/website/docs/r/eip.html.markdown +++ b/website/docs/r/eip.html.markdown @@ -126,6 +126,7 @@ This resource exports the following attributes in addition to the arguments abov * `id` - Contains the EIP allocation ID. * `private_dns` - The Private DNS associated with the Elastic IP address (if in VPC). * `private_ip` - Contains the private IP address (if in VPC). +* `ptr_record` - The DNS pointer (PTR) record for the IP address. * `public_dns` - Public DNS associated with the Elastic IP address. * `public_ip` - Contains the public IP address. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). From 719fafafbb4c11cad823d16b800c5c3bcfcf2859 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:06:55 -0400 Subject: [PATCH 20/25] r/aws_eip_domain_name: Add first acceptance test. --- internal/service/ec2/ec2_eip_domain_name.go | 7 +- .../service/ec2/ec2_eip_domain_name_test.go | 115 ++++++++++++++++++ internal/service/ec2/exports_test.go | 1 + internal/service/ec2/status.go | 2 +- internal/service/ec2/wait.go | 21 ++++ 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 internal/service/ec2/ec2_eip_domain_name_test.go diff --git a/internal/service/ec2/ec2_eip_domain_name.go b/internal/service/ec2/ec2_eip_domain_name.go index aacad005205..d95a11fb5c2 100644 --- a/internal/service/ec2/ec2_eip_domain_name.go +++ b/internal/service/ec2/ec2_eip_domain_name.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ec2" awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -196,13 +197,17 @@ func (r *eipDomainNameResource) Delete(ctx context.Context, request resource.Del Attribute: awstypes.AddressAttributeNameDomainName, }) + if tfawserr.ErrCodeEquals(err, errCodeInvalidAssociationIDNotFound) { + return + } + if err != nil { response.Diagnostics.AddError(fmt.Sprintf("deleting EC2 EIP Domain Name (%s)", data.ID.ValueString()), err.Error()) return } - if _, err := waitEIPDomainNameAttributeUpdated(ctx, conn, data.ID.ValueString(), r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + if _, err := waitEIPDomainNameAttributeDeleted(ctx, conn, data.ID.ValueString(), r.DeleteTimeout(ctx, data.Timeouts)); err != nil { response.Diagnostics.AddError(fmt.Sprintf("waiting for EC2 EIP Domain Name (%s) delete", data.ID.ValueString()), err.Error()) return diff --git a/internal/service/ec2/ec2_eip_domain_name_test.go b/internal/service/ec2/ec2_eip_domain_name_test.go new file mode 100644 index 00000000000..b0be83e0509 --- /dev/null +++ b/internal/service/ec2/ec2_eip_domain_name_test.go @@ -0,0 +1,115 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2_test + +import ( + "context" + "fmt" + "testing" + + 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" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccEC2EIPDomainName_basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_eip_domain_name.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEIPDomainNameDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEIPDomainNameConfig_basic(rName, rootDomain, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckEIPDomainNameExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, "ptr_record"), + ), + }, + }, + }) +} + +func testAccCheckEIPDomainNameExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + _, err := tfec2.FindEIPDomainNameAttributeByAllocationID(ctx, conn, rs.Primary.ID) + + return err + } +} + +func testAccCheckEIPDomainNameDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_eip_domain_name" { + continue + } + + _, err := tfec2.FindEIPDomainNameAttributeByAllocationID(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("EC2 EIP Domain Name %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccEIPDomainNameConfig_basic(rName, rootDomain, domain string) string { + return fmt.Sprintf(` +resource "aws_eip" "test" { + domain = "vpc" + + tags = { + Name = %[1]q + } +} + +data "aws_route53_zone" "test" { + name = %[2]q + private_zone = false +} + +resource "aws_route53_record" "test" { + zone_id = data.aws_route53_zone.test.zone_id + ttl = 60 + type = "A" + name = %[3]q + + records = [aws_eip.test.public_ip] +} + +resource "aws_eip_domain_name" "test" { + allocation_id = aws_eip.test.allocation_id + domain_name = aws_route53_record.test.fqdn +} +`, rName, rootDomain, domain) +} diff --git a/internal/service/ec2/exports_test.go b/internal/service/ec2/exports_test.go index 8785fb05f77..81457cf7a3c 100644 --- a/internal/service/ec2/exports_test.go +++ b/internal/service/ec2/exports_test.go @@ -32,6 +32,7 @@ var ( CustomFiltersSchema = customFiltersSchema FindEIPByAllocationID = findEIPByAllocationID FindEIPByAssociationID = findEIPByAssociationID + FindEIPDomainNameAttributeByAllocationID = findEIPDomainNameAttributeByAllocationID FindFastSnapshotRestoreByTwoPartKey = findFastSnapshotRestoreByTwoPartKey FindInstanceMetadataDefaults = findInstanceMetadataDefaults FindKeyPairByName = findKeyPairByName diff --git a/internal/service/ec2/status.go b/internal/service/ec2/status.go index c90bbc6c2fa..892025e7b86 100644 --- a/internal/service/ec2/status.go +++ b/internal/service/ec2/status.go @@ -1120,7 +1120,7 @@ func statusEIPDomainNameAttribute(ctx context.Context, conn *ec2_sdkv2.Client, a } if output.PtrRecordUpdate == nil { - return nil, "", nil + return output, "", nil } return output, aws_sdkv2.ToString(output.PtrRecordUpdate.Status), nil diff --git a/internal/service/ec2/wait.go b/internal/service/ec2/wait.go index c31de8d9465..56bed319e0b 100644 --- a/internal/service/ec2/wait.go +++ b/internal/service/ec2/wait.go @@ -2161,6 +2161,27 @@ func WaitVPNGatewayDeleted(ctx context.Context, conn *ec2.EC2, id string) (*ec2. } func waitEIPDomainNameAttributeUpdated(ctx context.Context, conn *ec2_sdkv2.Client, allocationID string, timeout time.Duration) (*awstypes.AddressAttribute, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{PTRUpdateStatusPending}, + Target: []string{""}, + Timeout: timeout, + Refresh: statusEIPDomainNameAttribute(ctx, conn, allocationID), + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.AddressAttribute); ok { + if v := output.PtrRecordUpdate; v != nil { + tfresource.SetLastError(err, errors.New(aws_sdkv2.ToString(v.Reason))) + } + + return output, err + } + + return nil, err +} + +func waitEIPDomainNameAttributeDeleted(ctx context.Context, conn *ec2_sdkv2.Client, allocationID string, timeout time.Duration) (*awstypes.AddressAttribute, error) { stateConf := &retry.StateChangeConf{ Pending: []string{PTRUpdateStatusPending}, Target: []string{}, From 74d489da8866289ea4104e22a8fd9d232e156d0b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:14:03 -0400 Subject: [PATCH 21/25] r/aws_eip_domain_name: Additional acceptance tests. --- .../service/ec2/ec2_eip_domain_name_test.go | 137 ++++++++++++++++++ internal/service/ec2/exports_test.go | 1 + 2 files changed, 138 insertions(+) diff --git a/internal/service/ec2/ec2_eip_domain_name_test.go b/internal/service/ec2/ec2_eip_domain_name_test.go index b0be83e0509..281e036ac8b 100644 --- a/internal/service/ec2/ec2_eip_domain_name_test.go +++ b/internal/service/ec2/ec2_eip_domain_name_test.go @@ -42,6 +42,63 @@ func TestAccEC2EIPDomainName_basic(t *testing.T) { }) } +func TestAccEC2EIPDomainName_disappears(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_eip_domain_name.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEIPDomainNameDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEIPDomainNameConfig_basic(rName, rootDomain, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckEIPDomainNameExists(ctx, resourceName), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfec2.ResourceEIPDomainName, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccEC2EIPDomainName_update(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_eip_domain_name.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain1 := acctest.ACMCertificateRandomSubDomain(rootDomain) + domain2 := acctest.ACMCertificateRandomSubDomain(rootDomain) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEIPDomainNameDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEIPDomainNameConfig_original(rName, rootDomain, domain1, domain2), + Check: resource.ComposeTestCheckFunc( + testAccCheckEIPDomainNameExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, "ptr_record"), + ), + }, + { + Config: testAccEIPDomainNameConfig_updated(rName, rootDomain, domain1, domain2), + Check: resource.ComposeTestCheckFunc( + testAccCheckEIPDomainNameExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, "ptr_record"), + ), + }, + }, + }) +} + func testAccCheckEIPDomainNameExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -113,3 +170,83 @@ resource "aws_eip_domain_name" "test" { } `, rName, rootDomain, domain) } + +func testAccEIPDomainNameConfig_original(rName, rootDomain, domain1, domain2 string) string { + return fmt.Sprintf(` +resource "aws_eip" "test" { + domain = "vpc" + + tags = { + Name = %[1]q + } +} + +data "aws_route53_zone" "test" { + name = %[2]q + private_zone = false +} + +resource "aws_route53_record" "test1" { + zone_id = data.aws_route53_zone.test.zone_id + ttl = 60 + type = "A" + name = %[3]q + + records = [aws_eip.test.public_ip] +} + +resource "aws_route53_record" "test2" { + zone_id = data.aws_route53_zone.test.zone_id + ttl = 60 + type = "A" + name = %[3]q + + records = [aws_eip.test.public_ip] +} + +resource "aws_eip_domain_name" "test" { + allocation_id = aws_eip.test.allocation_id + domain_name = aws_route53_record.test1.fqdn +} +`, rName, rootDomain, domain1, domain2) +} + +func testAccEIPDomainNameConfig_updated(rName, rootDomain, domain1, domain2 string) string { + return fmt.Sprintf(` +resource "aws_eip" "test" { + domain = "vpc" + + tags = { + Name = %[1]q + } +} + +data "aws_route53_zone" "test" { + name = %[2]q + private_zone = false +} + +resource "aws_route53_record" "test1" { + zone_id = data.aws_route53_zone.test.zone_id + ttl = 60 + type = "A" + name = %[3]q + + records = [aws_eip.test.public_ip] +} + +resource "aws_route53_record" "test2" { + zone_id = data.aws_route53_zone.test.zone_id + ttl = 60 + type = "A" + name = %[3]q + + records = [aws_eip.test.public_ip] +} + +resource "aws_eip_domain_name" "test" { + allocation_id = aws_eip.test.allocation_id + domain_name = aws_route53_record.test2.fqdn +} +`, rName, rootDomain, domain1, domain2) +} diff --git a/internal/service/ec2/exports_test.go b/internal/service/ec2/exports_test.go index 81457cf7a3c..4711f9a415e 100644 --- a/internal/service/ec2/exports_test.go +++ b/internal/service/ec2/exports_test.go @@ -11,6 +11,7 @@ var ( ResourceEBSFastSnapshotRestore = newEBSFastSnapshotRestoreResource ResourceEIP = resourceEIP ResourceEIPAssociation = resourceEIPAssociation + ResourceEIPDomainName = newEIPDomainNameResource ResourceInstanceConnectEndpoint = newInstanceConnectEndpointResource ResourceInstanceMetadataDefaults = newInstanceMetadataDefaultsResource ResourceKeyPair = resourceKeyPair From bb19ebe1a3094099feb2c5ebc970026dcd8eaff5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:28:20 -0400 Subject: [PATCH 22/25] r/aws_eip_domain_name: Add sweeper. --- internal/service/ec2/sweep.go | 85 +++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/internal/service/ec2/sweep.go b/internal/service/ec2/sweep.go index 7696673bd66..0f0dc18d63f 100644 --- a/internal/service/ec2/sweep.go +++ b/internal/service/ec2/sweep.go @@ -81,11 +81,17 @@ func RegisterSweepers() { resource.AddTestSweepers("aws_eip", &resource.Sweeper{ Name: "aws_eip", Dependencies: []string{ + "aws_eip_domain_name", "aws_vpc", }, F: sweepEIPs, }) + resource.AddTestSweepers("aws_eip_domain_name", &resource.Sweeper{ + Name: "aws_eip_domain_name", + F: sweepEIPDomainNames, + }) + resource.AddTestSweepers("aws_flow_log", &resource.Sweeper{ Name: "aws_flow_log", F: sweepFlowLogs, @@ -844,15 +850,13 @@ func sweepEgressOnlyInternetGateways(region string) error { func sweepEIPs(region string) error { ctx := sweep.Context(region) client, err := sweep.SharedRegionalSweepClient(ctx, region) - if err != nil { return fmt.Errorf("error getting client: %s", err) } - - conn := client.EC2Conn(ctx) - // There is currently no paginator or Marker/NextToken input := &ec2.DescribeAddressesInput{} + conn := client.EC2Conn(ctx) + sweepResources := make([]sweep.Sweepable, 0) output, err := conn.DescribeAddressesWithContext(ctx, input) @@ -865,43 +869,76 @@ func sweepEIPs(region string) error { return fmt.Errorf("error describing EC2 EIPs: %s", err) } - if output == nil || len(output.Addresses) == 0 { - log.Print("[DEBUG] No EC2 EIPs to sweep") - return nil - } - - sweepResources := make([]sweep.Sweepable, 0) - var errs *multierror.Error - - for _, address := range output.Addresses { - publicIP := aws.StringValue(address.PublicIp) + for _, v := range output.Addresses { + publicIP := aws.StringValue(v.PublicIp) - if address.AssociationId != nil { - log.Printf("[INFO] Skipping EC2 EIP (%s) with association: %s", publicIP, aws.StringValue(address.AssociationId)) + if v.AssociationId != nil { + log.Printf("[INFO] Skipping EC2 EIP (%s) with association: %s", publicIP, aws.StringValue(v.AssociationId)) continue } r := resourceEIP() d := r.Data(nil) - if address.AllocationId != nil { - d.SetId(aws.StringValue(address.AllocationId)) + if v.AllocationId != nil { + d.SetId(aws.StringValue(v.AllocationId)) } else { - d.SetId(aws.StringValue(address.PublicIp)) + d.SetId(aws.StringValue(v.PublicIp)) } sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) } - if err = sweep.SweepOrchestrator(ctx, sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping EC2 EIPs for %s: %w", region, err)) + err = sweep.SweepOrchestrator(ctx, sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping EC2 EIPs (%s): %w", region, err) } - if awsv1.SkipSweepError(errs.ErrorOrNil()) { - log.Printf("[WARN] Skipping EC2 EIP sweep for %s: %s", region, errs) + return nil +} + +func sweepEIPDomainNames(region string) error { + ctx := sweep.Context(region) + client, err := sweep.SharedRegionalSweepClient(ctx, region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.EC2Conn(ctx) + input := &ec2.DescribeAddressesAttributeInput{ + Attribute: aws.String(ec2.AddressAttributeNameDomainName), + } + sweepResources := make([]sweep.Sweepable, 0) + + err = conn.DescribeAddressesAttributePagesWithContext(ctx, input, func(page *ec2.DescribeAddressesAttributeOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.Addresses { + sweepResources = append(sweepResources, framework.NewSweepResource(newEIPDomainNameResource, client, + framework.NewAttribute("id", aws.StringValue(v.AllocationId)), + )) + } + + return !lastPage + }) + + if awsv1.SkipSweepError(err) { + log.Printf("[WARN] Skipping EIP Domain Name sweep for %s: %s", region, err) return nil } - return errs.ErrorOrNil() + if err != nil { + return fmt.Errorf("error listing EIP Domain Names (%s): %w", region, err) + } + + err = sweep.SweepOrchestrator(ctx, sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping EIP Domain Names (%s): %w", region, err) + } + + return nil } func sweepFlowLogs(region string) error { From e8a9bd295dfa19f1acf51e432bf7610407ef8b2f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:28:46 -0400 Subject: [PATCH 23/25] Fix 'TestAccEC2EIPDomainName_update'. --- internal/service/ec2/ec2_eip_domain_name_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/ec2/ec2_eip_domain_name_test.go b/internal/service/ec2/ec2_eip_domain_name_test.go index 281e036ac8b..e3924bf2298 100644 --- a/internal/service/ec2/ec2_eip_domain_name_test.go +++ b/internal/service/ec2/ec2_eip_domain_name_test.go @@ -199,7 +199,7 @@ resource "aws_route53_record" "test2" { zone_id = data.aws_route53_zone.test.zone_id ttl = 60 type = "A" - name = %[3]q + name = %[4]q records = [aws_eip.test.public_ip] } @@ -239,7 +239,7 @@ resource "aws_route53_record" "test2" { zone_id = data.aws_route53_zone.test.zone_id ttl = 60 type = "A" - name = %[3]q + name = %[4]q records = [aws_eip.test.public_ip] } From 77a0b8532864325c8aec6ce09d0ebee8afe4e23a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:30:42 -0400 Subject: [PATCH 24/25] r/aws_eip_domain_name: Fix error handling on Delete. --- internal/service/ec2/ec2_eip_domain_name.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/ec2_eip_domain_name.go b/internal/service/ec2/ec2_eip_domain_name.go index d95a11fb5c2..0aabb38c200 100644 --- a/internal/service/ec2/ec2_eip_domain_name.go +++ b/internal/service/ec2/ec2_eip_domain_name.go @@ -197,7 +197,7 @@ func (r *eipDomainNameResource) Delete(ctx context.Context, request resource.Del Attribute: awstypes.AddressAttributeNameDomainName, }) - if tfawserr.ErrCodeEquals(err, errCodeInvalidAssociationIDNotFound) { + if tfawserr.ErrCodeEquals(err, errCodeInvalidAllocationIDNotFound) { return } From cab40fcd124499e1c1e89bf2ae196729f2675d9b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 17 Apr 2024 15:35:11 -0400 Subject: [PATCH 25/25] Correct CHANGELOG entry file name. --- .changelog/{#####.txt => 36963.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{#####.txt => 36963.txt} (100%) diff --git a/.changelog/#####.txt b/.changelog/36963.txt similarity index 100% rename from .changelog/#####.txt rename to .changelog/36963.txt