Skip to content

Commit

Permalink
Merge pull request #40459 from Volatus/feat/add-ipam-data-sources
Browse files Browse the repository at this point in the history
feat: add aws_vpc_ipam & aws_vpc_ipams data sources
  • Loading branch information
jar-b authored Jan 31, 2025
2 parents 9d0b4bc + ee17088 commit c9b5045
Show file tree
Hide file tree
Showing 8 changed files with 586 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .changelog/40459.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:new-data-source
aws_vpc_ipam
```

```release-note:new-data-source
aws_vpc_ipams
```
11 changes: 11 additions & 0 deletions internal/service/ec2/service_package_gen.go

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

148 changes: 148 additions & 0 deletions internal/service/ec2/vpc_ipam_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ec2

import (
"context"

awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/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_vpc_ipam", name="IPAM")
// @Tags
// @Testing(tagsTest=false)
func newVPCIPAMDataSource(context.Context) (datasource.DataSourceWithConfigure, error) {
return &dataSourceVPCIPAM{}, nil
}

const (
DSNameVPCIPAM = "IPAM Data Source"
)

type dataSourceVPCIPAM struct {
framework.DataSourceWithConfigure
}

func (d *dataSourceVPCIPAM) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
resp.TypeName = "aws_vpc_ipam"
}

func (d *dataSourceVPCIPAM) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
names.AttrARN: framework.ARNAttributeComputedOnly(),
"default_resource_discovery_association_id": schema.StringAttribute{
Computed: true,
},
"default_resource_discovery_id": schema.StringAttribute{
Computed: true,
},
names.AttrDescription: schema.StringAttribute{
Computed: true,
},
"enable_private_gua": schema.BoolAttribute{
Computed: true,
},
names.AttrID: schema.StringAttribute{
Required: true,
},
"ipam_region": schema.StringAttribute{
Computed: true,
},
"operating_regions": framework.DataSourceComputedListOfObjectAttribute[ipamOperatingRegionModel](ctx),
names.AttrOwnerID: schema.StringAttribute{
Computed: true,
},
"private_default_scope_id": schema.StringAttribute{
Computed: true,
},
"public_default_scope_id": schema.StringAttribute{
Computed: true,
},
"resource_discovery_association_count": schema.Int32Attribute{
Computed: true,
},
"scope_count": schema.Int32Attribute{
Computed: true,
},
names.AttrState: schema.StringAttribute{
CustomType: fwtypes.StringEnumType[awstypes.IpamState](),
Computed: true,
},
"state_message": schema.StringAttribute{
Computed: true,
},
names.AttrTags: tftags.TagsAttributeComputedOnly(),
"tier": schema.StringAttribute{
CustomType: fwtypes.StringEnumType[awstypes.IpamTier](),
Computed: true,
},
},
}
}

func (d *dataSourceVPCIPAM) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
conn := d.Meta().EC2Client(ctx)

var data dataSourceVPCIPAMModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

ipam, err := findIPAMByID(ctx, conn, data.IpamId.ValueString())
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.EC2, create.ErrActionReading, DSNameVPCIPAM, data.IpamId.String(), err),
err.Error(),
)
return
}

resp.Diagnostics.Append(flex.Flatten(ctx, ipam, &data)...)
if resp.Diagnostics.HasError() {
return
}

setTagsOut(ctx, ipam.Tags)

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

type dataSourceVPCIPAMSummaryModel struct {
Description types.String `tfsdk:"description"`
DefaultResourceDiscoveryAssociationId types.String `tfsdk:"default_resource_discovery_association_id"`
DefaultResourceDiscoveryId types.String `tfsdk:"default_resource_discovery_id"`
EnablePrivateGua types.Bool `tfsdk:"enable_private_gua"`
IpamArn types.String `tfsdk:"arn"`
IpamId types.String `tfsdk:"id"`
IpamRegion types.String `tfsdk:"ipam_region"`
OperatingRegions fwtypes.ListNestedObjectValueOf[ipamOperatingRegionModel] `tfsdk:"operating_regions"`
OwnerID types.String `tfsdk:"owner_id"`
PrivateDefaultScopeId types.String `tfsdk:"private_default_scope_id"`
PublicDefaultScopeId types.String `tfsdk:"public_default_scope_id"`
ResourceDiscoveryAssociationCount types.Int32 `tfsdk:"resource_discovery_association_count"`
ScopeCount types.Int32 `tfsdk:"scope_count"`
State fwtypes.StringEnum[awstypes.IpamState] `tfsdk:"state"`
StateMessage types.String `tfsdk:"state_message"`
Tier fwtypes.StringEnum[awstypes.IpamTier] `tfsdk:"tier"`
}

type dataSourceVPCIPAMModel struct {
dataSourceVPCIPAMSummaryModel
Tags tftags.Map `tfsdk:"tags"`
}

type ipamOperatingRegionModel struct {
RegionName types.String `tfsdk:"region_name"`
}
69 changes: 69 additions & 0 deletions internal/service/ec2/vpc_ipam_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ec2_test

import (
"testing"

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

func TestAccVPCIPAMDataSource_basic(t *testing.T) {
ctx := acctest.Context(t)
resourceName := "aws_vpc_ipam.test"
dataSourceName := "data.aws_vpc_ipam.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: acctest.CheckDestroyNoop,
Steps: []resource.TestStep{
{
Config: testAccVPCIPAMDataSourceConfig_basic(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrDescription, resourceName, names.AttrDescription),
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID),
resource.TestCheckResourceAttrPair(dataSourceName, "default_resource_discovery_id", resourceName, "default_resource_discovery_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "default_resource_discovery_association_id", resourceName, "default_resource_discovery_association_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "enable_private_gua", resourceName, "enable_private_gua"),
resource.TestCheckResourceAttrPair(dataSourceName, "operating_regions.0.region_name", resourceName, "operating_regions.0.region_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "private_default_scope_id", resourceName, "private_default_scope_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "public_default_scope_id", resourceName, "public_default_scope_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "scope_count", resourceName, "scope_count"),
resource.TestCheckResourceAttrPair(dataSourceName, "tier", resourceName, "tier"),
resource.TestCheckResourceAttrPair(dataSourceName, acctest.CtTagsPercent, resourceName, acctest.CtTagsPercent),
resource.TestCheckResourceAttrPair(dataSourceName, "tags.Test", resourceName, "tags.Test"),
),
},
},
})
}

func testAccVPCIPAMDataSourceConfig_basic() string {
return `
data "aws_region" "current" {}
resource "aws_vpc_ipam" "test" {
description = "My IPAM"
operating_regions {
region_name = data.aws_region.current.name
}
tags = {
Test = "Test"
}
}
data "aws_vpc_ipam" "test" {
id = aws_vpc_ipam.test.id
}
`
}
121 changes: 121 additions & 0 deletions internal/service/ec2/vpc_ipams_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ec2

import (
"context"

"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/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkDataSource("aws_vpc_ipams", name="IPAMs")
func newVPCIPAMsDataSource(context.Context) (datasource.DataSourceWithConfigure, error) {
return &dataSourceVPCIPAMs{}, nil
}

const (
DSNameVPCIPAMs = "IPAMs Data Source"
)

type dataSourceVPCIPAMs struct {
framework.DataSourceWithConfigure
}

func (d *dataSourceVPCIPAMs) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
resp.TypeName = "aws_vpc_ipams"
}

func (d *dataSourceVPCIPAMs) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"ipams": framework.DataSourceComputedListOfObjectAttribute[dataSourceVPCIPAMSummaryModel](ctx),
"ipam_ids": schema.ListAttribute{
Optional: true,
ElementType: types.StringType,
},
},
Blocks: map[string]schema.Block{
names.AttrFilter: schema.ListNestedBlock{
CustomType: fwtypes.NewListNestedObjectTypeOf[filterModel](ctx),
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
names.AttrName: schema.StringAttribute{
Required: true,
},
names.AttrValues: schema.SetAttribute{
CustomType: fwtypes.SetOfStringType,
Required: true,
},
},
},
},
},
}
}

func findVPCIPAMs(ctx context.Context, conn *ec2.Client, input *ec2.DescribeIpamsInput) ([]awstypes.Ipam, error) {
var output []awstypes.Ipam

pages := ec2.NewDescribeIpamsPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
if err != nil {
return nil, err
}
output = append(output, page.Ipams...)
}
return output, nil
}

func (d *dataSourceVPCIPAMs) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
conn := d.Meta().EC2Client(ctx)

var data dataSourceVPCIPAMsModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

input := ec2.DescribeIpamsInput{}
resp.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...)
if resp.Diagnostics.HasError() {
return
}

output, err := findVPCIPAMs(ctx, conn, &input)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.EC2, create.ErrActionReading, DSNameVPCIPAMs, "", err),
err.Error(),
)
return
}

resp.Diagnostics.Append(fwflex.Flatten(ctx, output, &data.Ipams, fwflex.WithFieldNamePrefix("ipam"))...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

type filterModel struct {
Name types.String `tfsdk:"name"`
Values fwtypes.SetOfString `tfsdk:"values"`
}

type dataSourceVPCIPAMsModel struct {
Ipams fwtypes.ListNestedObjectValueOf[dataSourceVPCIPAMSummaryModel] `tfsdk:"ipams"`
Filters fwtypes.ListNestedObjectValueOf[filterModel] `tfsdk:"filter"`
IpamIds types.List `tfsdk:"ipam_ids"`
}
Loading

0 comments on commit c9b5045

Please sign in to comment.