From 0bc906553a9ccf5d52e0da1078271984bb6a04be Mon Sep 17 00:00:00 2001 From: Antoine Labarussias Date: Wed, 9 Jul 2025 13:38:43 +0200 Subject: [PATCH] feat(ec2/vpc): add datasource aws_egress_only_internet_gateway --- .changelog/43319.txt | 3 + internal/service/ec2/service_package_gen.go | 6 + ...gress_only_internet_gateway_data_source.go | 118 ++++++++++++++++++ ..._only_internet_gateway_data_source_test.go | 99 +++++++++++++++ ...egress_only_internet_gateway.html.markdown | 45 +++++++ 5 files changed, 271 insertions(+) create mode 100644 .changelog/43319.txt create mode 100644 internal/service/ec2/vpc_egress_only_internet_gateway_data_source.go create mode 100644 internal/service/ec2/vpc_egress_only_internet_gateway_data_source_test.go create mode 100644 website/docs/d/egress_only_internet_gateway.html.markdown diff --git a/.changelog/43319.txt b/.changelog/43319.txt new file mode 100644 index 000000000000..20e5bed7442d --- /dev/null +++ b/.changelog/43319.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_egress_only_internet_gateway +``` diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 756d787775ec..912075405fc6 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -26,6 +26,12 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S Name: "Capacity Block Offering", Region: unique.Make(inttypes.ResourceRegionDefault()), }, + { + Factory: newDataSourceVpcEgressOnlyInternetGateway, + TypeName: "aws_egress_only_internet_gateway", + Name: "Egress Only Internet Gateway", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, { Factory: newSpotDataFeedSubscriptionDataSource, TypeName: "aws_spot_datafeed_subscription", diff --git a/internal/service/ec2/vpc_egress_only_internet_gateway_data_source.go b/internal/service/ec2/vpc_egress_only_internet_gateway_data_source.go new file mode 100644 index 000000000000..dc7afc40274b --- /dev/null +++ b/internal/service/ec2/vpc_egress_only_internet_gateway_data_source.go @@ -0,0 +1,118 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkDataSource("aws_egress_only_internet_gateway", name="Egress Only Internet Gateway") +func newDataSourceVpcEgressOnlyInternetGateway(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceVpcEgressOnlyInternetGateway{}, nil +} + +const ( + DSNameVpcEgressOnlyInternetGateway = "Vpc Egress Only Internet Gateway Data Source" +) + +type dataSourceVpcEgressOnlyInternetGateway struct { + framework.DataSourceWithModel[dataSourceVpcEgressOnlyInternetGatewayModel] +} + +func (d *dataSourceVpcEgressOnlyInternetGateway) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrARN: framework.ARNAttributeComputedOnly(), + names.AttrID: framework.IDAttribute(), + "egress_only_internet_gateway_id": schema.StringAttribute{ + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.AtLeastOneOf( + path.MatchRelative().AtParent().AtName(names.AttrTags), + path.MatchRelative().AtParent().AtName("egress_only_internet_gateway_id"), + ), + }, + }, + names.AttrOwnerID: schema.StringAttribute{ + Computed: true, + }, + names.AttrTags: tftags.TagsAttribute(), + "attachments": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[eoigAttachmentModel](ctx), + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "state": types.StringType, + "vpc_id": types.StringType, + }, + }, + }, + }, + } +} + +func (d *dataSourceVpcEgressOnlyInternetGateway) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + conn := d.Meta().EC2Client(ctx) + + var data dataSourceVpcEgressOnlyInternetGatewayModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + input := &ec2.DescribeEgressOnlyInternetGatewaysInput{} + + if !data.EgressOnlyInternetGatewayID.IsNull() { + input.EgressOnlyInternetGatewayIds = []string{data.EgressOnlyInternetGatewayID.ValueString()} + } + + input.Filters = newTagFilterList(svcTags(tftags.New(ctx, data.Tags))) + + eoigw, err := findEgressOnlyInternetGateway(ctx, conn, input) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.EC2, create.ErrActionReading, DSNameVpcEgressOnlyInternetGateway, data.ID.ValueString(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(flex.Flatten(ctx, eoigw, &data, flex.WithFieldNamePrefix("EgressOnlyInternetGateway"))...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +type dataSourceVpcEgressOnlyInternetGatewayModel struct { + framework.WithRegionModel + ARN types.String `tfsdk:"arn"` + ID types.String `tfsdk:"id"` + OwnerID types.String `tfsdk:"owner_id"` + EgressOnlyInternetGatewayID types.String `tfsdk:"egress_only_internet_gateway_id"` + Attachments fwtypes.ListNestedObjectValueOf[eoigAttachmentModel] `tfsdk:"attachments"` + Tags tftags.Map `tfsdk:"tags"` +} + +type eoigAttachmentModel struct { + State types.String `tfsdk:"state"` + VpcID types.String `tfsdk:"vpc_id"` +} diff --git a/internal/service/ec2/vpc_egress_only_internet_gateway_data_source_test.go b/internal/service/ec2/vpc_egress_only_internet_gateway_data_source_test.go new file mode 100644 index 000000000000..f566ac942816 --- /dev/null +++ b/internal/service/ec2/vpc_egress_only_internet_gateway_data_source_test.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2_test + +import ( + "fmt" + "testing" + + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestVPCEgressOnlyInternetGatewayDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccVPCEgressOnlyInternetGatewayDataSourceConfig_basic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_id", "egress_only_internet_gateway_id", "aws_egress_only_internet_gateway.test", names.AttrID), + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_id", names.AttrOwnerID, "aws_egress_only_internet_gateway.test", names.AttrOwnerID), + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_id", "attachments.0.vpc_id", "aws_vpc.test", names.AttrID), + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_id", names.AttrARN, "aws_egress_only_internet_gateway.test", names.AttrARN), + ), + }, + }, + }) +} + +func TestVPCEgressOnlyInternetGatewayDataSource_tags(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccVPCEgressOnlyInternetGatewayDataSourceConfig_tags(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_tags", "egress_only_internet_gateway_id", "aws_egress_only_internet_gateway.test", names.AttrID), + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_tags", names.AttrOwnerID, "aws_egress_only_internet_gateway.test", names.AttrOwnerID), + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_tags", "attachments.0.vpc_id", "aws_vpc.test", names.AttrID), + resource.TestCheckResourceAttrPair("data.aws_egress_only_internet_gateway.by_tags", names.AttrARN, "aws_egress_only_internet_gateway.test", names.AttrARN), + ), + }, + }, + }) +} + +func testAccVPCEgressOnlyInternetGatewayDataSourceConfig_basic() string { + return ` +resource "aws_vpc" "test" { + cidr_block = "172.16.0.0/16" +} + +resource "aws_egress_only_internet_gateway" "test" { + vpc_id = aws_vpc.test.id +} + +data "aws_egress_only_internet_gateway" "by_id" { + egress_only_internet_gateway_id = aws_egress_only_internet_gateway.test.id +} +` +} + +func testAccVPCEgressOnlyInternetGatewayDataSourceConfig_tags(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "172.16.0.0/16" +} + +resource "aws_egress_only_internet_gateway" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +data "aws_egress_only_internet_gateway" "by_tags" { + tags = { + Name = %[1]q + } + + depends_on = [ + aws_egress_only_internet_gateway.test, + ] +} +`, rName) +} diff --git a/website/docs/d/egress_only_internet_gateway.html.markdown b/website/docs/d/egress_only_internet_gateway.html.markdown new file mode 100644 index 000000000000..18f329cb977f --- /dev/null +++ b/website/docs/d/egress_only_internet_gateway.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "VPC (Virtual Private Cloud)" +layout: "aws" +page_title: "AWS: aws_egress_only_internet_gateway" +description: |- + Provides details about a specific Egress-Only Internet Gateway. +--- + +# Data Source: aws_egress_only_internet_gateway + +`aws_egress_only_internet_gateway` provides details about a specific Egress-Only Internet Gateway. + +## Example Usage + +### Basic Usage + +```terraform +variable "eoig_id" {} + +data "aws_egress_only_internet_gateway" "default" { + egress_only_internet_gateway_id = var.eoig_id +} +``` + +## Argument Reference + +This data source supports the following arguments: + +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `egress_only_internet_gateway_id` - (Optional) ID of the specific Egress-Only Internet Gateway to retrieve. +* `tags` - (Optional) Map of tags, each pair of which must exactly match + a pair on the desired Egress-Only Internet Gateway. + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `arn` - ARN of the Egress-Only Internet Gateway. +* `owner_id` - ID of the AWS account that owns the egress-only internet gateway. + +`attachments` are also exported with the following attributes, when there are relevants: +Each attachment supports the following: + +* `state` - Current state of the attachment between the gateway and the VPC. Present only if a VPC is attached +* `vpc_id` - ID of an attached VPC.