Skip to content

Commit

Permalink
Merge pull request #18803 from farhanangullia/f-data_source_aws_subnets
Browse files Browse the repository at this point in the history
New data source: aws_subnets
  • Loading branch information
ewbankkit authored Aug 17, 2021
2 parents e8813c9 + 92b53bc commit 5fb3cd9
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/18803.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_subnets
```
69 changes: 69 additions & 0 deletions aws/data_source_aws_subnets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package aws

import (
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func dataSourceAwsSubnets() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsSubnetsRead,
Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"tags": tagsSchemaComputed(),

"ids": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}

func dataSourceAwsSubnetsRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn

input := &ec2.DescribeSubnetsInput{}

if tags, tagsOk := d.GetOk("tags"); tagsOk {
input.Filters = append(input.Filters, buildEC2TagFilterList(
keyvaluetags.New(tags.(map[string]interface{})).Ec2Tags(),
)...)
}

if filters, filtersOk := d.GetOk("filter"); filtersOk {
input.Filters = append(input.Filters,
buildAwsDataSourceFilters(filters.(*schema.Set))...)
}

if len(input.Filters) == 0 {
input.Filters = nil
}

var subnetIDs []*string
err := conn.DescribeSubnetsPages(input, func(page *ec2.DescribeSubnetsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, subnet := range page.Subnets {
subnetIDs = append(subnetIDs, subnet.SubnetId)
}

return !lastPage
})

if err != nil {
return fmt.Errorf("error reading Subnets: %w", err)
}

d.SetId(meta.(*AWSClient).region)
d.Set("ids", aws.StringValueSlice(subnetIDs))

return nil
}
198 changes: 198 additions & 0 deletions aws/data_source_aws_subnets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package aws

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceAwsSubnets_basic(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsSubnetsConfig(rName),
},
{
Config: testAccDataSourceAwsSubnetsConfigWithDataSource(rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.aws_subnets.selected", "ids.#", "4"),
resource.TestCheckResourceAttr("data.aws_subnets.private", "ids.#", "2"),
testCheckResourceAttrGreaterThanValue("data.aws_subnets.all", "ids.#", "0"),
resource.TestCheckResourceAttr("data.aws_subnets.none", "ids.#", "0"),
),
},
},
})
}

func TestAccDataSourceAwsSubnets_filter(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsSubnets_filter(rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.aws_subnets.test", "ids.#", "2"),
),
},
},
})
}

func testAccDataSourceAwsSubnetsConfig(rName string) string {
return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_vpc" "test" {
cidr_block = "172.16.0.0/16"
tags = {
Name = %[1]q
}
}
resource "aws_subnet" "test_public_a" {
vpc_id = aws_vpc.test.id
cidr_block = "172.16.123.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "%[1]s-public-a"
Tier = "Public"
}
}
resource "aws_subnet" "test_public_b" {
vpc_id = aws_vpc.test.id
cidr_block = "172.16.124.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "%[1]s-public-b"
Tier = "Public"
}
}
resource "aws_subnet" "test_private_a" {
vpc_id = aws_vpc.test.id
cidr_block = "172.16.125.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "%[1]s-private-a"
Tier = "Private"
}
}
resource "aws_subnet" "test_private_b" {
vpc_id = aws_vpc.test.id
cidr_block = "172.16.126.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
tags = {
Name = "%[1]s-private-b"
Tier = "Private"
}
}
`, rName))
}

func testAccDataSourceAwsSubnetsConfigWithDataSource(rName string) string {
return composeConfig(testAccDataSourceAwsSubnetsConfig(rName), `
data "aws_subnets" "selected" {
filter {
name = "vpc-id"
values = [aws_vpc.test.id]
}
}
data "aws_subnets" "private" {
filter {
name = "vpc-id"
values = [aws_vpc.test.id]
}
tags = {
Tier = "Private"
}
}
data "aws_subnets" "all" {}
data "aws_subnets" "none" {
filter {
name = "vpc-id"
values = [aws_vpc.test.id]
}
filter {
name = "cidr-block"
values = ["172.16.127.0/24"]
}
}
`)
}

func testAccDataSourceAwsSubnets_filter(rName string) string {
return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_vpc" "test" {
cidr_block = "172.16.0.0/16"
tags = {
Name = %[1]q
}
}
resource "aws_subnet" "test_a_one" {
vpc_id = aws_vpc.test.id
cidr_block = "172.16.1.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "%[1]s-a1"
}
}
resource "aws_subnet" "test_a_two" {
vpc_id = aws_subnet.test_b.vpc_id
cidr_block = "172.16.2.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "%[1]s-a2"
}
}
resource "aws_subnet" "test_b" {
vpc_id = aws_vpc.test.id
cidr_block = "172.16.3.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
tags = {
Name = "%[1]s-b"
}
}
data "aws_subnets" "test" {
filter {
name = "availabilityZone"
values = [aws_subnet.test_a_one.availability_zone]
}
filter {
name = "vpc-id"
values = [aws_subnet.test_a_two.vpc_id]
}
}
`, rName))
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ func Provider() *schema.Provider {
"aws_ssoadmin_permission_set": dataSourceAwsSsoAdminPermissionSet(),
"aws_storagegateway_local_disk": dataSourceAwsStorageGatewayLocalDisk(),
"aws_subnet": dataSourceAwsSubnet(),
"aws_subnets": dataSourceAwsSubnets(),
"aws_subnet_ids": dataSourceAwsSubnetIDs(),
"aws_transfer_server": dataSourceAwsTransferServer(),
"aws_vpcs": dataSourceAwsVpcs(),
Expand Down
86 changes: 86 additions & 0 deletions website/docs/d/subnets.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
subcategory: "VPC"
layout: "aws"
page_title: "AWS: aws_subnets"
description: |-
Get information about a set of subnets.
---

# Data Source: aws_subnets

This resource can be useful for getting back a set of subnet IDs.

## Example Usage

The following shows outputing all CIDR blocks for every subnet ID in a VPC.

```terraform
data "aws_subnets" "example" {
filter {
name = "vpc-id"
values = [var.vpc_id]
}
}
data "aws_subnet" "example" {
for_each = data.aws_subnets.example.ids
id = each.value
}
output "subnet_cidr_blocks" {
value = [for s in data.aws_subnet.example : s.cidr_block]
}
```

The following example retrieves a set of all subnets in a VPC with a custom
tag of `Tier` set to a value of "Private" so that the `aws_instance` resource
can loop through the subnets, putting instances across availability zones.

```terraform
data "aws_subnets" "private" {
filter {
name = "vpc-id"
values = [var.vpc_id]
}
tags = {
Tier = "Private"
}
}
resource "aws_instance" "app" {
for_each = data.aws_subnets.example.ids
ami = var.ami
instance_type = "t2.micro"
subnet_id = each.value
}
```

## Argument Reference

* `filter` - (Optional) Custom filter block as described below.
* `tags` - (Optional) A map of tags, each pair of which must exactly match
a pair on the desired subnets.

More complex filters can be expressed using one or more `filter` sub-blocks,
which take the following arguments:

* `name` - (Required) The name of the field to filter by, as defined by
[the underlying AWS API](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html).
For example, if matching against tag `Name`, use:

```terraform
data "aws_subnets" "selected" {
filter {
name = "tag:Name"
values = [""] # insert values here
}
}
```

* `values` - (Required) Set of values that are accepted for the given field.
Subnet IDs will be selected if any one of the given values match.

## Attributes Reference

* `ids` - A list of all the subnet ids found.

0 comments on commit 5fb3cd9

Please sign in to comment.