From 9c81e9debb19f759f35fd6f4c039bcdc586bff92 Mon Sep 17 00:00:00 2001 From: Matt Cooper Date: Tue, 3 Jul 2018 11:55:55 +1200 Subject: [PATCH 01/24] Add option to allow no results when querying for instances data --- aws/data_source_aws_instances.go | 8 +++++++- aws/data_source_aws_instances_test.go | 28 ++++++++++++++++++++++++++ website/docs/d/instances.html.markdown | 2 ++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_instances.go b/aws/data_source_aws_instances.go index e0b094e2042..ea8683be0ea 100644 --- a/aws/data_source_aws_instances.go +++ b/aws/data_source_aws_instances.go @@ -49,6 +49,11 @@ func dataSourceAwsInstances() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "allow_no_results": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, }, } } @@ -58,6 +63,7 @@ func dataSourceAwsInstancesRead(d *schema.ResourceData, meta interface{}) error filters, filtersOk := d.GetOk("filter") tags, tagsOk := d.GetOk("instance_tags") + allowNoResults := d.Get("allow_no_results").(bool) if !filtersOk && !tagsOk { return fmt.Errorf("One of filters or instance_tags must be assigned") @@ -107,7 +113,7 @@ func dataSourceAwsInstancesRead(d *schema.ResourceData, meta interface{}) error return err } - if len(instanceIds) < 1 { + if len(instanceIds) < 1 && allowNoResults == false { return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") } diff --git a/aws/data_source_aws_instances_test.go b/aws/data_source_aws_instances_test.go index a886e3b68af..5e25a5d27b8 100644 --- a/aws/data_source_aws_instances_test.go +++ b/aws/data_source_aws_instances_test.go @@ -59,6 +59,23 @@ func TestAccAWSInstancesDataSource_instance_state_names(t *testing.T) { }) } +func TestAccAWSInstancesDataSource_noResults(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccInstancesDataSourceConfig_noResults, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_instances.test", "ids.#", "0"), + resource.TestCheckResourceAttr("data.aws_instances.test", "private_ips.#", "0"), + resource.TestCheckResourceAttr("data.aws_instances.test", "public_ips.#", "0"), + ), + }, + }, + }) +} + const testAccInstancesDataSourceConfig_ids = ` data "aws_ami" "ubuntu" { most_recent = true @@ -167,3 +184,14 @@ data "aws_instances" "test" { } `, rInt) } + +const testAccInstancesDataSourceConfig_noResults = ` +data "aws_instances" "test" { + filter { + name = "instance-id" + values = ["does", "not", "exist"] + } + + allow_no_results = true +} +` diff --git a/website/docs/d/instances.html.markdown b/website/docs/d/instances.html.markdown index dd16fe7a70e..45b150abdd9 100644 --- a/website/docs/d/instances.html.markdown +++ b/website/docs/d/instances.html.markdown @@ -53,6 +53,8 @@ exactly match a pair on desired instances. several valid keys, for a full reference, check out [describe-instances in the AWS CLI reference][1]. +* `allow_no_results` - (Optional) Defaults to false. If true, empty lists could be returned for `ids`, `private_ips` and `public_ips`. This is useful when querying the count of ephemeral instances (e.g. managed via autoscaling group) which may not be created yet. + ## Attributes Reference * `ids` - IDs of instances found through the filter From 7b2fb0abc9be084de9d1e8218ae27e627fb99f1a Mon Sep 17 00:00:00 2001 From: "Prats, Jordi" Date: Wed, 20 Oct 2021 22:09:36 +0200 Subject: [PATCH 02/24] Return empty list when aws_security_groups doesnt match any SG --- .../ec2/security_groups_data_source.go | 4 --- .../ec2/security_groups_data_source_test.go | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/internal/service/ec2/security_groups_data_source.go b/internal/service/ec2/security_groups_data_source.go index f651645efb0..a3beae08d83 100644 --- a/internal/service/ec2/security_groups_data_source.go +++ b/internal/service/ec2/security_groups_data_source.go @@ -90,10 +90,6 @@ func dataSourceSecurityGroupsRead(d *schema.ResourceData, meta interface{}) erro req.NextToken = resp.NextToken } - if len(ids) < 1 { - return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") - } - log.Printf("[DEBUG] Found %d security groups via given filter: %s", len(ids), req) d.SetId(meta.(*conns.AWSClient).Region) diff --git a/internal/service/ec2/security_groups_data_source_test.go b/internal/service/ec2/security_groups_data_source_test.go index fba42a1bf1e..709d6af59f3 100644 --- a/internal/service/ec2/security_groups_data_source_test.go +++ b/internal/service/ec2/security_groups_data_source_test.go @@ -50,6 +50,26 @@ func TestAccEC2SecurityGroupsDataSource_filter(t *testing.T) { }) } +func TestAccDataSourceAwsSecurityGroups_empty(t *testing.T) { + rInt := acctest.RandInt() + dataSourceName := "data.aws_security_groups.empty" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsSecurityGroupsConfig_empty(rInt), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "vpc_ids.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "arns.#", "0"), + ), + }, + }, + }) +} + func testAccSecurityGroupsDataSourceConfig_tag(rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "test_tag" { @@ -111,3 +131,13 @@ data "aws_security_groups" "by_filter" { } `, rInt) } + +func testAccDataSourceAwsSecurityGroupsConfig_empty(rInt int) string { + return fmt.Sprintf(` +data "aws_security_groups" "empty" { + tags = { + Random = "%[1]d" + } +} +`, rInt) +} From ccb27a0ca70c563c038184bbc09e68053c8782bc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 11:08:12 -0500 Subject: [PATCH 03/24] Revert "Add option to allow no results when querying for instances data" This reverts commit 9c81e9debb19f759f35fd6f4c039bcdc586bff92. --- aws/data_source_aws_instances.go | 8 +------- aws/data_source_aws_instances_test.go | 28 -------------------------- website/docs/d/instances.html.markdown | 2 -- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/aws/data_source_aws_instances.go b/aws/data_source_aws_instances.go index ea8683be0ea..e0b094e2042 100644 --- a/aws/data_source_aws_instances.go +++ b/aws/data_source_aws_instances.go @@ -49,11 +49,6 @@ func dataSourceAwsInstances() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "allow_no_results": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, }, } } @@ -63,7 +58,6 @@ func dataSourceAwsInstancesRead(d *schema.ResourceData, meta interface{}) error filters, filtersOk := d.GetOk("filter") tags, tagsOk := d.GetOk("instance_tags") - allowNoResults := d.Get("allow_no_results").(bool) if !filtersOk && !tagsOk { return fmt.Errorf("One of filters or instance_tags must be assigned") @@ -113,7 +107,7 @@ func dataSourceAwsInstancesRead(d *schema.ResourceData, meta interface{}) error return err } - if len(instanceIds) < 1 && allowNoResults == false { + if len(instanceIds) < 1 { return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") } diff --git a/aws/data_source_aws_instances_test.go b/aws/data_source_aws_instances_test.go index 5e25a5d27b8..a886e3b68af 100644 --- a/aws/data_source_aws_instances_test.go +++ b/aws/data_source_aws_instances_test.go @@ -59,23 +59,6 @@ func TestAccAWSInstancesDataSource_instance_state_names(t *testing.T) { }) } -func TestAccAWSInstancesDataSource_noResults(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - Steps: []resource.TestStep{ - { - Config: testAccInstancesDataSourceConfig_noResults, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.aws_instances.test", "ids.#", "0"), - resource.TestCheckResourceAttr("data.aws_instances.test", "private_ips.#", "0"), - resource.TestCheckResourceAttr("data.aws_instances.test", "public_ips.#", "0"), - ), - }, - }, - }) -} - const testAccInstancesDataSourceConfig_ids = ` data "aws_ami" "ubuntu" { most_recent = true @@ -184,14 +167,3 @@ data "aws_instances" "test" { } `, rInt) } - -const testAccInstancesDataSourceConfig_noResults = ` -data "aws_instances" "test" { - filter { - name = "instance-id" - values = ["does", "not", "exist"] - } - - allow_no_results = true -} -` diff --git a/website/docs/d/instances.html.markdown b/website/docs/d/instances.html.markdown index 45b150abdd9..dd16fe7a70e 100644 --- a/website/docs/d/instances.html.markdown +++ b/website/docs/d/instances.html.markdown @@ -53,8 +53,6 @@ exactly match a pair on desired instances. several valid keys, for a full reference, check out [describe-instances in the AWS CLI reference][1]. -* `allow_no_results` - (Optional) Defaults to false. If true, empty lists could be returned for `ids`, `private_ips` and `public_ips`. This is useful when querying the count of ephemeral instances (e.g. managed via autoscaling group) which may not be created yet. - ## Attributes Reference * `ids` - IDs of instances found through the filter From 96fc7a0d4c581350629601c476bbdbf3aca74862 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 11:13:04 -0500 Subject: [PATCH 04/24] d/aws_security_groups: Alphabetize attributes. --- internal/service/ec2/security_groups_data_source.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/internal/service/ec2/security_groups_data_source.go b/internal/service/ec2/security_groups_data_source.go index a3beae08d83..b1e43501c7e 100644 --- a/internal/service/ec2/security_groups_data_source.go +++ b/internal/service/ec2/security_groups_data_source.go @@ -17,20 +17,19 @@ func DataSourceSecurityGroups() *schema.Resource { Read: dataSourceSecurityGroupsRead, Schema: map[string]*schema.Schema{ - "filter": DataSourceFiltersSchema(), - "tags": tftags.TagsSchemaComputed(), - - "ids": { + "arns": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "vpc_ids": { + "filter": DataSourceFiltersSchema(), + "ids": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "arns": { + "tags": tftags.TagsSchemaComputed(), + "vpc_ids": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, From 5ba86e7c7eb2f465ff60e9a746610f0192857452 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 11:34:00 -0500 Subject: [PATCH 05/24] d/aws_security_groups: Use `FindSecurityGroups`. Acceptance test output: % make testacc TESTS=TestAccEC2SecurityGroupsDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2SecurityGroupsDataSource_' -timeout 180m === RUN TestAccEC2SecurityGroupsDataSource_tag === PAUSE TestAccEC2SecurityGroupsDataSource_tag === RUN TestAccEC2SecurityGroupsDataSource_filter === PAUSE TestAccEC2SecurityGroupsDataSource_filter === RUN TestAccEC2SecurityGroupsDataSource_empty === PAUSE TestAccEC2SecurityGroupsDataSource_empty === CONT TestAccEC2SecurityGroupsDataSource_tag === CONT TestAccEC2SecurityGroupsDataSource_empty === CONT TestAccEC2SecurityGroupsDataSource_filter --- PASS: TestAccEC2SecurityGroupsDataSource_empty (12.98s) --- PASS: TestAccEC2SecurityGroupsDataSource_filter (29.08s) --- PASS: TestAccEC2SecurityGroupsDataSource_tag (29.57s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 34.934s --- .../ec2/security_groups_data_source.go | 79 ++++++----------- .../ec2/security_groups_data_source_test.go | 88 ++++++++++--------- 2 files changed, 74 insertions(+), 93 deletions(-) diff --git a/internal/service/ec2/security_groups_data_source.go b/internal/service/ec2/security_groups_data_source.go index b1e43501c7e..df49fdad6ab 100644 --- a/internal/service/ec2/security_groups_data_source.go +++ b/internal/service/ec2/security_groups_data_source.go @@ -2,7 +2,6 @@ package ec2 import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -40,71 +39,49 @@ func DataSourceSecurityGroups() *schema.Resource { func dataSourceSecurityGroupsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeSecurityGroupsInput{} - filters, filtersOk := d.GetOk("filter") - tags, tagsOk := d.GetOk("tags") + input := &ec2.DescribeSecurityGroupsInput{} - if !filtersOk && !tagsOk { - return fmt.Errorf("One of filters or tags must be assigned") - } - - if filtersOk { - req.Filters = append(req.Filters, - BuildFiltersDataSource(filters.(*schema.Set))...) - } - if tagsOk { - req.Filters = append(req.Filters, BuildTagFilterList( + if tags, tagsOk := d.GetOk("tags"); tagsOk { + input.Filters = append(input.Filters, BuildTagFilterList( Tags(tftags.New(tags.(map[string]interface{}))), )...) } - log.Printf("[DEBUG] Reading Security Groups with request: %s", req) - - var ids, vpcIds, arns []string - for { - resp, err := conn.DescribeSecurityGroups(req) - if err != nil { - return fmt.Errorf("error reading security groups: %w", err) - } - - for _, sg := range resp.SecurityGroups { - ids = append(ids, aws.StringValue(sg.GroupId)) - vpcIds = append(vpcIds, aws.StringValue(sg.VpcId)) - - arn := arn.ARN{ - Partition: meta.(*conns.AWSClient).Partition, - Service: ec2.ServiceName, - Region: meta.(*conns.AWSClient).Region, - AccountID: aws.StringValue(sg.OwnerId), - Resource: fmt.Sprintf("security-group/%s", aws.StringValue(sg.GroupId)), - }.String() - - arns = append(arns, arn) - } + if filters, filtersOk := d.GetOk("filter"); filtersOk { + input.Filters = append(input.Filters, + BuildFiltersDataSource(filters.(*schema.Set))...) + } - if resp.NextToken == nil { - break - } - req.NextToken = resp.NextToken + if len(input.Filters) == 0 { + input.Filters = nil } - log.Printf("[DEBUG] Found %d security groups via given filter: %s", len(ids), req) + output, err := FindSecurityGroups(conn, input) - d.SetId(meta.(*conns.AWSClient).Region) - - err := d.Set("ids", ids) if err != nil { - return err + return fmt.Errorf("error reading EC2 Security Groups: %w", err) } - if err = d.Set("vpc_ids", vpcIds); err != nil { - return fmt.Errorf("error setting vpc_ids: %s", err) + var arns, securityGroupIDs, vpcIDs []string + + for _, v := range output { + arn := arn.ARN{ + Partition: meta.(*conns.AWSClient).Partition, + Service: ec2.ServiceName, + Region: meta.(*conns.AWSClient).Region, + AccountID: aws.StringValue(v.OwnerId), + Resource: fmt.Sprintf("security-group/%s", aws.StringValue(v.GroupId)), + }.String() + arns = append(arns, arn) + securityGroupIDs = append(securityGroupIDs, aws.StringValue(v.GroupId)) + vpcIDs = append(vpcIDs, aws.StringValue(v.VpcId)) } - if err = d.Set("arns", arns); err != nil { - return fmt.Errorf("error setting arns: %s", err) - } + d.SetId(meta.(*conns.AWSClient).Region) + d.Set("arns", arns) + d.Set("ids", securityGroupIDs) + d.Set("vpc_ids", vpcIDs) return nil } diff --git a/internal/service/ec2/security_groups_data_source_test.go b/internal/service/ec2/security_groups_data_source_test.go index 709d6af59f3..803b3139f5d 100644 --- a/internal/service/ec2/security_groups_data_source_test.go +++ b/internal/service/ec2/security_groups_data_source_test.go @@ -11,19 +11,20 @@ import ( ) func TestAccEC2SecurityGroupsDataSource_tag(t *testing.T) { - rInt := sdkacctest.RandInt() - dataSourceName := "data.aws_security_groups.by_tag" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_security_groups.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), Providers: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccSecurityGroupsDataSourceConfig_tag(rInt), + Config: testAccSecurityGroupsDataSourceConfig_tag(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "arns.#", "3"), resource.TestCheckResourceAttr(dataSourceName, "ids.#", "3"), resource.TestCheckResourceAttr(dataSourceName, "vpc_ids.#", "3"), - resource.TestCheckResourceAttr(dataSourceName, "arns.#", "3"), ), }, }, @@ -31,113 +32,116 @@ func TestAccEC2SecurityGroupsDataSource_tag(t *testing.T) { } func TestAccEC2SecurityGroupsDataSource_filter(t *testing.T) { - rInt := sdkacctest.RandInt() - dataSourceName := "data.aws_security_groups.by_filter" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_security_groups.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), Providers: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccSecurityGroupsDataSourceConfig_filter(rInt), + Config: testAccSecurityGroupsDataSourceConfig_filter(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "ids.#", "3"), - resource.TestCheckResourceAttr(dataSourceName, "vpc_ids.#", "3"), - resource.TestCheckResourceAttr(dataSourceName, "arns.#", "3"), + resource.TestCheckResourceAttr(dataSourceName, "arns.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "vpc_ids.#", "1"), ), }, }, }) } -func TestAccDataSourceAwsSecurityGroups_empty(t *testing.T) { - rInt := acctest.RandInt() - dataSourceName := "data.aws_security_groups.empty" +func TestAccEC2SecurityGroupsDataSource_empty(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_security_groups.test" + resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), - Providers: testAccProviders, + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsSecurityGroupsConfig_empty(rInt), + Config: testAccDataSourceAwsSecurityGroupsConfig_empty(rName), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "arns.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "ids.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "vpc_ids.#", "0"), - resource.TestCheckResourceAttr(dataSourceName, "arns.#", "0"), ), }, }, }) } -func testAccSecurityGroupsDataSourceConfig_tag(rInt int) string { +func testAccSecurityGroupsDataSourceConfig_tag(rName string) string { return fmt.Sprintf(` -resource "aws_vpc" "test_tag" { +resource "aws_vpc" "test" { cidr_block = "172.16.0.0/16" tags = { - Name = "terraform-testacc-security-group-data-source" + Name = %[1]q } } resource "aws_security_group" "test" { count = 3 - vpc_id = aws_vpc.test_tag.id - name = "tf-%[1]d-${count.index}" + vpc_id = aws_vpc.test.id + name = "%[1]s-${count.index}" tags = { - Seed = "%[1]d" + Name = %[1]q } } -data "aws_security_groups" "by_tag" { +data "aws_security_groups" "test" { tags = { - Seed = aws_security_group.test[0].tags["Seed"] + Name = %[1]q } + + depends_on = [aws_security_group.test[0], aws_security_group.test[1], aws_security_group.test[2]] } -`, rInt) +`, rName) } -func testAccSecurityGroupsDataSourceConfig_filter(rInt int) string { +func testAccSecurityGroupsDataSourceConfig_filter(rName string) string { return fmt.Sprintf(` -resource "aws_vpc" "test_filter" { +resource "aws_vpc" "test" { cidr_block = "172.16.0.0/16" tags = { - Name = "terraform-testacc-security-group-data-source" + Name = %[1]q } } resource "aws_security_group" "test" { - count = 3 - vpc_id = aws_vpc.test_filter.id - name = "tf-%[1]d-${count.index}" + vpc_id = aws_vpc.test.id + name = %[1]q tags = { - Seed = "%[1]d" + Name = %[1]q } } -data "aws_security_groups" "by_filter" { +data "aws_security_groups" "test" { filter { name = "vpc-id" - values = [aws_vpc.test_filter.id] + values = [aws_vpc.test.id] } filter { name = "group-name" - values = ["tf-${aws_security_group.test[0].tags["Seed"]}-*"] + values = [aws_security_group.test.name] } } -`, rInt) +`, rName) } -func testAccDataSourceAwsSecurityGroupsConfig_empty(rInt int) string { +func testAccDataSourceAwsSecurityGroupsConfig_empty(rName string) string { return fmt.Sprintf(` -data "aws_security_groups" "empty" { +data "aws_security_groups" "test" { tags = { - Random = "%[1]d" + Name = %[1]q } } -`, rInt) +`, rName) } From 4d0c9e7db7a41e10ca0e8967e1eb2162f02b07c2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 11:38:17 -0500 Subject: [PATCH 06/24] Add CHANGELOG entry. --- .changelog/21219.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/21219.txt diff --git a/.changelog/21219.txt b/.changelog/21219.txt new file mode 100644 index 00000000000..2b6a3914ff6 --- /dev/null +++ b/.changelog/21219.txt @@ -0,0 +1,3 @@ +```release-note:note +data-source/aws_security_groups: If no security groups match the specified criteria an empty list is returned (previously an error was raised) +``` \ No newline at end of file From 47c49e7619e036810e20d9e6072825785279c769 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 12:08:12 -0500 Subject: [PATCH 07/24] Add and use 'FindInstances'. Acceptance test output: % make testacc TESTS=TestAccEC2Instance_instanceProfileChange PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2Instance_instanceProfileChange' -timeout 180m === RUN TestAccEC2Instance_instanceProfileChange === PAUSE TestAccEC2Instance_instanceProfileChange === CONT TestAccEC2Instance_instanceProfileChange --- PASS: TestAccEC2Instance_instanceProfileChange (313.72s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 317.907s --- internal/service/ec2/find.go | 72 +++++++++++++++++++++++++++++++--- internal/service/ec2/status.go | 6 +-- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 36d22abab64..1b983e8cc31 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -135,23 +135,85 @@ func FindHost(conn *ec2.EC2, input *ec2.DescribeHostsInput) (*ec2.Host, error) { return host, nil } -// FindInstanceByID looks up a Instance by ID. When not found, returns nil and potentially an API error. +func FindInstances(conn *ec2.EC2, input *ec2.DescribeInstancesInput) ([]*ec2.Instance, error) { + var output []*ec2.Instance + + err := conn.DescribeInstancesPages(input, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.Reservations { + if v != nil { + for _, v := range v.Instances { + if v != nil { + output = append(output, v) + } + } + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, ErrCodeInvalidInstanceIDNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindInstance(conn *ec2.EC2, input *ec2.DescribeInstancesInput) (*ec2.Instance, error) { + output, err := FindInstances(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + func FindInstanceByID(conn *ec2.EC2, id string) (*ec2.Instance, error) { input := &ec2.DescribeInstancesInput{ InstanceIds: aws.StringSlice([]string{id}), } - output, err := conn.DescribeInstances(input) + output, err := FindInstance(conn, input) if err != nil { return nil, err } - if output == nil || len(output.Reservations) == 0 || output.Reservations[0] == nil || len(output.Reservations[0].Instances) == 0 || output.Reservations[0].Instances[0] == nil { - return nil, nil + if state := aws.StringValue(output.State.Name); state == ec2.InstanceStateNameTerminated { + return nil, &resource.NotFoundError{ + Message: state, + LastRequest: input, + } } - return output.Reservations[0].Instances[0], nil + // Eventual consistency check. + if aws.StringValue(output.InstanceId) != id { + return nil, &resource.NotFoundError{ + LastRequest: input, + } + } + + return output, nil } func FindNetworkACL(conn *ec2.EC2, input *ec2.DescribeNetworkAclsInput) (*ec2.NetworkAcl, error) { diff --git a/internal/service/ec2/status.go b/internal/service/ec2/status.go index cd84b6d420b..6a4dc7edf45 100644 --- a/internal/service/ec2/status.go +++ b/internal/service/ec2/status.go @@ -218,7 +218,7 @@ func StatusInstanceIAMInstanceProfile(conn *ec2.EC2, id string) resource.StateRe return func() (interface{}, string, error) { instance, err := FindInstanceByID(conn, id) - if tfawserr.ErrCodeEquals(err, ErrCodeInvalidInstanceIDNotFound) { + if tfresource.NotFound(err) { return nil, "", nil } @@ -226,10 +226,6 @@ func StatusInstanceIAMInstanceProfile(conn *ec2.EC2, id string) resource.StateRe return nil, "", err } - if instance == nil { - return nil, "", nil - } - if instance.IamInstanceProfile == nil || instance.IamInstanceProfile.Arn == nil { return instance, "", nil } From b173816c0b69cd42c86b46557a23fc42d3244c1b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 12:35:24 -0500 Subject: [PATCH 08/24] d/aws_instances: Use 'FindInstances'. Acceptance test output: % make testacc TESTS=TestAccEC2InstancesDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2InstancesDataSource_' -timeout 180m === RUN TestAccEC2InstancesDataSource_basic === PAUSE TestAccEC2InstancesDataSource_basic === RUN TestAccEC2InstancesDataSource_tags === PAUSE TestAccEC2InstancesDataSource_tags === RUN TestAccEC2InstancesDataSource_instanceStateNames === PAUSE TestAccEC2InstancesDataSource_instanceStateNames === RUN TestAccEC2InstancesDataSource_empty === PAUSE TestAccEC2InstancesDataSource_empty === CONT TestAccEC2InstancesDataSource_basic === CONT TestAccEC2InstancesDataSource_instanceStateNames === CONT TestAccEC2InstancesDataSource_empty === CONT TestAccEC2InstancesDataSource_tags --- PASS: TestAccEC2InstancesDataSource_empty (13.42s) --- PASS: TestAccEC2InstancesDataSource_instanceStateNames (111.19s) --- PASS: TestAccEC2InstancesDataSource_basic (119.68s) --- PASS: TestAccEC2InstancesDataSource_tags (121.22s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 126.560s --- .changelog/5055.txt | 3 + internal/service/ec2/instances_data_source.go | 115 +++++++----------- .../service/ec2/instances_data_source_test.go | 34 +++++- 3 files changed, 77 insertions(+), 75 deletions(-) create mode 100644 .changelog/5055.txt diff --git a/.changelog/5055.txt b/.changelog/5055.txt new file mode 100644 index 00000000000..da9fa294d9c --- /dev/null +++ b/.changelog/5055.txt @@ -0,0 +1,3 @@ +```release-note:note +data-source/aws_instances: If no instances match the specified criteria an empty list is returned (previously an error was raised) +``` \ No newline at end of file diff --git a/internal/service/ec2/instances_data_source.go b/internal/service/ec2/instances_data_source.go index b318933eae9..bb12e16a4be 100644 --- a/internal/service/ec2/instances_data_source.go +++ b/internal/service/ec2/instances_data_source.go @@ -2,7 +2,6 @@ package ec2 import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" @@ -18,29 +17,21 @@ func DataSourceInstances() *schema.Resource { Read: dataSourceInstancesRead, Schema: map[string]*schema.Schema{ - "filter": DataSourceFiltersSchema(), + "filter": DataSourceFiltersSchema(), + "ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "instance_tags": tftags.TagsSchemaComputed(), "instance_state_names": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - ec2.InstanceStateNamePending, - ec2.InstanceStateNameRunning, - ec2.InstanceStateNameShuttingDown, - ec2.InstanceStateNameStopped, - ec2.InstanceStateNameStopping, - ec2.InstanceStateNameTerminated, - }, false), + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.InstanceStateName_Values(), false), }, }, - - "ids": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, "private_ips": { Type: schema.TypeList, Computed: true, @@ -58,75 +49,53 @@ func DataSourceInstances() *schema.Resource { func dataSourceInstancesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - filters, filtersOk := d.GetOk("filter") - tags, tagsOk := d.GetOk("instance_tags") - - if !filtersOk && !tagsOk { - return fmt.Errorf("One of filters or instance_tags must be assigned") + input := &ec2.DescribeInstancesInput{} + + if v, ok := d.GetOk("instance_state_names"); ok && v.(*schema.Set).Len() > 0 { + input.Filters = append(input.Filters, &ec2.Filter{ + Name: aws.String("instance-state-name"), + Values: flex.ExpandStringSet(v.(*schema.Set)), + }) + } else { + input.Filters = append(input.Filters, &ec2.Filter{ + Name: aws.String("instance-state-name"), + Values: aws.StringSlice([]string{ec2.InstanceStateNameRunning}), + }) } - instanceStateNames := []*string{aws.String(ec2.InstanceStateNameRunning)} - if v, ok := d.GetOk("instance_state_names"); ok && len(v.(*schema.Set).List()) > 0 { - instanceStateNames = flex.ExpandStringSet(v.(*schema.Set)) - } - params := &ec2.DescribeInstancesInput{ - Filters: []*ec2.Filter{ - { - Name: aws.String("instance-state-name"), - Values: instanceStateNames, - }, - }, + if tags, tagsOk := d.GetOk("instance_tags"); tagsOk { + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(tags.(map[string]interface{}))), + )...) } - if filtersOk { - params.Filters = append(params.Filters, + if filters, filtersOk := d.GetOk("filter"); filtersOk { + input.Filters = append(input.Filters, BuildFiltersDataSource(filters.(*schema.Set))...) } - if tagsOk { - params.Filters = append(params.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } - log.Printf("[DEBUG] Reading EC2 instances: %s", params) + output, err := FindInstances(conn, input) - var instanceIds, privateIps, publicIps []string - err := conn.DescribeInstancesPages(params, func(resp *ec2.DescribeInstancesOutput, lastPage bool) bool { - for _, res := range resp.Reservations { - for _, instance := range res.Instances { - instanceIds = append(instanceIds, *instance.InstanceId) - if instance.PrivateIpAddress != nil { - privateIps = append(privateIps, *instance.PrivateIpAddress) - } - if instance.PublicIpAddress != nil { - publicIps = append(publicIps, *instance.PublicIpAddress) - } - } - } - return !lastPage - }) if err != nil { - return err - } - - if len(instanceIds) < 1 { - return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") + return fmt.Errorf("error reading EC2 Instances: %w", err) } - log.Printf("[DEBUG] Found %d instances via given filter", len(instanceIds)) + var instanceIDs, privateIPs, publicIPs []string - d.SetId(meta.(*conns.AWSClient).Region) - - err = d.Set("ids", instanceIds) - if err != nil { - return err + for _, v := range output { + instanceIDs = append(instanceIDs, aws.StringValue(v.InstanceId)) + if privateIP := aws.StringValue(v.PrivateIpAddress); privateIP != "" { + privateIPs = append(privateIPs, privateIP) + } + if publicIP := aws.StringValue(v.PublicIpAddress); publicIP != "" { + publicIPs = append(publicIPs, publicIP) + } } - err = d.Set("private_ips", privateIps) - if err != nil { - return err - } + d.SetId(meta.(*conns.AWSClient).Region) + d.Set("ids", instanceIDs) + d.Set("private_ips", privateIPs) + d.Set("public_ips", publicIPs) - err = d.Set("public_ips", publicIps) - return err + return nil } diff --git a/internal/service/ec2/instances_data_source_test.go b/internal/service/ec2/instances_data_source_test.go index 9f4c2ca7887..9a0d7e9a6dd 100644 --- a/internal/service/ec2/instances_data_source_test.go +++ b/internal/service/ec2/instances_data_source_test.go @@ -67,6 +67,26 @@ func TestAccEC2InstancesDataSource_instanceStateNames(t *testing.T) { }) } +func TestAccEC2InstancesDataSource_empty(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccInstancesDataSourceConfig_empty(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_instances.test", "ids.#", "0"), + resource.TestCheckResourceAttr("data.aws_instances.test", "private_ips.#", "0"), + resource.TestCheckResourceAttr("data.aws_instances.test", "public_ips.#", "0"), + ), + }, + }, + }) +} + func testAccInstancesDataSourceConfig_ids(rName string) string { return acctest.ConfigCompose( acctest.ConfigLatestAmazonLinuxHvmEbsAmi(), @@ -78,7 +98,7 @@ resource "aws_instance" "test" { instance_type = data.aws_ec2_instance_type_offering.available.instance_type tags = { - Name = %q + Name = %[1]q } } @@ -129,7 +149,7 @@ resource "aws_instance" "test" { instance_type = data.aws_ec2_instance_type_offering.available.instance_type tags = { - Name = %q + Name = %[1]q } } @@ -143,3 +163,13 @@ data "aws_instances" "test" { } `, rName)) } + +func testAccInstancesDataSourceConfig_empty(rName string) string { + return fmt.Sprintf(` +data "aws_instances" "test" { + instance_tags = { + Name = %[1]q + } +} +`, rName) +} From 60127e23ac7f612d4b90af49df515f9ffa0a1183 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 14:41:22 -0500 Subject: [PATCH 09/24] d/aws_route_tables: Call 'FindRouteTables'. Acceptance test output: % make testacc TESTS=TestAccEC2RouteTablesDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2RouteTablesDataSource_' -timeout 180m === RUN TestAccEC2RouteTablesDataSource_basic === PAUSE TestAccEC2RouteTablesDataSource_basic === CONT TestAccEC2RouteTablesDataSource_basic --- PASS: TestAccEC2RouteTablesDataSource_basic (26.72s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 32.176s --- .changelog/21219.txt | 4 + internal/service/ec2/instances_data_source.go | 17 +-- .../service/ec2/route_tables_data_source.go | 51 +++---- .../ec2/route_tables_data_source_test.go | 136 ++++++------------ .../ec2/security_groups_data_source.go | 15 +- 5 files changed, 85 insertions(+), 138 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 2b6a3914ff6..9c3e46a19cb 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -1,3 +1,7 @@ ```release-note:note data-source/aws_security_groups: If no security groups match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_route_tables: The type of the `ids` attributes has changed from Set to List. If no route tables match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/instances_data_source.go b/internal/service/ec2/instances_data_source.go index bb12e16a4be..13dd3204753 100644 --- a/internal/service/ec2/instances_data_source.go +++ b/internal/service/ec2/instances_data_source.go @@ -63,15 +63,16 @@ func dataSourceInstancesRead(d *schema.ResourceData, meta interface{}) error { }) } - if tags, tagsOk := d.GetOk("instance_tags"); tagsOk { - input.Filters = append(input.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) + + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) - if filters, filtersOk := d.GetOk("filter"); filtersOk { - input.Filters = append(input.Filters, - BuildFiltersDataSource(filters.(*schema.Set))...) + if len(input.Filters) == 0 { + input.Filters = nil } output, err := FindInstances(conn, input) diff --git a/internal/service/ec2/route_tables_data_source.go b/internal/service/ec2/route_tables_data_source.go index f82bf0763ce..248f4b14bc2 100644 --- a/internal/service/ec2/route_tables_data_source.go +++ b/internal/service/ec2/route_tables_data_source.go @@ -2,7 +2,6 @@ package ec2 import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" @@ -15,22 +14,17 @@ func DataSourceRouteTables() *schema.Resource { return &schema.Resource{ Read: dataSourceRouteTablesRead, Schema: map[string]*schema.Schema{ - - "filter": CustomFiltersSchema(), - + "filter": DataSourceFiltersSchema(), + "ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "tags": tftags.TagsSchemaComputed(), - "vpc_id": { Type: schema.TypeString, Optional: true, }, - - "ids": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, }, } } @@ -38,45 +32,42 @@ func DataSourceRouteTables() *schema.Resource { func dataSourceRouteTablesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeRouteTablesInput{} + input := &ec2.DescribeRouteTablesInput{} if v, ok := d.GetOk("vpc_id"); ok { - req.Filters = BuildAttributeFilterList( + input.Filters = append(input.Filters, BuildAttributeFilterList( map[string]string{ "vpc-id": v.(string), }, - ) + )...) } - req.Filters = append(req.Filters, BuildTagFilterList( + input.Filters = append(input.Filters, BuildTagFilterList( Tags(tftags.New(d.Get("tags").(map[string]interface{}))), )...) - req.Filters = append(req.Filters, BuildCustomFilterList( + input.Filters = append(input.Filters, BuildFiltersDataSource( d.Get("filter").(*schema.Set), )...) - log.Printf("[DEBUG] DescribeRouteTables %s\n", req) - resp, err := conn.DescribeRouteTables(req) - if err != nil { - return err + if len(input.Filters) == 0 { + input.Filters = nil } - if resp == nil || len(resp.RouteTables) == 0 { - return fmt.Errorf("no matching route tables found for vpc with id %s", d.Get("vpc_id").(string)) + output, err := FindRouteTables(conn, input) + + if err != nil { + return fmt.Errorf("error reading EC2 Route Tables: %w", err) } - routeTables := make([]string, 0) + var routeTableIDs []string - for _, routeTable := range resp.RouteTables { - routeTables = append(routeTables, aws.StringValue(routeTable.RouteTableId)) + for _, v := range output { + routeTableIDs = append(routeTableIDs, aws.StringValue(v.RouteTableId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err = d.Set("ids", routeTables); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } + d.Set("ids", routeTableIDs) return nil } diff --git a/internal/service/ec2/route_tables_data_source_test.go b/internal/service/ec2/route_tables_data_source_test.go index 49a36f2c6bb..5fad885e1ab 100644 --- a/internal/service/ec2/route_tables_data_source_test.go +++ b/internal/service/ec2/route_tables_data_source_test.go @@ -11,7 +11,8 @@ import ( ) func TestAccEC2RouteTablesDataSource_basic(t *testing.T) { - rInt := sdkacctest.RandIntRange(0, 256) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), @@ -19,154 +20,107 @@ func TestAccEC2RouteTablesDataSource_basic(t *testing.T) { CheckDestroy: testAccCheckVpcDestroy, Steps: []resource.TestStep{ { - Config: testAccRouteTablesDataSourceConfig(rInt), - }, - { - Config: testAccRouteTablesWithDataSourceDataSourceConfig(rInt), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.aws_route_tables.test", "ids.#", "5"), - resource.TestCheckResourceAttr("data.aws_route_tables.private", "ids.#", "3"), - resource.TestCheckResourceAttr("data.aws_route_tables.test2", "ids.#", "1"), - resource.TestCheckResourceAttr("data.aws_route_tables.filter_test", "ids.#", "2"), + Config: testAccRouteTablesDataSourceConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_route_tables.by_vpc_id", "ids.#", "2"), // Add the default route table. + resource.TestCheckResourceAttr("data.aws_route_tables.by_tags", "ids.#", "2"), + resource.TestCheckResourceAttr("data.aws_route_tables.by_filter", "ids.#", "6"), // Add the default route tables. + resource.TestCheckResourceAttr("data.aws_route_tables.empty", "ids.#", "0"), ), }, }, }) } -func testAccRouteTablesWithDataSourceDataSourceConfig(rInt int) string { +func testAccRouteTablesDataSourceConfig(rName string) string { return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "172.%d.0.0/16" +resource "aws_vpc" "test1" { + cidr_block = "172.16.0.0/16" tags = { - Name = "terraform-testacc-route-tables-data-source" + Name = %[1]q } } resource "aws_vpc" "test2" { - cidr_block = "172.%d.0.0/16" + cidr_block = "172.16.0.0/16" tags = { - Name = "terraform-test2acc-route-tables-data-source" + Name = %[1]q } } -resource "aws_route_table" "test_public_a" { - vpc_id = aws_vpc.test.id +resource "aws_route_table" "test1_public" { + vpc_id = aws_vpc.test1.id tags = { - Name = "tf-acc-route-tables-data-source-public-a" + Name = %[1]q Tier = "Public" Component = "Frontend" } } -resource "aws_route_table" "test_private_a" { - vpc_id = aws_vpc.test.id +resource "aws_route_table" "test1_private1" { + vpc_id = aws_vpc.test1.id tags = { - Name = "tf-acc-route-tables-data-source-private-a" + Name = %[1]q Tier = "Private" Component = "Database" } } -resource "aws_route_table" "test_private_b" { - vpc_id = aws_vpc.test.id +resource "aws_route_table" "test1_private2" { + vpc_id = aws_vpc.test1.id tags = { - Name = "tf-acc-route-tables-data-source-private-b" + Name = %[1]q Tier = "Private" - Component = "Backend-1" + Component = "AppServer" } } -resource "aws_route_table" "test_private_c" { - vpc_id = aws_vpc.test.id - - tags = { - Name = "tf-acc-route-tables-data-source-private-c" - Tier = "Private" - Component = "Backend-2" - } -} - -data "aws_route_tables" "test" { - vpc_id = aws_vpc.test.id -} - -data "aws_route_tables" "test2" { +resource "aws_route_table" "test2_public" { vpc_id = aws_vpc.test2.id -} - -data "aws_route_tables" "private" { - vpc_id = aws_vpc.test.id tags = { - Tier = "Private" + Name = %[1]q + Tier = "Public" + Component = "Frontend" } } -data "aws_route_tables" "filter_test" { - vpc_id = aws_vpc.test.id +data "aws_route_tables" "by_vpc_id" { + vpc_id = aws_vpc.test2.id - filter { - name = "tag:Component" - values = ["Backend*"] - } + depends_on = [aws_route_table.test1_public, aws_route_table.test1_private1, aws_route_table.test1_private2, aws_route_table.test2_public] } -`, rInt, rInt) -} - -func testAccRouteTablesDataSourceConfig(rInt int) string { - return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "172.%d.0.0/16" +data "aws_route_tables" "by_tags" { tags = { - Name = "terraform-testacc-route-tables-data-source" + Tier = "Public" } -} - -resource "aws_route_table" "test_public_a" { - vpc_id = aws_vpc.test.id - tags = { - Name = "tf-acc-route-tables-data-source-public-a" - Tier = "Public" - Component = "Frontend" - } + depends_on = [aws_route_table.test1_public, aws_route_table.test1_private1, aws_route_table.test1_private2, aws_route_table.test2_public] } -resource "aws_route_table" "test_private_a" { - vpc_id = aws_vpc.test.id - - tags = { - Name = "tf-acc-route-tables-data-source-private-a" - Tier = "Private" - Component = "Database" +data "aws_route_tables" "by_filter" { + filter { + name = "vpc-id" + values = [aws_vpc.test1.id, aws_vpc.test2.id] } -} - -resource "aws_route_table" "test_private_b" { - vpc_id = aws_vpc.test.id - tags = { - Name = "tf-acc-route-tables-data-source-private-b" - Tier = "Private" - Component = "Backend-1" - } + depends_on = [aws_route_table.test1_public, aws_route_table.test1_private1, aws_route_table.test1_private2, aws_route_table.test2_public] } -resource "aws_route_table" "test_private_c" { - vpc_id = aws_vpc.test.id +data "aws_route_tables" "empty" { + vpc_id = aws_vpc.test2.id tags = { - Name = "tf-acc-route-tables-data-source-private-c" - Tier = "Private" - Component = "Backend-2" + Tier = "Private" } + + depends_on = [aws_route_table.test1_public, aws_route_table.test1_private1, aws_route_table.test1_private2, aws_route_table.test2_public] } -`, rInt) +`, rName) } diff --git a/internal/service/ec2/security_groups_data_source.go b/internal/service/ec2/security_groups_data_source.go index df49fdad6ab..8dc1cc5e8c5 100644 --- a/internal/service/ec2/security_groups_data_source.go +++ b/internal/service/ec2/security_groups_data_source.go @@ -42,16 +42,13 @@ func dataSourceSecurityGroupsRead(d *schema.ResourceData, meta interface{}) erro input := &ec2.DescribeSecurityGroupsInput{} - if tags, tagsOk := d.GetOk("tags"); tagsOk { - input.Filters = append(input.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) - if filters, filtersOk := d.GetOk("filter"); filtersOk { - input.Filters = append(input.Filters, - BuildFiltersDataSource(filters.(*schema.Set))...) - } + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) if len(input.Filters) == 0 { input.Filters = nil From d4f5d1556b8954b10da08baf11b0c43322f21a82 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 14:59:02 -0500 Subject: [PATCH 10/24] d/aws_network_interfaces: Allow empty results. Acceptance test output: % make testacc TESTS=TestAccEC2NetworkInterfacesDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2NetworkInterfacesDataSource_' -timeout 180m === RUN TestAccEC2NetworkInterfacesDataSource_filter === PAUSE TestAccEC2NetworkInterfacesDataSource_filter === RUN TestAccEC2NetworkInterfacesDataSource_tags === PAUSE TestAccEC2NetworkInterfacesDataSource_tags === RUN TestAccEC2NetworkInterfacesDataSource_empty === PAUSE TestAccEC2NetworkInterfacesDataSource_empty === CONT TestAccEC2NetworkInterfacesDataSource_filter === CONT TestAccEC2NetworkInterfacesDataSource_empty === CONT TestAccEC2NetworkInterfacesDataSource_tags --- PASS: TestAccEC2NetworkInterfacesDataSource_empty (10.98s) --- PASS: TestAccEC2NetworkInterfacesDataSource_tags (28.43s) --- PASS: TestAccEC2NetworkInterfacesDataSource_filter (28.45s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 32.493s --- .changelog/21219.txt | 4 +++ .../ec2/network_interfaces_data_source.go | 32 ++++++------------- .../network_interfaces_data_source_test.go | 29 +++++++++++++++++ .../service/ec2/route_tables_data_source.go | 1 + .../docs/d/network_interfaces.html.markdown | 2 +- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 9c3e46a19cb..a4a647a7813 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -4,4 +4,8 @@ data-source/aws_security_groups: If no security groups match the specified crite ```release-note:note data-source/aws_route_tables: The type of the `ids` attributes has changed from Set to List. If no route tables match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_network_interfaces: The type of the `ids` attributes has changed from Set to List. If no network interfaces match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/network_interfaces_data_source.go b/internal/service/ec2/network_interfaces_data_source.go index 129d92a48f5..fcbe3e8ecfb 100644 --- a/internal/service/ec2/network_interfaces_data_source.go +++ b/internal/service/ec2/network_interfaces_data_source.go @@ -1,7 +1,6 @@ package ec2 import ( - "errors" "fmt" "github.com/aws/aws-sdk-go/aws" @@ -14,13 +13,13 @@ import ( func DataSourceNetworkInterfaces() *schema.Resource { return &schema.Resource{ Read: dataSourceNetworkInterfacesRead, + Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), + "filter": DataSourceFiltersSchema(), "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "tags": tftags.TagsSchemaComputed(), }, @@ -32,17 +31,13 @@ func dataSourceNetworkInterfacesRead(d *schema.ResourceData, meta interface{}) e input := &ec2.DescribeNetworkInterfacesInput{} - if v, ok := d.GetOk("tags"); ok { - input.Filters = BuildTagFilterList( - Tags(tftags.New(v.(map[string]interface{}))), - ) - } + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) - if v, ok := d.GetOk("filter"); ok { - input.Filters = append(input.Filters, BuildCustomFilterList( - v.(*schema.Set), - )...) - } + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) if len(input.Filters) == 0 { input.Filters = nil @@ -56,19 +51,12 @@ func dataSourceNetworkInterfacesRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("error reading EC2 Network Interfaces: %w", err) } - if len(output) == 0 { - return errors.New("no matching network interfaces found") - } - for _, v := range output { networkInterfaceIDs = append(networkInterfaceIDs, aws.StringValue(v.NetworkInterfaceId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("ids", networkInterfaceIDs); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } + d.Set("ids", networkInterfaceIDs) return nil } diff --git a/internal/service/ec2/network_interfaces_data_source_test.go b/internal/service/ec2/network_interfaces_data_source_test.go index 81f7759999d..cb65c331c3b 100644 --- a/internal/service/ec2/network_interfaces_data_source_test.go +++ b/internal/service/ec2/network_interfaces_data_source_test.go @@ -48,6 +48,25 @@ func TestAccEC2NetworkInterfacesDataSource_tags(t *testing.T) { }) } +func TestAccEC2NetworkInterfacesDataSource_empty(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckVpcDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkInterfacesDataSourceConfig_Empty(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_network_interfaces.test", "ids.#", "0"), + ), + }, + }, + }) +} + func testAccNetworkInterfacesDataSourceConfig_Base(rName string) string { return fmt.Sprintf(` resource "aws_vpc" "test" { @@ -105,3 +124,13 @@ data "aws_network_interfaces" "test" { } `) } + +func testAccNetworkInterfacesDataSourceConfig_Empty(rName string) string { + return fmt.Sprintf(` +data "aws_network_interfaces" "test" { + tags = { + Name = %[1]q + } +} +`, rName) +} diff --git a/internal/service/ec2/route_tables_data_source.go b/internal/service/ec2/route_tables_data_source.go index 248f4b14bc2..1779aa1e74b 100644 --- a/internal/service/ec2/route_tables_data_source.go +++ b/internal/service/ec2/route_tables_data_source.go @@ -13,6 +13,7 @@ import ( func DataSourceRouteTables() *schema.Resource { return &schema.Resource{ Read: dataSourceRouteTablesRead, + Schema: map[string]*schema.Schema{ "filter": DataSourceFiltersSchema(), "ids": { diff --git a/website/docs/d/network_interfaces.html.markdown b/website/docs/d/network_interfaces.html.markdown index 0a5a6ec6c6b..fd0be09ca7f 100644 --- a/website/docs/d/network_interfaces.html.markdown +++ b/website/docs/d/network_interfaces.html.markdown @@ -68,5 +68,5 @@ which take the following arguments: ## Attributes Reference * `id` - AWS Region. -* `ids` - A list of all the network interface ids found. This data source will fail if none are found. +* `ids` - A list of all the network interface ids found. From e74f9163fe6af0bf8a0085191107e505966ca34a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 15:21:42 -0500 Subject: [PATCH 11/24] d/aws_network_acls: Use 'FindNetworkACLs'. Acceptance test output: % make testacc TESTS=TestAccEC2NetworkACLsDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2NetworkACLsDataSource_' -timeout 180m === RUN TestAccEC2NetworkACLsDataSource_basic === PAUSE TestAccEC2NetworkACLsDataSource_basic === RUN TestAccEC2NetworkACLsDataSource_filter === PAUSE TestAccEC2NetworkACLsDataSource_filter === RUN TestAccEC2NetworkACLsDataSource_tags === PAUSE TestAccEC2NetworkACLsDataSource_tags === RUN TestAccEC2NetworkACLsDataSource_vpcID === PAUSE TestAccEC2NetworkACLsDataSource_vpcID === RUN TestAccEC2NetworkACLsDataSource_empty === PAUSE TestAccEC2NetworkACLsDataSource_empty === CONT TestAccEC2NetworkACLsDataSource_basic === CONT TestAccEC2NetworkACLsDataSource_vpcID === CONT TestAccEC2NetworkACLsDataSource_empty === CONT TestAccEC2NetworkACLsDataSource_tags === CONT TestAccEC2NetworkACLsDataSource_filter --- PASS: TestAccEC2NetworkACLsDataSource_empty (12.47s) --- PASS: TestAccEC2NetworkACLsDataSource_basic (26.31s) --- PASS: TestAccEC2NetworkACLsDataSource_tags (26.82s) --- PASS: TestAccEC2NetworkACLsDataSource_filter (26.82s) --- PASS: TestAccEC2NetworkACLsDataSource_vpcID (26.82s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 30.300s --- .changelog/21219.txt | 4 + .../service/ec2/network_acls_data_source.go | 67 +++++---------- .../ec2/network_acls_data_source_test.go | 84 +++++++++++++------ website/docs/d/network_acls.html.markdown | 2 +- website/docs/d/route_tables.html.markdown | 2 +- website/docs/d/vpcs.html.markdown | 2 +- 6 files changed, 88 insertions(+), 73 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index a4a647a7813..445dea86e5e 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -8,4 +8,8 @@ data-source/aws_route_tables: The type of the `ids` attributes has changed from ```release-note:note data-source/aws_network_interfaces: The type of the `ids` attributes has changed from Set to List. If no network interfaces match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_network_acls: The type of the `ids` attributes has changed from Set to List. If no NACLs match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/network_acls_data_source.go b/internal/service/ec2/network_acls_data_source.go index 26bd24308a3..7de247c6ace 100644 --- a/internal/service/ec2/network_acls_data_source.go +++ b/internal/service/ec2/network_acls_data_source.go @@ -1,9 +1,7 @@ package ec2 import ( - "errors" "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" @@ -16,21 +14,17 @@ func DataSourceNetworkACLs() *schema.Resource { return &schema.Resource{ Read: dataSourceNetworkACLsRead, Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), - + "filter": DataSourceFiltersSchema(), + "ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, "tags": tftags.TagsSchemaComputed(), - "vpc_id": { Type: schema.TypeString, Optional: true, }, - - "ids": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, }, } } @@ -38,57 +32,42 @@ func DataSourceNetworkACLs() *schema.Resource { func dataSourceNetworkACLsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeNetworkAclsInput{} + input := &ec2.DescribeNetworkAclsInput{} if v, ok := d.GetOk("vpc_id"); ok { - req.Filters = BuildAttributeFilterList( + input.Filters = append(input.Filters, BuildAttributeFilterList( map[string]string{ "vpc-id": v.(string), }, - ) + )...) } - filters, filtersOk := d.GetOk("filter") - tags, tagsOk := d.GetOk("tags") + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) - if tagsOk { - req.Filters = append(req.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) - if filtersOk { - req.Filters = append(req.Filters, BuildCustomFilterList( - filters.(*schema.Set), - )...) + if len(input.Filters) == 0 { + input.Filters = nil } - if len(req.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. - req.Filters = nil - } + output, err := FindNetworkACLs(conn, input) - log.Printf("[DEBUG] DescribeNetworkAcls %s\n", req) - resp, err := conn.DescribeNetworkAcls(req) if err != nil { - return err - } - - if resp == nil || len(resp.NetworkAcls) == 0 { - return errors.New("no matching network ACLs found") + return fmt.Errorf("error reading EC2 Network ACLs: %w", err) } - networkAcls := make([]string, 0) + var naclIDs []string - for _, networkAcl := range resp.NetworkAcls { - networkAcls = append(networkAcls, aws.StringValue(networkAcl.NetworkAclId)) + for _, v := range output { + naclIDs = append(naclIDs, aws.StringValue(v.NetworkAclId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("ids", networkAcls); err != nil { - return fmt.Errorf("Error setting network ACL ids: %w", err) - } + d.Set("ids", naclIDs) return nil } diff --git a/internal/service/ec2/network_acls_data_source_test.go b/internal/service/ec2/network_acls_data_source_test.go index 59c76a62494..bb72cfbbc3b 100644 --- a/internal/service/ec2/network_acls_data_source_test.go +++ b/internal/service/ec2/network_acls_data_source_test.go @@ -2,7 +2,6 @@ package ec2_test import ( "fmt" - "regexp" "testing" "github.com/aws/aws-sdk-go/service/ec2" @@ -12,7 +11,7 @@ import ( ) func TestAccEC2NetworkACLsDataSource_basic(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_network_acls.test" resource.ParallelTest(t, resource.TestCase{ @@ -21,15 +20,10 @@ func TestAccEC2NetworkACLsDataSource_basic(t *testing.T) { Providers: acctest.Providers, CheckDestroy: testAccCheckVpcDestroy, Steps: []resource.TestStep{ - { - // Ensure at least 1 network ACL exists. We cannot use depends_on. - Config: testAccNetworkACLsDataSourceConfig_Base(rName), - }, { Config: testAccNetworkACLsDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - // At least 1 - resource.TestMatchResourceAttr(dataSourceName, "ids.#", regexp.MustCompile(`^[1-9][0-9]*`)), + testCheckResourceAttrGreaterThanValue(dataSourceName, "ids.#", "1"), ), }, }, @@ -37,7 +31,7 @@ func TestAccEC2NetworkACLsDataSource_basic(t *testing.T) { } func TestAccEC2NetworkACLsDataSource_filter(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_network_acls.test" resource.ParallelTest(t, resource.TestCase{ @@ -57,7 +51,7 @@ func TestAccEC2NetworkACLsDataSource_filter(t *testing.T) { } func TestAccEC2NetworkACLsDataSource_tags(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_network_acls.test" resource.ParallelTest(t, resource.TestCase{ @@ -77,7 +71,7 @@ func TestAccEC2NetworkACLsDataSource_tags(t *testing.T) { } func TestAccEC2NetworkACLsDataSource_vpcID(t *testing.T) { - rName := sdkacctest.RandString(5) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_network_acls.test" resource.ParallelTest(t, resource.TestCase{ @@ -97,59 +91,97 @@ func TestAccEC2NetworkACLsDataSource_vpcID(t *testing.T) { }) } +func TestAccEC2NetworkACLsDataSource_empty(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_network_acls.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckVpcDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkACLsDataSourceConfig_Empty(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "0"), + ), + }, + }, + }) +} + func testAccNetworkACLsDataSourceConfig_Base(rName string) string { return fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" tags = { - Name = "testacc-acl-%[1]s" + Name = %[1]q } } -resource "aws_network_acl" "acl" { +resource "aws_network_acl" "test" { count = 2 vpc_id = aws_vpc.test.id tags = { - Name = "testacc-acl-%[1]s" + Name = %[1]q } } `, rName) } func testAccNetworkACLsDataSourceConfig_basic(rName string) string { - return testAccNetworkACLsDataSourceConfig_Base(rName) + ` -data "aws_network_acls" "test" {} -` + return acctest.ConfigCompose(testAccNetworkACLsDataSourceConfig_Base(rName), ` +data "aws_network_acls" "test" { + depends_on = [aws_network_acl.test[0], aws_network_acl.test[1]] +} +`) } func testAccNetworkACLsDataSourceConfig_Filter(rName string) string { - return testAccNetworkACLsDataSourceConfig_Base(rName) + ` + return acctest.ConfigCompose(testAccNetworkACLsDataSourceConfig_Base(rName), ` data "aws_network_acls" "test" { filter { name = "network-acl-id" - values = [aws_network_acl.acl[0].id] + values = [aws_network_acl.test[0].id] } + + depends_on = [aws_network_acl.test[0], aws_network_acl.test[1]] } -` +`) } func testAccNetworkACLsDataSourceConfig_Tags(rName string) string { - return testAccNetworkACLsDataSourceConfig_Base(rName) + ` + return acctest.ConfigCompose(testAccNetworkACLsDataSourceConfig_Base(rName), ` data "aws_network_acls" "test" { tags = { - Name = aws_network_acl.acl[0].tags.Name + Name = aws_network_acl.test[0].tags.Name } + + depends_on = [aws_network_acl.test[0], aws_network_acl.test[1]] } -` +`) } func testAccNetworkACLsDataSourceConfig_VPCID(rName string) string { - return testAccNetworkACLsDataSourceConfig_Base(rName) + ` + return acctest.ConfigCompose(testAccNetworkACLsDataSourceConfig_Base(rName), ` data "aws_network_acls" "test" { - vpc_id = aws_network_acl.acl[0].vpc_id + vpc_id = aws_network_acl.test[0].vpc_id + + depends_on = [aws_network_acl.test[0], aws_network_acl.test[1]] +} +`) } -` + +func testAccNetworkACLsDataSourceConfig_Empty(rName string) string { + return fmt.Sprintf(` +data "aws_network_acls" "test" { + tags = { + Name = %[1]q + } +} +`, rName) } diff --git a/website/docs/d/network_acls.html.markdown b/website/docs/d/network_acls.html.markdown index 5a0d21ce824..e53660d74e7 100644 --- a/website/docs/d/network_acls.html.markdown +++ b/website/docs/d/network_acls.html.markdown @@ -70,4 +70,4 @@ which take the following arguments: ## Attributes Reference * `id` - AWS Region. -* `ids` - A list of all the network ACL ids found. This data source will fail if none are found. +* `ids` - A list of all the network ACL ids found. diff --git a/website/docs/d/route_tables.html.markdown b/website/docs/d/route_tables.html.markdown index e874be58192..37e88521e60 100644 --- a/website/docs/d/route_tables.html.markdown +++ b/website/docs/d/route_tables.html.markdown @@ -55,4 +55,4 @@ which take the following arguments: ## Attributes Reference * `id` - AWS Region. -* `ids` - A set of all the route table ids found. This data source will fail if none are found. +* `ids` - A set of all the route table ids found. diff --git a/website/docs/d/vpcs.html.markdown b/website/docs/d/vpcs.html.markdown index 56b26fcc18a..8cd42429528 100644 --- a/website/docs/d/vpcs.html.markdown +++ b/website/docs/d/vpcs.html.markdown @@ -71,4 +71,4 @@ which take the following arguments: ## Attributes Reference * `id` - AWS Region. -* `ids` - A list of all the VPC Ids found. This data source will fail if none are found. +* `ids` - A list of all the VPC Ids found. From 08c56596883e4266b785e878f2bb749ba49e233f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 16:24:13 -0500 Subject: [PATCH 12/24] d/aws_ec2_transit_gateway_route_tables: Add and use 'FindTransitGatewayRouteTables'. Acceptance test output: % make testacc TESTS=TestAccEC2TransitGatewayDataSource_serial/RouteTables PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2TransitGatewayDataSource_serial/RouteTables' -timeout 180m === RUN TestAccEC2TransitGatewayDataSource_serial === RUN TestAccEC2TransitGatewayDataSource_serial/RouteTables === RUN TestAccEC2TransitGatewayDataSource_serial/RouteTables/Empty === RUN TestAccEC2TransitGatewayDataSource_serial/RouteTables/basic === RUN TestAccEC2TransitGatewayDataSource_serial/RouteTables/Filter === RUN TestAccEC2TransitGatewayDataSource_serial/RouteTables/Tags --- PASS: TestAccEC2TransitGatewayDataSource_serial (1087.03s) --- PASS: TestAccEC2TransitGatewayDataSource_serial/RouteTables (1087.03s) --- PASS: TestAccEC2TransitGatewayDataSource_serial/RouteTables/Empty (10.24s) --- PASS: TestAccEC2TransitGatewayDataSource_serial/RouteTables/basic (351.09s) --- PASS: TestAccEC2TransitGatewayDataSource_serial/RouteTables/Filter (340.75s) --- PASS: TestAccEC2TransitGatewayDataSource_serial/RouteTables/Tags (384.95s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 1090.624s --- .changelog/21219.txt | 4 + internal/service/ec2/find.go | 31 +++++ .../ec2/transit_gateway_data_source_test.go | 4 +- ...ransit_gateway_route_tables_data_source.go | 43 ++----- ...t_gateway_route_tables_data_source_test.go | 118 ++++++++++++++++-- 5 files changed, 155 insertions(+), 45 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 445dea86e5e..a345b0fbe3a 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -12,4 +12,8 @@ data-source/aws_network_interfaces: The type of the `ids` attributes has changed ```release-note:note data-source/aws_network_acls: The type of the `ids` attributes has changed from Set to List. If no NACLs match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ec2_transit_gateway_route_tables: The type of the `ids` attributes has changed from Set to List. If no transit gateway route tables match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 1b983e8cc31..528600c9305 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1705,6 +1705,37 @@ func FindTransitGatewayAttachmentByID(conn *ec2.EC2, id string) (*ec2.TransitGat return output, nil } +func FindTransitGatewayRouteTables(conn *ec2.EC2, input *ec2.DescribeTransitGatewayRouteTablesInput) ([]*ec2.TransitGatewayRouteTable, error) { + var output []*ec2.TransitGatewayRouteTable + + err := conn.DescribeTransitGatewayRouteTablesPages(input, func(page *ec2.DescribeTransitGatewayRouteTablesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.TransitGatewayRouteTables { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, ErrCodeInvalidRouteTableIDNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} + func FindDHCPOptions(conn *ec2.EC2, input *ec2.DescribeDhcpOptionsInput) (*ec2.DhcpOptions, error) { output, err := FindDHCPOptionses(conn, input) diff --git a/internal/service/ec2/transit_gateway_data_source_test.go b/internal/service/ec2/transit_gateway_data_source_test.go index 9b3d5c800aa..8cafb8d3e57 100644 --- a/internal/service/ec2/transit_gateway_data_source_test.go +++ b/internal/service/ec2/transit_gateway_data_source_test.go @@ -31,7 +31,9 @@ func TestAccEC2TransitGatewayDataSource_serial(t *testing.T) { }, "RouteTables": { "basic": testAccTransitGatewayRouteTablesDataSource_basic, - "Filter": testAccTransitGatewayRouteTablesDataSource_Filter, + "Filter": testAccTransitGatewayRouteTablesDataSource_filter, + "Tags": testAccTransitGatewayRouteTablesDataSource_tags, + "Empty": testAccTransitGatewayRouteTablesDataSource_empty, }, "VpcAttachment": { "Filter": testAccTransitGatewayVPCAttachmentDataSource_Filter, diff --git a/internal/service/ec2/transit_gateway_route_tables_data_source.go b/internal/service/ec2/transit_gateway_route_tables_data_source.go index 294050898b8..be60da44063 100644 --- a/internal/service/ec2/transit_gateway_route_tables_data_source.go +++ b/internal/service/ec2/transit_gateway_route_tables_data_source.go @@ -15,15 +15,12 @@ func DataSourceTransitGatewayRouteTables() *schema.Resource { Read: dataSourceTransitGatewayRouteTablesRead, Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), - + "filter": DataSourceFiltersSchema(), "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, - "tags": tftags.TagsSchemaComputed(), }, } @@ -38,50 +35,28 @@ func dataSourceTransitGatewayRouteTablesRead(d *schema.ResourceData, meta interf Tags(tftags.New(d.Get("tags").(map[string]interface{}))), )...) - input.Filters = append(input.Filters, BuildCustomFilterList( + input.Filters = append(input.Filters, BuildFiltersDataSource( d.Get("filter").(*schema.Set), )...) if len(input.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. input.Filters = nil } - var transitGatewayRouteTables []*ec2.TransitGatewayRouteTable - - err := conn.DescribeTransitGatewayRouteTablesPages(input, func(page *ec2.DescribeTransitGatewayRouteTablesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - transitGatewayRouteTables = append(transitGatewayRouteTables, page.TransitGatewayRouteTables...) - - return !lastPage - }) + output, err := FindTransitGatewayRouteTables(conn, input) if err != nil { - return fmt.Errorf("error describing EC2 Transit Gateway Route Tables: %w", err) + return fmt.Errorf("error reading EC2 Transit Gateway Route Tables: %w", err) } - if len(transitGatewayRouteTables) == 0 { - return fmt.Errorf("no matching EC2 Transit Gateway Route Tables found") - } - - var ids []string - - for _, transitGatewayRouteTable := range transitGatewayRouteTables { - if transitGatewayRouteTable == nil { - continue - } + var routeTableIDs []string - ids = append(ids, aws.StringValue(transitGatewayRouteTable.TransitGatewayRouteTableId)) + for _, v := range output { + routeTableIDs = append(routeTableIDs, aws.StringValue(v.TransitGatewayRouteTableId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err = d.Set("ids", ids); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } + d.Set("ids", routeTableIDs) return nil } diff --git a/internal/service/ec2/transit_gateway_route_tables_data_source_test.go b/internal/service/ec2/transit_gateway_route_tables_data_source_test.go index 4cd8ab8a19b..96f0300b909 100644 --- a/internal/service/ec2/transit_gateway_route_tables_data_source_test.go +++ b/internal/service/ec2/transit_gateway_route_tables_data_source_test.go @@ -1,14 +1,17 @@ package ec2_test import ( + "fmt" "testing" "github.com/aws/aws-sdk-go/service/ec2" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/acctest" ) func testAccTransitGatewayRouteTablesDataSource_basic(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_ec2_transit_gateway_route_tables.test" resource.Test(t, resource.TestCase{ @@ -17,7 +20,7 @@ func testAccTransitGatewayRouteTablesDataSource_basic(t *testing.T) { Providers: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccTransitGatewayRouteTablesDataSourceConfig, + Config: testAccTransitGatewayRouteTablesDataSourceConfig(rName), Check: resource.ComposeTestCheckFunc( testCheckResourceAttrGreaterThanValue(dataSourceName, "ids.#", "0"), ), @@ -26,7 +29,8 @@ func testAccTransitGatewayRouteTablesDataSource_basic(t *testing.T) { }) } -func testAccTransitGatewayRouteTablesDataSource_Filter(t *testing.T) { +func testAccTransitGatewayRouteTablesDataSource_filter(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) dataSourceName := "data.aws_ec2_transit_gateway_route_tables.test" resource.Test(t, resource.TestCase{ @@ -35,32 +39,89 @@ func testAccTransitGatewayRouteTablesDataSource_Filter(t *testing.T) { Providers: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccTransitGatewayRouteTablesTransitGatewayFilterDataSource, + Config: testAccTransitGatewayRouteTablesTransitGatewayFilterDataSource(rName), Check: resource.ComposeTestCheckFunc( - testCheckResourceAttrGreaterThanValue(dataSourceName, "ids.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "2"), + ), + }, + }, + }) +} + +func testAccTransitGatewayRouteTablesDataSource_tags(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_ec2_transit_gateway_route_tables.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); testAccPreCheckTransitGateway(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccTransitGatewayRouteTablesTransitGatewayTagsDataSource(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "1"), + ), + }, + }, + }) +} + +func testAccTransitGatewayRouteTablesDataSource_empty(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_ec2_transit_gateway_route_tables.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); testAccPreCheckTransitGateway(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccTransitGatewayRouteTablesTransitGatewayEmptyDataSource(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "0"), ), }, }, }) } -const testAccTransitGatewayRouteTablesDataSourceConfig = ` -resource "aws_ec2_transit_gateway" "test" {} +func testAccTransitGatewayRouteTablesDataSourceConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_ec2_transit_gateway" "test" { + tags = { + Name = %[1]q + } +} resource "aws_ec2_transit_gateway_route_table" "test" { transit_gateway_id = aws_ec2_transit_gateway.test.id + + tags = { + Name = %[1]q + } } data "aws_ec2_transit_gateway_route_tables" "test" { depends_on = [aws_ec2_transit_gateway_route_table.test] } -` +`, rName) +} -const testAccTransitGatewayRouteTablesTransitGatewayFilterDataSource = ` -resource "aws_ec2_transit_gateway" "test" {} +func testAccTransitGatewayRouteTablesTransitGatewayFilterDataSource(rName string) string { + return fmt.Sprintf(` +resource "aws_ec2_transit_gateway" "test" { + tags = { + Name = %[1]q + } +} resource "aws_ec2_transit_gateway_route_table" "test" { transit_gateway_id = aws_ec2_transit_gateway.test.id + + tags = { + Name = %[1]q + } } data "aws_ec2_transit_gateway_route_tables" "test" { @@ -71,4 +132,41 @@ data "aws_ec2_transit_gateway_route_tables" "test" { depends_on = [aws_ec2_transit_gateway_route_table.test] } -` +`, rName) +} + +func testAccTransitGatewayRouteTablesTransitGatewayTagsDataSource(rName string) string { + return fmt.Sprintf(` +resource "aws_ec2_transit_gateway" "test" { + tags = { + Name = %[1]q + } +} + +resource "aws_ec2_transit_gateway_route_table" "test" { + transit_gateway_id = aws_ec2_transit_gateway.test.id + + tags = { + Name = %[1]q + } +} + +data "aws_ec2_transit_gateway_route_tables" "test" { + tags = { + Name = %[1]q + } + + depends_on = [aws_ec2_transit_gateway_route_table.test] +} +`, rName) +} + +func testAccTransitGatewayRouteTablesTransitGatewayEmptyDataSource(rName string) string { + return fmt.Sprintf(` +data "aws_ec2_transit_gateway_route_tables" "test" { + tags = { + Name = %[1]q + } +} +`, rName) +} From 6c8463771588fca1aa74f5ac19110f9aca81b857 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 16:46:12 -0500 Subject: [PATCH 13/24] d/aws_coip_pools: Add and use 'FindCOIPPools'. Acceptance test output: % aws ec2 describe-coip-pools --pool-ids ipv4pool-coip-123a45678b0001234 An error occurred (InvalidPoolID.NotFound) when calling the DescribeCoipPools operation: The pool ID 'ipv4pool-coip-123a45678b0001234' does not exist. ewbankkit@ewbankkit-C02F408DML85 terraform-provider-aws % make testacc TESTS=TestAccEC2CoIPPoolsDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2CoIPPoolsDataSource_' -timeout 180m === RUN TestAccEC2CoIPPoolsDataSource_basic === PAUSE TestAccEC2CoIPPoolsDataSource_basic === RUN TestAccEC2CoIPPoolsDataSource_filter === PAUSE TestAccEC2CoIPPoolsDataSource_filter === CONT TestAccEC2CoIPPoolsDataSource_basic === CONT TestAccEC2CoIPPoolsDataSource_filter acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2CoIPPoolsDataSource_filter (1.36s) === CONT TestAccEC2CoIPPoolsDataSource_basic acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2CoIPPoolsDataSource_basic (1.53s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 5.178s --- .changelog/21219.txt | 4 ++ .../service/ec2/coip_pools_data_source.go | 65 ++++++------------- internal/service/ec2/errors.go | 1 + internal/service/ec2/find.go | 49 ++++++++++++++ 4 files changed, 73 insertions(+), 46 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index a345b0fbe3a..25df856ea6d 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -16,4 +16,8 @@ data-source/aws_network_acls: The type of the `ids` attributes has changed from ```release-note:note data-source/aws_ec2_transit_gateway_route_tables: The type of the `ids` attributes has changed from Set to List. If no transit gateway route tables match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ec2_coip_pools: The type of the `pool_ids` attributes has changed from Set to List. If no COIP pools match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/coip_pools_data_source.go b/internal/service/ec2/coip_pools_data_source.go index e2d35941279..1c8a2848afd 100644 --- a/internal/service/ec2/coip_pools_data_source.go +++ b/internal/service/ec2/coip_pools_data_source.go @@ -13,17 +13,15 @@ import ( func DataSourceCoIPPools() *schema.Resource { return &schema.Resource{ Read: dataSourceCoIPPoolsRead, - Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), - - "tags": tftags.TagsSchemaComputed(), + Schema: map[string]*schema.Schema{ + "filter": DataSourceFiltersSchema(), "pool_ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, + "tags": tftags.TagsSchemaComputed(), }, } } @@ -31,59 +29,34 @@ func DataSourceCoIPPools() *schema.Resource { func dataSourceCoIPPoolsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeCoipPoolsInput{} - - if tags, tagsOk := d.GetOk("tags"); tagsOk { - req.Filters = append(req.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } - - if filters, filtersOk := d.GetOk("filter"); filtersOk { - req.Filters = append(req.Filters, BuildCustomFilterList( - filters.(*schema.Set), - )...) - } - if len(req.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. - req.Filters = nil - } + input := &ec2.DescribeCoipPoolsInput{} - var coipPools []*ec2.CoipPool + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) - err := conn.DescribeCoipPoolsPages(req, func(page *ec2.DescribeCoipPoolsOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) - coipPools = append(coipPools, page.CoipPools...) + if len(input.Filters) == 0 { + input.Filters = nil + } - return !lastPage - }) + output, err := FindCOIPPools(conn, input) if err != nil { - return fmt.Errorf("error describing EC2 COIP Pools: %w", err) - } - - if len(coipPools) == 0 { - return fmt.Errorf("no matching EC2 COIP Pools found") + return fmt.Errorf("error reading EC2 COIP Pools: %w", err) } var poolIDs []string - for _, coipPool := range coipPools { - if coipPool == nil { - continue - } - - poolIDs = append(poolIDs, aws.StringValue(coipPool.PoolId)) + for _, v := range output { + poolIDs = append(poolIDs, aws.StringValue(v.PoolId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("pool_ids", poolIDs); err != nil { - return fmt.Errorf("error setting pool_ids: %w", err) - } + d.Set("pool_ids", poolIDs) return nil } diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index 32325b66232..82475d96051 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -40,6 +40,7 @@ const ( ErrCodeInvalidPermissionMalformed = "InvalidPermission.Malformed" ErrCodeInvalidPermissionNotFound = "InvalidPermission.NotFound" ErrCodeInvalidPlacementGroupUnknown = "InvalidPlacementGroup.Unknown" + ErrCodeInvalidPoolIDNotFound = "InvalidPoolID.NotFound" ErrCodeInvalidPrefixListIDNotFound = "InvalidPrefixListID.NotFound" ErrCodeInvalidRouteNotFound = "InvalidRoute.NotFound" ErrCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 528600c9305..31c8169e1f7 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -79,6 +79,55 @@ func FindClientVPNRouteByID(conn *ec2.EC2, routeID string) (*ec2.DescribeClientV return FindClientVPNRoute(conn, endpointID, targetSubnetID, destinationCidr) } +func FindCOIPPools(conn *ec2.EC2, input *ec2.DescribeCoipPoolsInput) ([]*ec2.CoipPool, error) { + var output []*ec2.CoipPool + + err := conn.DescribeCoipPoolsPages(input, func(page *ec2.DescribeCoipPoolsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.CoipPools { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, ErrCodeInvalidPoolIDNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindCOIPPool(conn *ec2.EC2, input *ec2.DescribeCoipPoolsInput) (*ec2.CoipPool, error) { + output, err := FindCOIPPools(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + func FindHostByID(conn *ec2.EC2, id string) (*ec2.Host, error) { input := &ec2.DescribeHostsInput{ HostIds: aws.StringSlice([]string{id}), From 7055c0f9feffb80b46fc24e9a02d8f873ceaf190 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 25 Jan 2022 16:57:50 -0500 Subject: [PATCH 14/24] d/aws_ec2_local_gateway_route_tables: Add and use 'FindLocalGatewayRouteTables'. Acceptance test output: % make testacc TESTS=TestAccEC2LocalGatewayRouteTablesDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2LocalGatewayRouteTablesDataSource_' -timeout 180m === RUN TestAccEC2LocalGatewayRouteTablesDataSource_basic === PAUSE TestAccEC2LocalGatewayRouteTablesDataSource_basic === RUN TestAccEC2LocalGatewayRouteTablesDataSource_filter === PAUSE TestAccEC2LocalGatewayRouteTablesDataSource_filter === CONT TestAccEC2LocalGatewayRouteTablesDataSource_basic === CONT TestAccEC2LocalGatewayRouteTablesDataSource_filter === CONT TestAccEC2LocalGatewayRouteTablesDataSource_basic acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2LocalGatewayRouteTablesDataSource_basic (2.31s) === CONT TestAccEC2LocalGatewayRouteTablesDataSource_filter acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2LocalGatewayRouteTablesDataSource_filter (8.82s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 12.555s --- .changelog/21219.txt | 4 ++ internal/service/ec2/find.go | 42 +++++++++++++++ .../local_gateway_route_tables_data_source.go | 53 ++++++------------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 25df856ea6d..06537a702d6 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -20,4 +20,8 @@ data-source/aws_ec2_transit_gateway_route_tables: The type of the `ids` attribut ```release-note:note data-source/aws_ec2_coip_pools: The type of the `pool_ids` attributes has changed from Set to List. If no COIP pools match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ec2_local_gateway_route_tables: The type of the `ids` attributes has changed from Set to List. If no local gateway route tables match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 31c8169e1f7..2152ec412f6 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -265,6 +265,48 @@ func FindInstanceByID(conn *ec2.EC2, id string) (*ec2.Instance, error) { return output, nil } +func FindLocalGatewayRouteTables(conn *ec2.EC2, input *ec2.DescribeLocalGatewayRouteTablesInput) ([]*ec2.LocalGatewayRouteTable, error) { + var output []*ec2.LocalGatewayRouteTable + + err := conn.DescribeLocalGatewayRouteTablesPages(input, func(page *ec2.DescribeLocalGatewayRouteTablesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.LocalGatewayRouteTables { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindLocalGatewayRouteTable(conn *ec2.EC2, input *ec2.DescribeLocalGatewayRouteTablesInput) (*ec2.LocalGatewayRouteTable, error) { + output, err := FindLocalGatewayRouteTables(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + func FindNetworkACL(conn *ec2.EC2, input *ec2.DescribeNetworkAclsInput) (*ec2.NetworkAcl, error) { output, err := FindNetworkACLs(conn, input) diff --git a/internal/service/ec2/local_gateway_route_tables_data_source.go b/internal/service/ec2/local_gateway_route_tables_data_source.go index d16d24e4ec4..d559e69942d 100644 --- a/internal/service/ec2/local_gateway_route_tables_data_source.go +++ b/internal/service/ec2/local_gateway_route_tables_data_source.go @@ -13,17 +13,15 @@ import ( func DataSourceLocalGatewayRouteTables() *schema.Resource { return &schema.Resource{ Read: dataSourceLocalGatewayRouteTablesRead, + Schema: map[string]*schema.Schema{ "filter": CustomFiltersSchema(), - - "tags": tftags.TagsSchemaComputed(), - "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, + "tags": tftags.TagsSchemaComputed(), }, } } @@ -31,55 +29,34 @@ func DataSourceLocalGatewayRouteTables() *schema.Resource { func dataSourceLocalGatewayRouteTablesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeLocalGatewayRouteTablesInput{} + input := &ec2.DescribeLocalGatewayRouteTablesInput{} - req.Filters = append(req.Filters, BuildTagFilterList( + input.Filters = append(input.Filters, BuildTagFilterList( Tags(tftags.New(d.Get("tags").(map[string]interface{}))), )...) - req.Filters = append(req.Filters, BuildCustomFilterList( + input.Filters = append(input.Filters, BuildFiltersDataSource( d.Get("filter").(*schema.Set), )...) - if len(req.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. - req.Filters = nil - } - - var localGatewayRouteTables []*ec2.LocalGatewayRouteTable - err := conn.DescribeLocalGatewayRouteTablesPages(req, func(page *ec2.DescribeLocalGatewayRouteTablesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - localGatewayRouteTables = append(localGatewayRouteTables, page.LocalGatewayRouteTables...) + if len(input.Filters) == 0 { + input.Filters = nil + } - return !lastPage - }) + output, err := FindLocalGatewayRouteTables(conn, input) if err != nil { - return fmt.Errorf("error describing EC2 Local Gateway Route Tables: %w", err) - } - - if len(localGatewayRouteTables) == 0 { - return fmt.Errorf("no matching EC2 Local Gateway Route Tables found") + return fmt.Errorf("error reading EC2 Local Gateway Route Tables: %w", err) } - var ids []string + var routeTableIDs []string - for _, localGatewayRouteTable := range localGatewayRouteTables { - if localGatewayRouteTable == nil { - continue - } - - ids = append(ids, aws.StringValue(localGatewayRouteTable.LocalGatewayRouteTableId)) + for _, v := range output { + routeTableIDs = append(routeTableIDs, aws.StringValue(v.LocalGatewayRouteTableId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("ids", ids); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } + d.Set("ids", routeTableIDs) return nil } From 1f6aa0ef26feed18f061745048f5e738fffd150d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 08:42:56 -0500 Subject: [PATCH 15/24] d/aws_ec2_local_gateway_virtual_interface_groups: Add and use 'FindLocalGatewayVirtualInterfaceGroups'. Acceptance test output: % make testacc TESTS=TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_' -timeout 180m === RUN TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_basic === PAUSE TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_basic === RUN TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_filter === PAUSE TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_filter === RUN TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_tags === PAUSE TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_tags === CONT TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_basic === CONT TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_tags === CONT TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_filter acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_filter (1.40s) === CONT TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_basic acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_basic (8.10s) === CONT TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_tags acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2LocalGatewayVirtualInterfaceGroupsDataSource_tags (8.12s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 14.867s --- .changelog/21219.txt | 16 ++++--- internal/service/ec2/find.go | 42 ++++++++++++++++ ...ay_virtual_interface_groups_data_source.go | 48 +++++-------------- 3 files changed, 64 insertions(+), 42 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 06537a702d6..f05107e2ca4 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -3,25 +3,29 @@ data-source/aws_security_groups: If no security groups match the specified crite ``` ```release-note:note -data-source/aws_route_tables: The type of the `ids` attributes has changed from Set to List. If no route tables match the specified criteria an empty list is returned (previously an error was raised) +data-source/aws_route_tables: The type of the `ids` attribute has changed from Set to List. If no route tables match the specified criteria an empty list is returned (previously an error was raised) ``` ```release-note:note -data-source/aws_network_interfaces: The type of the `ids` attributes has changed from Set to List. If no network interfaces match the specified criteria an empty list is returned (previously an error was raised) +data-source/aws_network_interfaces: The type of the `ids` attribute has changed from Set to List. If no network interfaces match the specified criteria an empty list is returned (previously an error was raised) ``` ```release-note:note -data-source/aws_network_acls: The type of the `ids` attributes has changed from Set to List. If no NACLs match the specified criteria an empty list is returned (previously an error was raised) +data-source/aws_network_acls: The type of the `ids` attribute has changed from Set to List. If no NACLs match the specified criteria an empty list is returned (previously an error was raised) ``` ```release-note:note -data-source/aws_ec2_transit_gateway_route_tables: The type of the `ids` attributes has changed from Set to List. If no transit gateway route tables match the specified criteria an empty list is returned (previously an error was raised) +data-source/aws_ec2_transit_gateway_route_tables: The type of the `ids` attribute has changed from Set to List. If no transit gateway route tables match the specified criteria an empty list is returned (previously an error was raised) ``` ```release-note:note -data-source/aws_ec2_coip_pools: The type of the `pool_ids` attributes has changed from Set to List. If no COIP pools match the specified criteria an empty list is returned (previously an error was raised) +data-source/aws_ec2_coip_pools: The type of the `pool_ids` attribute has changed from Set to List. If no COIP pools match the specified criteria an empty list is returned (previously an error was raised) ``` ```release-note:note -data-source/aws_ec2_local_gateway_route_tables: The type of the `ids` attributes has changed from Set to List. If no local gateway route tables match the specified criteria an empty list is returned (previously an error was raised) +data-source/aws_ec2_local_gateway_route_tables: The type of the `ids` attribute has changed from Set to List. If no local gateway route tables match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ec2_local_gateway_virtual_interface_groups: The type of the `ids` and `local_gateway_virtual_interface_ids` attributes has changed from Set to List. If no local gateway virtual interface groups match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 2152ec412f6..ff236261d4d 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -307,6 +307,48 @@ func FindLocalGatewayRouteTable(conn *ec2.EC2, input *ec2.DescribeLocalGatewayRo return output[0], nil } +func FindLocalGatewayVirtualInterfaceGroups(conn *ec2.EC2, input *ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput) ([]*ec2.LocalGatewayVirtualInterfaceGroup, error) { + var output []*ec2.LocalGatewayVirtualInterfaceGroup + + err := conn.DescribeLocalGatewayVirtualInterfaceGroupsPages(input, func(page *ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.LocalGatewayVirtualInterfaceGroups { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindLocalGatewayVirtualInterfaceGroup(conn *ec2.EC2, input *ec2.DescribeLocalGatewayVirtualInterfaceGroupsInput) (*ec2.LocalGatewayVirtualInterfaceGroup, error) { + output, err := FindLocalGatewayVirtualInterfaceGroups(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + func FindNetworkACL(conn *ec2.EC2, input *ec2.DescribeNetworkAclsInput) (*ec2.NetworkAcl, error) { output, err := FindNetworkACLs(conn, input) diff --git a/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go b/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go index 7a61ecbe88d..54ef39655ba 100644 --- a/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go +++ b/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go @@ -3,6 +3,7 @@ package ec2 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/hashicorp/terraform-provider-aws/internal/conns" @@ -16,12 +17,12 @@ func DataSourceLocalGatewayVirtualInterfaceGroups() *schema.Resource { Schema: map[string]*schema.Schema{ "filter": CustomFiltersSchema(), "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "local_gateway_virtual_interface_ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -39,55 +40,30 @@ func dataSourceLocalGatewayVirtualInterfaceGroupsRead(d *schema.ResourceData, me Tags(tftags.New(d.Get("tags").(map[string]interface{}))), )...) - input.Filters = append(input.Filters, BuildCustomFilterList( + input.Filters = append(input.Filters, BuildFiltersDataSource( d.Get("filter").(*schema.Set), )...) if len(input.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. input.Filters = nil } - var localGatewayVirtualInterfaceGroups []*ec2.LocalGatewayVirtualInterfaceGroup - - err := conn.DescribeLocalGatewayVirtualInterfaceGroupsPages(input, func(page *ec2.DescribeLocalGatewayVirtualInterfaceGroupsOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - localGatewayVirtualInterfaceGroups = append(localGatewayVirtualInterfaceGroups, page.LocalGatewayVirtualInterfaceGroups...) - - return !lastPage - }) + output, err := FindLocalGatewayVirtualInterfaceGroups(conn, input) if err != nil { - return fmt.Errorf("error describing EC2 Local Gateway Virtual Interface Groups: %w", err) - } - - if len(localGatewayVirtualInterfaceGroups) == 0 { - return fmt.Errorf("no matching EC2 Local Gateway Virtual Interface Groups found") + return fmt.Errorf("error reading EC2 Local Gateway Virtual Interface Groups: %w", err) } - var ids, localGatewayVirtualInterfaceIds []*string + var groupIDs, interfaceIDs []string - for _, group := range localGatewayVirtualInterfaceGroups { - if group == nil { - continue - } - - ids = append(ids, group.LocalGatewayVirtualInterfaceGroupId) - localGatewayVirtualInterfaceIds = append(localGatewayVirtualInterfaceIds, group.LocalGatewayVirtualInterfaceIds...) + for _, v := range output { + groupIDs = append(groupIDs, aws.StringValue(v.LocalGatewayVirtualInterfaceGroupId)) + interfaceIDs = append(interfaceIDs, aws.StringValueSlice(v.LocalGatewayVirtualInterfaceIds)...) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("ids", ids); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } - - if err := d.Set("local_gateway_virtual_interface_ids", localGatewayVirtualInterfaceIds); err != nil { - return fmt.Errorf("error setting local_gateway_virtual_interface_ids: %w", err) - } + d.Set("ids", groupIDs) + d.Set("local_gateway_virtual_interface_ids", interfaceIDs) return nil } From 728870a832e4e8842c244f750d0add451dbce46e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 08:58:09 -0500 Subject: [PATCH 16/24] d/aws_ec2_local_gateways: Add and use 'FindLocalGateways'. Acceptance test output: % make testacc TESTS=TestAccEC2LocalGatewaysDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2LocalGatewaysDataSource_' -timeout 180m === RUN TestAccEC2LocalGatewaysDataSource_basic === PAUSE TestAccEC2LocalGatewaysDataSource_basic === CONT TestAccEC2LocalGatewaysDataSource_basic acctest.go:1255: skipping since no Outposts found --- SKIP: TestAccEC2LocalGatewaysDataSource_basic (3.35s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 9.011s --- .changelog/21219.txt | 4 ++ internal/service/ec2/find.go | 42 ++++++++++++ .../service/ec2/local_gateways_data_source.go | 64 ++++++------------- 3 files changed, 64 insertions(+), 46 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index f05107e2ca4..ceb6e7096e3 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -28,4 +28,8 @@ data-source/aws_ec2_local_gateway_route_tables: The type of the `ids` attribute ```release-note:note data-source/aws_ec2_local_gateway_virtual_interface_groups: The type of the `ids` and `local_gateway_virtual_interface_ids` attributes has changed from Set to List. If no local gateway virtual interface groups match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ec2_local_gateways: The type of the `ids` attribute has changed from Set to List. If no local gateways match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index ff236261d4d..07a72750b39 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -349,6 +349,48 @@ func FindLocalGatewayVirtualInterfaceGroup(conn *ec2.EC2, input *ec2.DescribeLoc return output[0], nil } +func FindLocalGateways(conn *ec2.EC2, input *ec2.DescribeLocalGatewaysInput) ([]*ec2.LocalGateway, error) { + var output []*ec2.LocalGateway + + err := conn.DescribeLocalGatewaysPages(input, func(page *ec2.DescribeLocalGatewaysOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.LocalGateways { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindLocalGateway(conn *ec2.EC2, input *ec2.DescribeLocalGatewaysInput) (*ec2.LocalGateway, error) { + output, err := FindLocalGateways(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + func FindNetworkACL(conn *ec2.EC2, input *ec2.DescribeNetworkAclsInput) (*ec2.NetworkAcl, error) { output, err := FindNetworkACLs(conn, input) diff --git a/internal/service/ec2/local_gateways_data_source.go b/internal/service/ec2/local_gateways_data_source.go index cf46eae5255..a3934d0d1b1 100644 --- a/internal/service/ec2/local_gateways_data_source.go +++ b/internal/service/ec2/local_gateways_data_source.go @@ -15,15 +15,12 @@ func DataSourceLocalGateways() *schema.Resource { Read: dataSourceLocalGatewaysRead, Schema: map[string]*schema.Schema{ "filter": CustomFiltersSchema(), - - "tags": tftags.TagsSchemaComputed(), - "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, + "tags": tftags.TagsSchemaComputed(), }, } } @@ -31,59 +28,34 @@ func DataSourceLocalGateways() *schema.Resource { func dataSourceLocalGatewaysRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeLocalGatewaysInput{} + input := &ec2.DescribeLocalGatewaysInput{} - if tags, tagsOk := d.GetOk("tags"); tagsOk { - req.Filters = append(req.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } - - if filters, filtersOk := d.GetOk("filter"); filtersOk { - req.Filters = append(req.Filters, BuildCustomFilterList( - filters.(*schema.Set), - )...) - } - if len(req.Filters) == 0 { - // Don't send an empty filters list; the EC2 API won't accept it. - req.Filters = nil - } + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) - var localGateways []*ec2.LocalGateway + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) - err := conn.DescribeLocalGatewaysPages(req, func(page *ec2.DescribeLocalGatewaysOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - localGateways = append(localGateways, page.LocalGateways...) + if len(input.Filters) == 0 { + input.Filters = nil + } - return !lastPage - }) + output, err := FindLocalGateways(conn, input) if err != nil { - return fmt.Errorf("error describing EC2 Local Gateways: %w", err) - } - - if len(localGateways) == 0 { - return fmt.Errorf("no matching EC2 Local Gateways found") + return fmt.Errorf("error reading EC2 Local Gateways: %w", err) } - var ids []string + var gatewayIDs []string - for _, localGateway := range localGateways { - if localGateway == nil { - continue - } - - ids = append(ids, aws.StringValue(localGateway.LocalGatewayId)) + for _, v := range output { + gatewayIDs = append(gatewayIDs, aws.StringValue(v.LocalGatewayId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("ids", ids); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } + d.Set("ids", gatewayIDs) return nil } From 3b5be552c430ecbd4a05424f0184e232b203f895 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 09:27:26 -0500 Subject: [PATCH 17/24] d/aws_ebs_volumes: Add and use 'FindEBSVolumes'. Acceptance test output: % make testacc TESTS=TestAccEC2EBSVolumesDataSource_ PKG=ec2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run='TestAccEC2EBSVolumesDataSource_' -timeout 180m === RUN TestAccEC2EBSVolumesDataSource_basic === PAUSE TestAccEC2EBSVolumesDataSource_basic === CONT TestAccEC2EBSVolumesDataSource_basic --- PASS: TestAccEC2EBSVolumesDataSource_basic (31.42s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 36.659s --- .changelog/21219.txt | 4 ++ .../service/ec2/ebs_volumes_data_source.go | 55 ++++++---------- .../ec2/ebs_volumes_data_source_test.go | 64 +++++++++++-------- internal/service/ec2/errors.go | 1 + internal/service/ec2/find.go | 49 ++++++++++++++ 5 files changed, 111 insertions(+), 62 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index ceb6e7096e3..2e00a59f67a 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -32,4 +32,8 @@ data-source/aws_ec2_local_gateway_virtual_interface_groups: The type of the `ids ```release-note:note data-source/aws_ec2_local_gateways: The type of the `ids` attribute has changed from Set to List. If no local gateways match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ebs_volumes: The type of the `ids` attribute has changed from Set to List. If no volumes match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/ec2/ebs_volumes_data_source.go b/internal/service/ec2/ebs_volumes_data_source.go index bc9f90cb121..fd5f38b41ab 100644 --- a/internal/service/ec2/ebs_volumes_data_source.go +++ b/internal/service/ec2/ebs_volumes_data_source.go @@ -1,10 +1,9 @@ package ec2 import ( - "errors" "fmt" - "log" + "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/hashicorp/terraform-provider-aws/internal/conns" @@ -15,16 +14,13 @@ func DataSourceEBSVolumes() *schema.Resource { return &schema.Resource{ Read: dataSourceEBSVolumesRead, Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), - - "tags": tftags.TagsSchema(), - + "filter": DataSourceFiltersSchema(), "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, + "tags": tftags.TagsSchema(), }, } } @@ -32,45 +28,34 @@ func DataSourceEBSVolumes() *schema.Resource { func dataSourceEBSVolumesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - req := &ec2.DescribeVolumesInput{} + input := &ec2.DescribeVolumesInput{} - if tags, tagsOk := d.GetOk("tags"); tagsOk { - req.Filters = append(req.Filters, BuildTagFilterList( - Tags(tftags.New(tags.(map[string]interface{}))), - )...) - } + input.Filters = append(input.Filters, BuildTagFilterList( + Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + )...) - if filters, filtersOk := d.GetOk("filter"); filtersOk { - req.Filters = append(req.Filters, BuildCustomFilterList( - filters.(*schema.Set), - )...) - } + input.Filters = append(input.Filters, BuildFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) - if len(req.Filters) == 0 { - req.Filters = nil + if len(input.Filters) == 0 { + input.Filters = nil } - log.Printf("[DEBUG] DescribeVolumes %s\n", req) - resp, err := conn.DescribeVolumes(req) - if err != nil { - return fmt.Errorf("error describing EC2 Volumes: %w", err) - } + output, err := FindEBSVolumes(conn, input) - if resp == nil || len(resp.Volumes) == 0 { - return errors.New("no matching volumes found") + if err != nil { + return fmt.Errorf("error reading EC2 Volumes: %w", err) } - volumes := make([]string, 0) + var volumeIDs []string - for _, volume := range resp.Volumes { - volumes = append(volumes, *volume.VolumeId) + for _, v := range output { + volumeIDs = append(volumeIDs, aws.StringValue(v.VolumeId)) } d.SetId(meta.(*conns.AWSClient).Region) - - if err := d.Set("ids", volumes); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } + d.Set("ids", volumeIDs) return nil } diff --git a/internal/service/ec2/ebs_volumes_data_source_test.go b/internal/service/ec2/ebs_volumes_data_source_test.go index 26d60fa7e0c..e71ffcce07d 100644 --- a/internal/service/ec2/ebs_volumes_data_source_test.go +++ b/internal/service/ec2/ebs_volumes_data_source_test.go @@ -11,7 +11,8 @@ import ( ) func TestAccEC2EBSVolumesDataSource_basic(t *testing.T) { - rInt := sdkacctest.RandIntRange(0, 256) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), @@ -19,47 +20,56 @@ func TestAccEC2EBSVolumesDataSource_basic(t *testing.T) { CheckDestroy: testAccCheckVolumeDestroy, Steps: []resource.TestStep{ { - Config: testAccEBSVolumeIDsDataSourceConfig(rInt), - }, - { - Config: testAccEBSVolumeIDsWithDataSourceDataSourceConfig(rInt), + Config: testAccEBSVolumeIDsDataSourceConfig(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.aws_ebs_volumes.subject_under_test", "ids.#", "2"), + resource.TestCheckResourceAttr("data.aws_ebs_volumes.by_tags", "ids.#", "2"), + resource.TestCheckResourceAttr("data.aws_ebs_volumes.by_filter", "ids.#", "1"), + resource.TestCheckResourceAttr("data.aws_ebs_volumes.empty", "ids.#", "0"), ), }, - { - // Force the destroy to not refresh the data source (leading to an error) - Config: testAccEBSVolumeIDsDataSourceConfig(rInt), - }, }, }) } -func testAccEBSVolumeIDsWithDataSourceDataSourceConfig(rInt int) string { - return fmt.Sprintf(` -%s - -data "aws_ebs_volumes" "subject_under_test" { - tags = { - TestIdentifierSet = "testAccDataSourceAwsEbsVolumes-%d" - } -} -`, testAccEBSVolumeIDsDataSourceConfig(rInt), rInt) -} - -func testAccEBSVolumeIDsDataSourceConfig(rInt int) string { - return acctest.ConfigAvailableAZsNoOptIn() + fmt.Sprintf(` +func testAccEBSVolumeIDsDataSourceConfig(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` data "aws_region" "current" {} -resource "aws_ebs_volume" "volume" { +resource "aws_ebs_volume" "test" { count = 2 availability_zone = data.aws_availability_zones.available.names[0] size = 1 tags = { - TestIdentifierSet = "testAccDataSourceAwsEbsVolumes-%d" + Name = %[1]q + } +} + +data "aws_ebs_volumes" "by_tags" { + tags = { + Name = %[1]q + } + + depends_on = [aws_ebs_volume.test[0], aws_ebs_volume.test[1]] +} + +data "aws_ebs_volumes" "by_filter" { + filter { + name = "volume-id" + values = [aws_ebs_volume.test[0].id] + } + + depends_on = [aws_ebs_volume.test[0], aws_ebs_volume.test[1]] +} + +data "aws_ebs_volumes" "empty" { + filter { + name = "create-time" + values = ["2000-01-01T00:00:00.000Z"] } + + depends_on = [aws_ebs_volume.test[0], aws_ebs_volume.test[1]] } -`, rInt) +`, rName)) } diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index 82475d96051..cdd9389b129 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -54,6 +54,7 @@ const ( ErrCodeInvalidSubnetIdNotFound = "InvalidSubnetId.NotFound" ErrCodeInvalidTransitGatewayAttachmentIDNotFound = "InvalidTransitGatewayAttachmentID.NotFound" ErrCodeInvalidTransitGatewayIDNotFound = "InvalidTransitGatewayID.NotFound" + ErrCodeInvalidVolumeNotFound = "InvalidVolume.NotFound" ErrCodeInvalidVpcCidrBlockAssociationIDNotFound = "InvalidVpcCidrBlockAssociationID.NotFound" ErrCodeInvalidVpcEndpointIdNotFound = "InvalidVpcEndpointId.NotFound" ErrCodeInvalidVpcEndpointNotFound = "InvalidVpcEndpoint.NotFound" diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 07a72750b39..8bad7a48062 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -128,6 +128,55 @@ func FindCOIPPool(conn *ec2.EC2, input *ec2.DescribeCoipPoolsInput) (*ec2.CoipPo return output[0], nil } +func FindEBSVolumes(conn *ec2.EC2, input *ec2.DescribeVolumesInput) ([]*ec2.Volume, error) { + var output []*ec2.Volume + + err := conn.DescribeVolumesPages(input, func(page *ec2.DescribeVolumesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.Volumes { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, ErrCodeInvalidVolumeNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindEBSVolume(conn *ec2.EC2, input *ec2.DescribeVolumesInput) (*ec2.Volume, error) { + output, err := FindEBSVolumes(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + func FindHostByID(conn *ec2.EC2, id string) (*ec2.Host, error) { input := &ec2.DescribeHostsInput{ HostIds: aws.StringSlice([]string{id}), From 87b14b9e9bf3cec82775a3f8832f1cc94cd49d6b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 09:30:54 -0500 Subject: [PATCH 18/24] 'CustomFiltersSchema' -> 'DataSourceFiltersSchema'. --- internal/service/ec2/local_gateway_route_tables_data_source.go | 2 +- .../ec2/local_gateway_virtual_interface_groups_data_source.go | 2 +- internal/service/ec2/local_gateways_data_source.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/ec2/local_gateway_route_tables_data_source.go b/internal/service/ec2/local_gateway_route_tables_data_source.go index d559e69942d..4db12ee2680 100644 --- a/internal/service/ec2/local_gateway_route_tables_data_source.go +++ b/internal/service/ec2/local_gateway_route_tables_data_source.go @@ -15,7 +15,7 @@ func DataSourceLocalGatewayRouteTables() *schema.Resource { Read: dataSourceLocalGatewayRouteTablesRead, Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), + "filter": DataSourceFiltersSchema(), "ids": { Type: schema.TypeList, Computed: true, diff --git a/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go b/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go index 54ef39655ba..b4481123d48 100644 --- a/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go +++ b/internal/service/ec2/local_gateway_virtual_interface_groups_data_source.go @@ -15,7 +15,7 @@ func DataSourceLocalGatewayVirtualInterfaceGroups() *schema.Resource { Read: dataSourceLocalGatewayVirtualInterfaceGroupsRead, Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), + "filter": DataSourceFiltersSchema(), "ids": { Type: schema.TypeList, Computed: true, diff --git a/internal/service/ec2/local_gateways_data_source.go b/internal/service/ec2/local_gateways_data_source.go index a3934d0d1b1..9a4ae075086 100644 --- a/internal/service/ec2/local_gateways_data_source.go +++ b/internal/service/ec2/local_gateways_data_source.go @@ -14,7 +14,7 @@ func DataSourceLocalGateways() *schema.Resource { return &schema.Resource{ Read: dataSourceLocalGatewaysRead, Schema: map[string]*schema.Schema{ - "filter": CustomFiltersSchema(), + "filter": DataSourceFiltersSchema(), "ids": { Type: schema.TypeList, Computed: true, From 69eb401a71400c6b105cf0cf1fb7d983d665ca61 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 09:55:20 -0500 Subject: [PATCH 19/24] d/aws_cognito_user_pools: Allow no pools to be selected. Acceptance test output: % make testacc TESTS=TestAccCognitoIDPUserPoolsDataSource_ PKG=cognitoidp ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/cognitoidp/... -v -count 1 -parallel 20 -run='TestAccCognitoIDPUserPoolsDataSource_' -timeout 180m === RUN TestAccCognitoIDPUserPoolsDataSource_basic === PAUSE TestAccCognitoIDPUserPoolsDataSource_basic === CONT TestAccCognitoIDPUserPoolsDataSource_basic --- PASS: TestAccCognitoIDPUserPoolsDataSource_basic (18.78s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/cognitoidp 24.721s --- .changelog/21219.txt | 4 + .../cognitoidp/user_pools_data_source.go | 99 ++++++++++--------- .../cognitoidp/user_pools_data_source_test.go | 38 ++++--- 3 files changed, 72 insertions(+), 69 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 2e00a59f67a..da14c5b792d 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -36,4 +36,8 @@ data-source/aws_ec2_local_gateways: The type of the `ids` attribute has changed ```release-note:note data-source/aws_ebs_volumes: The type of the `ids` attribute has changed from Set to List. If no volumes match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_cognito_user_pools: The type of the `ids` and `arns` attributes has changed from Set to List. If no volumes match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/cognitoidp/user_pools_data_source.go b/internal/service/cognitoidp/user_pools_data_source.go index 0c29cc0e82a..30ed24abdd4 100644 --- a/internal/service/cognitoidp/user_pools_data_source.go +++ b/internal/service/cognitoidp/user_pools_data_source.go @@ -13,85 +13,86 @@ import ( func DataSourceUserPools() *schema.Resource { return &schema.Resource{ Read: dataSourceUserPoolsRead, + Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "ids": { - Type: schema.TypeSet, + "arns": { + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "arns": { - Type: schema.TypeSet, + "ids": { + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "name": { + Type: schema.TypeString, + Required: true, + }, }, } } func dataSourceUserPoolsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).CognitoIDPConn - name := d.Get("name").(string) - var ids []string - var arns []string - pools, err := getAllCognitoUserPools(conn) + output, err := findUserPoolDescriptionTypes(conn) + if err != nil { - return fmt.Errorf("Error listing cognito user pools: %w", err) + return fmt.Errorf("error reading Cognito User Pools: %w", err) } - for _, pool := range pools { - if name == aws.StringValue(pool.Name) { - id := aws.StringValue(pool.Id) - arn := arn.ARN{ - Partition: meta.(*conns.AWSClient).Partition, - Service: "cognito-idp", - Region: meta.(*conns.AWSClient).Region, - AccountID: meta.(*conns.AWSClient).AccountID, - Resource: fmt.Sprintf("userpool/%s", id), - }.String() - - ids = append(ids, id) - arns = append(arns, arn) + + name := d.Get("name").(string) + var arns, userPoolIDs []string + + for _, v := range output { + if name != aws.StringValue(v.Name) { + continue } - } - if len(ids) == 0 { - return fmt.Errorf("No cognito user pool found with name: %s", name) + userPoolID := aws.StringValue(v.Id) + arn := arn.ARN{ + Partition: meta.(*conns.AWSClient).Partition, + Service: cognitoidentityprovider.ServiceName, + Region: meta.(*conns.AWSClient).Region, + AccountID: meta.(*conns.AWSClient).AccountID, + Resource: fmt.Sprintf("userpool/%s", userPoolID), + }.String() + + userPoolIDs = append(userPoolIDs, userPoolID) + arns = append(arns, arn) } d.SetId(name) - d.Set("ids", ids) + d.Set("ids", userPoolIDs) d.Set("arns", arns) return nil } -func getAllCognitoUserPools(conn *cognitoidentityprovider.CognitoIdentityProvider) ([]*cognitoidentityprovider.UserPoolDescriptionType, error) { - var pools []*cognitoidentityprovider.UserPoolDescriptionType - var nextToken string +func findUserPoolDescriptionTypes(conn *cognitoidentityprovider.CognitoIdentityProvider) ([]*cognitoidentityprovider.UserPoolDescriptionType, error) { + input := &cognitoidentityprovider.ListUserPoolsInput{ + MaxResults: aws.Int64(60), + } + var output []*cognitoidentityprovider.UserPoolDescriptionType - for { - input := &cognitoidentityprovider.ListUserPoolsInput{ - // MaxResults Valid Range: Minimum value of 1. Maximum value of 60 - MaxResults: aws.Int64(60), - } - if nextToken != "" { - input.NextToken = aws.String(nextToken) - } - out, err := conn.ListUserPools(input) - if err != nil { - return pools, err + err := conn.ListUserPoolsPages(input, func(page *cognitoidentityprovider.ListUserPoolsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - pools = append(pools, out.UserPools...) - if out.NextToken == nil { - break + for _, v := range page.UserPools { + if v != nil { + output = append(output, v) + } } - nextToken = aws.StringValue(out.NextToken) + + return !lastPage + }) + + if err != nil { + return nil, err } - return pools, nil + return output, nil } diff --git a/internal/service/cognitoidp/user_pools_data_source_test.go b/internal/service/cognitoidp/user_pools_data_source_test.go index ecce4ddc6bd..1a5eb7cbd4a 100644 --- a/internal/service/cognitoidp/user_pools_data_source_test.go +++ b/internal/service/cognitoidp/user_pools_data_source_test.go @@ -2,7 +2,6 @@ package cognitoidp_test import ( "fmt" - "regexp" "testing" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" @@ -12,44 +11,43 @@ import ( ) func TestAccCognitoIDPUserPoolsDataSource_basic(t *testing.T) { - rName := fmt.Sprintf("tf_acc_ds_cognito_user_pools_%s", sdkacctest.RandString(7)) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t); testAccPreCheckIdentityProvider(t) }, ErrorCheck: acctest.ErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: acctest.Providers, Steps: []resource.TestStep{ { - Config: testAccUserPoolsDataSourceConfig_basic(rName), + Config: testAccUserPoolsDataSourceConfig(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.aws_cognito_user_pools.selected", "ids.#", "2"), - resource.TestCheckResourceAttr("data.aws_cognito_user_pools.selected", "arns.#", "2"), + resource.TestCheckResourceAttr("data.aws_cognito_user_pools.test", "arns.#", "2"), + resource.TestCheckResourceAttr("data.aws_cognito_user_pools.test", "ids.#", "2"), + resource.TestCheckResourceAttr("data.aws_cognito_user_pools.empty", "arns.#", "0"), + resource.TestCheckResourceAttr("data.aws_cognito_user_pools.empty", "ids.#", "0"), ), }, - { - Config: testAccUserPoolsDataSourceConfig_notFound(rName), - ExpectError: regexp.MustCompile(`No cognito user pool found with name:`), - }, }, }) } -func testAccUserPoolsDataSourceConfig_basic(rName string) string { +func testAccUserPoolsDataSourceConfig(rName string) string { return fmt.Sprintf(` -resource "aws_cognito_user_pool" "main" { +resource "aws_cognito_user_pool" "test" { count = 2 - name = "%s" + name = %[1]q } -data "aws_cognito_user_pools" "selected" { - name = aws_cognito_user_pool.main.*.name[0] -} -`, rName) +data "aws_cognito_user_pools" "test" { + name = %[1]q + + depends_on = [aws_cognito_user_pool.test[0], aws_cognito_user_pool.test[1]] } -func testAccUserPoolsDataSourceConfig_notFound(rName string) string { - return fmt.Sprintf(` -data "aws_cognito_user_pools" "selected" { - name = "%s-not-found" +data "aws_cognito_user_pools" "empty" { + name = "not.%[1]s" + + depends_on = [aws_cognito_user_pool.test[0], aws_cognito_user_pool.test[1]] } `, rName) } From 30799167c5fc58cd2c22086c7389976e72bf5ab9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 10:05:49 -0500 Subject: [PATCH 20/24] d/aws_ip_ranges: Allow empty results. Acceptance test output: % make testacc TESTS=TestAccMetaIPRangesDataSource_ PKG=meta ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/meta/... -v -count 1 -parallel 20 -run='TestAccMetaIPRangesDataSource_' -timeout 180m === RUN TestAccMetaIPRangesDataSource_basic === PAUSE TestAccMetaIPRangesDataSource_basic === RUN TestAccMetaIPRangesDataSource_url === PAUSE TestAccMetaIPRangesDataSource_url === CONT TestAccMetaIPRangesDataSource_basic === CONT TestAccMetaIPRangesDataSource_url --- PASS: TestAccMetaIPRangesDataSource_url (16.39s) --- PASS: TestAccMetaIPRangesDataSource_basic (17.24s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/meta 22.673s --- .changelog/21219.txt | 4 ++++ internal/service/meta/ip_ranges_data_source.go | 4 ---- internal/service/meta/ip_ranges_data_source_test.go | 7 +++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index da14c5b792d..6d3992fe0c8 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -40,4 +40,8 @@ data-source/aws_ebs_volumes: The type of the `ids` attribute has changed from Se ```release-note:note data-source/aws_cognito_user_pools: The type of the `ids` and `arns` attributes has changed from Set to List. If no volumes match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ip_ranges: If no ranges match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/meta/ip_ranges_data_source.go b/internal/service/meta/ip_ranges_data_source.go index ba208bb09f4..2ad149767f3 100644 --- a/internal/service/meta/ip_ranges_data_source.go +++ b/internal/service/meta/ip_ranges_data_source.go @@ -160,10 +160,6 @@ func dataSourceIPRangesRead(d *schema.ResourceData, meta interface{}) error { } } - if len(ipPrefixes) == 0 && len(ipv6Prefixes) == 0 { - return fmt.Errorf("No IP ranges result from filters from (%s)", url) - } - sort.Strings(ipPrefixes) if err := d.Set("cidr_blocks", ipPrefixes); err != nil { diff --git a/internal/service/meta/ip_ranges_data_source_test.go b/internal/service/meta/ip_ranges_data_source_test.go index e3dbe2fdf6a..547afd791d6 100644 --- a/internal/service/meta/ip_ranges_data_source_test.go +++ b/internal/service/meta/ip_ranges_data_source_test.go @@ -27,6 +27,8 @@ func TestAccMetaIPRangesDataSource_basic(t *testing.T) { testAccIPRangesCheckAttributes("data.aws_ip_ranges.some"), testAccIPRangesCheckCIDRBlocksAttribute("data.aws_ip_ranges.some", "cidr_blocks"), testAccIPRangesCheckCIDRBlocksAttribute("data.aws_ip_ranges.some", "ipv6_cidr_blocks"), + resource.TestCheckResourceAttr("data.aws_ip_ranges.none", "cidr_blocks.#", "0"), + resource.TestCheckResourceAttr("data.aws_ip_ranges.none", "ipv6_cidr_blocks.#", "0"), ), }, }, @@ -163,6 +165,11 @@ data "aws_ip_ranges" "some" { regions = ["eu-west-1", "eu-central-1"] services = ["ec2"] } + +data "aws_ip_ranges" "none" { + regions = ["mars-1"] + services = ["blueorigin"] +} ` // lintignore:AWSAT003 From 046eda5279fc00dc4671f56669360c677a8d4e21 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 12:23:55 -0500 Subject: [PATCH 21/24] d/aws_efs_access_points: Allow empty results. Acceptance test output: % make testacc TESTS=TestAccEFSAccessPointsDataSource_ PKG=efs ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/efs/... -v -count 1 -parallel 20 -run='TestAccEFSAccessPointsDataSource_' -timeout 180m === RUN TestAccEFSAccessPointsDataSource_basic === PAUSE TestAccEFSAccessPointsDataSource_basic === RUN TestAccEFSAccessPointsDataSource_empty === PAUSE TestAccEFSAccessPointsDataSource_empty === CONT TestAccEFSAccessPointsDataSource_basic === CONT TestAccEFSAccessPointsDataSource_empty --- PASS: TestAccEFSAccessPointsDataSource_empty (29.39s) --- PASS: TestAccEFSAccessPointsDataSource_basic (39.36s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/efs 45.604s --- .changelog/21219.txt | 4 ++ .../service/efs/access_points_data_source.go | 62 ++++++++++--------- .../efs/access_points_data_source_test.go | 30 +++++++++ 3 files changed, 67 insertions(+), 29 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 6d3992fe0c8..cfa8e491a8d 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -44,4 +44,8 @@ data-source/aws_cognito_user_pools: The type of the `ids` and `arns` attributes ```release-note:note data-source/aws_ip_ranges: If no ranges match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_efs_access_points: The type of the `ids` and `arns` attributes has changed from Set to List. If no access points match the specified criteria an empty list is returned (previously an error was raised) ``` \ No newline at end of file diff --git a/internal/service/efs/access_points_data_source.go b/internal/service/efs/access_points_data_source.go index 3fc36a150d1..44b4abf0516 100644 --- a/internal/service/efs/access_points_data_source.go +++ b/internal/service/efs/access_points_data_source.go @@ -16,7 +16,7 @@ func DataSourceAccessPoints() *schema.Resource { Schema: map[string]*schema.Schema{ "arns": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -26,7 +26,7 @@ func DataSourceAccessPoints() *schema.Resource { ValidateFunc: validation.StringIsNotEmpty, }, "ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -37,47 +37,51 @@ func DataSourceAccessPoints() *schema.Resource { func dataSourceAccessPointsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EFSConn - fileSystemId := d.Get("file_system_id").(string) + fileSystemID := d.Get("file_system_id").(string) input := &efs.DescribeAccessPointsInput{ - FileSystemId: aws.String(fileSystemId), + FileSystemId: aws.String(fileSystemID), } - var accessPoints []*efs.AccessPointDescription + output, err := findAccessPointDescriptions(conn, input) + + if err != nil { + return fmt.Errorf("error reading EFS Access Points: %w", err) + } + + var accessPointIDs, arns []string + + for _, v := range output { + accessPointIDs = append(accessPointIDs, aws.StringValue(v.AccessPointId)) + arns = append(arns, aws.StringValue(v.AccessPointArn)) + } + + d.SetId(fileSystemID) + d.Set("arns", arns) + d.Set("ids", accessPointIDs) + + return nil +} + +func findAccessPointDescriptions(conn *efs.EFS, input *efs.DescribeAccessPointsInput) ([]*efs.AccessPointDescription, error) { + var output []*efs.AccessPointDescription err := conn.DescribeAccessPointsPages(input, func(page *efs.DescribeAccessPointsOutput, lastPage bool) bool { if page == nil { return !lastPage } - accessPoints = append(accessPoints, page.AccessPoints...) + for _, v := range page.AccessPoints { + if v != nil { + output = append(output, v) + } + } return !lastPage }) if err != nil { - return fmt.Errorf("error reading EFS Access Points for File System (%s): %w", fileSystemId, err) + return nil, err } - if len(accessPoints) == 0 { - return fmt.Errorf("no matching EFS Access Points for File System (%s) found", fileSystemId) - } - - d.SetId(fileSystemId) - - var arns, ids []string - - for _, accessPoint := range accessPoints { - arns = append(arns, aws.StringValue(accessPoint.AccessPointArn)) - ids = append(ids, aws.StringValue(accessPoint.AccessPointId)) - } - - if err := d.Set("arns", arns); err != nil { - return fmt.Errorf("error setting arns: %w", err) - } - - if err := d.Set("ids", ids); err != nil { - return fmt.Errorf("error setting ids: %w", err) - } - - return nil + return output, nil } diff --git a/internal/service/efs/access_points_data_source_test.go b/internal/service/efs/access_points_data_source_test.go index 9e87e146a34..9ae9a1b3f4d 100644 --- a/internal/service/efs/access_points_data_source_test.go +++ b/internal/service/efs/access_points_data_source_test.go @@ -28,6 +28,26 @@ func TestAccEFSAccessPointsDataSource_basic(t *testing.T) { }) } +func TestAccEFSAccessPointsDataSource_empty(t *testing.T) { + dataSourceName := "data.aws_efs_access_points.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, efs.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckEfsAccessPointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAccessPointsEmptyDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "arns.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "ids.#", "0"), + ), + }, + }, + }) +} + func testAccAccessPointsDataSourceConfig() string { return ` resource "aws_efs_file_system" "test" {} @@ -41,3 +61,13 @@ data "aws_efs_access_points" "test" { } ` } + +func testAccAccessPointsEmptyDataSourceConfig() string { + return ` +resource "aws_efs_file_system" "test" {} + +data "aws_efs_access_points" "test" { + file_system_id = aws_efs_file_system.test.id +} +` +} From 90c3c383d772dfb4080fe27b4ffdbd081c1dbb79 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 13:49:23 -0500 Subject: [PATCH 22/24] d/aws_emr_release_labels: Allow empty result. Acceptance test output: % make testacc TESTS=TestAccEMRReleaseLabels_ PKG=emr ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/emr/... -v -count 1 -parallel 20 -run='TestAccEMRReleaseLabels_' -timeout 180m === RUN TestAccEMRReleaseLabels_basic === PAUSE TestAccEMRReleaseLabels_basic === RUN TestAccEMRReleaseLabels_prefix === PAUSE TestAccEMRReleaseLabels_prefix === RUN TestAccEMRReleaseLabels_application === PAUSE TestAccEMRReleaseLabels_application === RUN TestAccEMRReleaseLabels_full === PAUSE TestAccEMRReleaseLabels_full === RUN TestAccEMRReleaseLabels_empty === PAUSE TestAccEMRReleaseLabels_empty === CONT TestAccEMRReleaseLabels_basic === CONT TestAccEMRReleaseLabels_full === CONT TestAccEMRReleaseLabels_empty === CONT TestAccEMRReleaseLabels_prefix === CONT TestAccEMRReleaseLabels_application --- PASS: TestAccEMRReleaseLabels_application (18.21s) --- PASS: TestAccEMRReleaseLabels_prefix (18.57s) --- PASS: TestAccEMRReleaseLabels_empty (18.75s) --- PASS: TestAccEMRReleaseLabels_full (18.79s) --- PASS: TestAccEMRReleaseLabels_basic (19.38s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/emr 24.816s --- .changelog/21219.txt | 6 ++- .../service/emr/release_labels_data_source.go | 44 +++++++++++++++---- .../emr/release_labels_data_source_test.go | 29 ++++++++++++ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index cfa8e491a8d..7bfb3ce009d 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -48,4 +48,8 @@ data-source/aws_ip_ranges: If no ranges match the specified criteria an empty li ```release-note:note data-source/aws_efs_access_points: The type of the `ids` and `arns` attributes has changed from Set to List. If no access points match the specified criteria an empty list is returned (previously an error was raised) -``` \ No newline at end of file +``` + +```release-note:note +data-source/aws_emr_release_labels: The type of the `ids` attribute has changed from Set to List. If no release labels match the specified criteria an empty list is returned (previously an error was raised) +``` diff --git a/internal/service/emr/release_labels_data_source.go b/internal/service/emr/release_labels_data_source.go index b863bac5584..b8b92b9f8b5 100644 --- a/internal/service/emr/release_labels_data_source.go +++ b/internal/service/emr/release_labels_data_source.go @@ -10,12 +10,12 @@ import ( "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/flex" ) func DataSourceReleaseLabels() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceReleaseLabelsRead, + Schema: map[string]*schema.Schema{ "filters": { Type: schema.TypeList, @@ -35,7 +35,7 @@ func DataSourceReleaseLabels() *schema.Resource { }, }, "release_labels": { - Type: schema.TypeSet, + Type: schema.TypeList, Elem: &schema.Schema{Type: schema.TypeString}, Computed: true, }, @@ -52,17 +52,20 @@ func dataSourceReleaseLabelsRead(ctx context.Context, d *schema.ResourceData, me input.Filters = expandReleaseLabelsFilters(v.([]interface{})) } - out, err := conn.ListReleaseLabels(input) + output, err := findReleaseLabels(conn, input) + if err != nil { - return diag.FromErr(fmt.Errorf("error reading EMR Release Label: %w", err)) + return diag.FromErr(fmt.Errorf("error reading EMR Release Labels: %w", err)) } - if len(out.ReleaseLabels) == 0 { - return diag.Errorf("no EMR release labels found") - } + releaseLabels := aws.StringValueSlice(output) - d.SetId(strings.Join(aws.StringValueSlice(out.ReleaseLabels), ",")) - d.Set("release_labels", flex.FlattenStringSet(out.ReleaseLabels)) + if len(releaseLabels) == 0 { + d.SetId(",") + } else { + d.SetId(strings.Join(releaseLabels, ",")) + } + d.Set("release_labels", releaseLabels) return nil } @@ -85,3 +88,26 @@ func expandReleaseLabelsFilters(filters []interface{}) *emr.ReleaseLabelFilter { return app } + +func findReleaseLabels(conn *emr.EMR, input *emr.ListReleaseLabelsInput) ([]*string, error) { + var output []*string + + err := conn.ListReleaseLabelsPages(input, func(page *emr.ListReleaseLabelsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, v := range page.ReleaseLabels { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return output, nil +} diff --git a/internal/service/emr/release_labels_data_source_test.go b/internal/service/emr/release_labels_data_source_test.go index ca2836f04a0..646adf090a6 100644 --- a/internal/service/emr/release_labels_data_source_test.go +++ b/internal/service/emr/release_labels_data_source_test.go @@ -84,6 +84,25 @@ func TestAccEMRReleaseLabels_full(t *testing.T) { }) } +func TestAccEMRReleaseLabels_empty(t *testing.T) { + dataSourceResourceName := "data.aws_emr_release_labels.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, emr.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccReleaseLabelsDataSourceConfigEmpty(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceResourceName, "release_labels.#", "0"), + ), + }, + }, + }) +} + func testAccReleaseLabelsDataSourceConfigBasic() string { return ` data "aws_emr_release_labels" "test" {} @@ -120,3 +139,13 @@ data "aws_emr_release_labels" "test" { } ` } + +func testAccReleaseLabelsDataSourceConfigEmpty() string { + return ` +data "aws_emr_release_labels" "test" { + filters { + prefix = "emr-0" + } +} +` +} From e506645dcd370774aee7cfe54f923cdafbd55d47 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 14:40:46 -0500 Subject: [PATCH 23/24] d/aws_ssoadmin_instances: Allow empty results. Acceptance test output: % make testacc TESTS=TestAccSSOAdminInstancesDataSource_ PKG=ssoadmin ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ssoadmin/... -v -count 1 -parallel 20 -run='TestAccSSOAdminInstancesDataSource_' -timeout 180m === RUN TestAccSSOAdminInstancesDataSource_basic === PAUSE TestAccSSOAdminInstancesDataSource_basic === CONT TestAccSSOAdminInstancesDataSource_basic --- PASS: TestAccSSOAdminInstancesDataSource_basic (12.10s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ssoadmin 17.085s --- .changelog/21219.txt | 12 ++++ .../inspector/rules_packages_data_source.go | 45 ++++++++------ .../rds/event_categories_data_source.go | 60 +++++++++++-------- .../service/ssoadmin/instances_data_source.go | 59 ++++++++++-------- 4 files changed, 108 insertions(+), 68 deletions(-) diff --git a/.changelog/21219.txt b/.changelog/21219.txt index 7bfb3ce009d..4870302226c 100644 --- a/.changelog/21219.txt +++ b/.changelog/21219.txt @@ -53,3 +53,15 @@ data-source/aws_efs_access_points: The type of the `ids` and `arns` attributes h ```release-note:note data-source/aws_emr_release_labels: The type of the `ids` attribute has changed from Set to List. If no release labels match the specified criteria an empty list is returned (previously an error was raised) ``` + +```release-note:note +data-source/aws_inspector_rules_packages: If no rules packages match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_db_event_categories: The type of the `ids` attribute has changed from Set to List. If no event categories match the specified criteria an empty list is returned (previously an error was raised) +``` + +```release-note:note +data-source/aws_ssoadmin_instances: The type of the `identity_store_ids` and `arns` attributes has changed from Set to List. If no instances match the specified criteria an empty list is returned (previously an error was raised) +``` \ No newline at end of file diff --git a/internal/service/inspector/rules_packages_data_source.go b/internal/service/inspector/rules_packages_data_source.go index 5e92d5dc240..6ab5d66e0e6 100644 --- a/internal/service/inspector/rules_packages_data_source.go +++ b/internal/service/inspector/rules_packages_data_source.go @@ -1,11 +1,10 @@ package inspector import ( - "errors" "fmt" - "log" "sort" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/inspector" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -28,30 +27,42 @@ func DataSourceRulesPackages() *schema.Resource { func dataSourceRulesPackagesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).InspectorConn - log.Printf("[DEBUG] Reading Rules Packages.") + output, err := findRulesPackageArns(conn) - var arns []string + if err != nil { + return fmt.Errorf("error reading Inspector Rules Packages: %w", err) + } + + arns := aws.StringValueSlice(output) + sort.Strings(arns) + d.SetId(meta.(*conns.AWSClient).Region) + d.Set("arns", arns) + + return nil +} + +func findRulesPackageArns(conn *inspector.Inspector) ([]*string, error) { input := &inspector.ListRulesPackagesInput{} + var output []*string err := conn.ListRulesPackagesPages(input, func(page *inspector.ListRulesPackagesOutput, lastPage bool) bool { - for _, arn := range page.RulesPackageArns { - arns = append(arns, *arn) + if page == nil { + return !lastPage + } + + for _, v := range page.RulesPackageArns { + if v != nil { + output = append(output, v) + } } + return !lastPage }) - if err != nil { - return fmt.Errorf("Error fetching Rules Packages: %w", err) - } - if len(arns) == 0 { - return errors.New("No rules packages found.") + if err != nil { + return nil, err } - d.SetId(meta.(*conns.AWSClient).Region) - - sort.Strings(arns) - d.Set("arns", arns) - - return nil + return output, nil } diff --git a/internal/service/rds/event_categories_data_source.go b/internal/service/rds/event_categories_data_source.go index 433f5106478..7fbce681efb 100644 --- a/internal/service/rds/event_categories_data_source.go +++ b/internal/service/rds/event_categories_data_source.go @@ -2,11 +2,11 @@ package rds import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "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" ) @@ -15,15 +15,15 @@ func DataSourceEventCategories() *schema.Resource { Read: dataSourceEventCategoriesRead, Schema: map[string]*schema.Schema{ - "source_type": { - Type: schema.TypeString, - Optional: true, - }, "event_categories": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, + }, + "source_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(rds.SourceType_Values(), false), }, }, } @@ -32,35 +32,45 @@ func DataSourceEventCategories() *schema.Resource { func dataSourceEventCategoriesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).RDSConn - req := &rds.DescribeEventCategoriesInput{} + input := &rds.DescribeEventCategoriesInput{} - if sourceType := d.Get("source_type").(string); sourceType != "" { - req.SourceType = aws.String(sourceType) + if v, ok := d.GetOk("source_type"); ok { + input.SourceType = aws.String(v.(string)) } - log.Printf("[DEBUG] Describe Event Categories %s\n", req) - resp, err := conn.DescribeEventCategories(req) - if err != nil { - return err - } + output, err := findEventCategoriesMaps(conn, input) - if resp == nil || len(resp.EventCategoriesMapList) == 0 { - return fmt.Errorf("Event Categories not found") + if err != nil { + return fmt.Errorf("error reading RDS Event Categories: %w", err) } - eventCategories := make([]string, 0) + var eventCategories []string - for _, eventMap := range resp.EventCategoriesMapList { - for _, v := range eventMap.EventCategories { - eventCategories = append(eventCategories, aws.StringValue(v)) - } + for _, v := range output { + eventCategories = append(eventCategories, aws.StringValueSlice(v.EventCategories)...) } d.SetId(meta.(*conns.AWSClient).Region) - if err := d.Set("event_categories", eventCategories); err != nil { - return fmt.Errorf("Error setting Event Categories: %w", err) - } + d.Set("event_categories", eventCategories) return nil } + +func findEventCategoriesMaps(conn *rds.RDS, input *rds.DescribeEventCategoriesInput) ([]*rds.EventCategoriesMap, error) { + var output []*rds.EventCategoriesMap + + page, err := conn.DescribeEventCategories(input) + + if err != nil { + return nil, err + } + + for _, v := range page.EventCategoriesMapList { + if v != nil { + output = append(output, v) + } + } + + return output, nil +} diff --git a/internal/service/ssoadmin/instances_data_source.go b/internal/service/ssoadmin/instances_data_source.go index a97e418c82d..5bafb16dfc3 100644 --- a/internal/service/ssoadmin/instances_data_source.go +++ b/internal/service/ssoadmin/instances_data_source.go @@ -15,13 +15,12 @@ func DataSourceInstances() *schema.Resource { Schema: map[string]*schema.Schema{ "arns": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "identity_store_ids": { - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -32,39 +31,47 @@ func DataSourceInstances() *schema.Resource { func dataSourceInstancesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).SSOAdminConn - var instances []*ssoadmin.InstanceMetadata - var arns, ids []string + output, err := findInstanceMetadatas(conn) + + if err != nil { + return fmt.Errorf("error reading SSO Instances: %w", err) + } + + var identityStoreIDs, arns []string + + for _, v := range output { + identityStoreIDs = append(identityStoreIDs, aws.StringValue(v.IdentityStoreId)) + arns = append(arns, aws.StringValue(v.InstanceArn)) + } + + d.SetId(meta.(*conns.AWSClient).Region) + d.Set("arns", arns) + d.Set("identity_store_ids", identityStoreIDs) + + return nil +} - err := conn.ListInstancesPages(&ssoadmin.ListInstancesInput{}, func(page *ssoadmin.ListInstancesOutput, lastPage bool) bool { +func findInstanceMetadatas(conn *ssoadmin.SSOAdmin) ([]*ssoadmin.InstanceMetadata, error) { + input := &ssoadmin.ListInstancesInput{} + var output []*ssoadmin.InstanceMetadata + + err := conn.ListInstancesPages(input, func(page *ssoadmin.ListInstancesOutput, lastPage bool) bool { if page == nil { return !lastPage } - instances = append(instances, page.Instances...) + for _, v := range page.Instances { + if v != nil { + output = append(output, v) + } + } return !lastPage }) if err != nil { - return fmt.Errorf("error reading SSO Instances: %w", err) - } - - if len(instances) == 0 { - return fmt.Errorf("error reading SSO Instance: no instances found") - } - - for _, instance := range instances { - arns = append(arns, aws.StringValue(instance.InstanceArn)) - ids = append(ids, aws.StringValue(instance.IdentityStoreId)) - } - - d.SetId(meta.(*conns.AWSClient).Region) - if err := d.Set("arns", arns); err != nil { - return fmt.Errorf("error setting arns: %w", err) - } - if err := d.Set("identity_store_ids", ids); err != nil { - return fmt.Errorf("error setting identity_store_ids: %w", err) + return nil, err } - return nil + return output, nil } From 9b4b1ca60920c670b144a9a4146c8e0024f2155d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 Jan 2022 16:32:00 -0500 Subject: [PATCH 24/24] d/aws_instances: Correct argument name. --- internal/service/ec2/instances_data_source.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/instances_data_source.go b/internal/service/ec2/instances_data_source.go index 13dd3204753..4f9d9b2e1e0 100644 --- a/internal/service/ec2/instances_data_source.go +++ b/internal/service/ec2/instances_data_source.go @@ -64,7 +64,7 @@ func dataSourceInstancesRead(d *schema.ResourceData, meta interface{}) error { } input.Filters = append(input.Filters, BuildTagFilterList( - Tags(tftags.New(d.Get("tags").(map[string]interface{}))), + Tags(tftags.New(d.Get("instance_tags").(map[string]interface{}))), )...) input.Filters = append(input.Filters, BuildFiltersDataSource(