From b92d3a52adce7927a5c465bdd3151dfc5cab0a32 Mon Sep 17 00:00:00 2001 From: Jeremy Chauvet Date: Fri, 28 Jul 2023 16:59:26 +0200 Subject: [PATCH 1/8] enhancement: add support of tags to filter RDS instances (#2988) --- internal/service/rds/instances_data_source.go | 107 +++++++++++++++--- .../service/rds/instances_data_source_test.go | 90 +++++++++++++++ 2 files changed, 181 insertions(+), 16 deletions(-) diff --git a/internal/service/rds/instances_data_source.go b/internal/service/rds/instances_data_source.go index facd89ab2fa3..53047625e24a 100644 --- a/internal/service/rds/instances_data_source.go +++ b/internal/service/rds/instances_data_source.go @@ -5,15 +5,16 @@ package rds import ( "context" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/generate/namevaluesfilters" "github.com/hashicorp/terraform-provider-aws/names" + "log" ) // @SDKDataSource("aws_db_instances") @@ -22,6 +23,26 @@ func DataSourceInstances() *schema.Resource { ReadWithoutTimeout: dataSourceInstancesRead, Schema: map[string]*schema.Schema{ + "filter": namevaluesfilters.Schema(), + "tag": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + // Computed values. "instance_arns": { Type: schema.TypeList, Computed: true, @@ -32,7 +53,6 @@ func DataSourceInstances() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "filter": namevaluesfilters.Schema(), }, } } @@ -45,32 +65,65 @@ func dataSourceInstancesRead(ctx context.Context, d *schema.ResourceData, meta i conn := meta.(*conns.AWSClient).RDSConn(ctx) input := &rds.DescribeDBInstancesInput{} + var instanceARNS []string + var instanceIdentifiers []string if v, ok := d.GetOk("filter"); ok { input.Filters = namevaluesfilters.New(v.(*schema.Set)).RDSFilters() - } - var instanceARNS []string - var instanceIdentifiers []string + err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *rds.DescribeDBInstancesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, dbInstance := range page.DBInstances { + if dbInstance == nil { + continue + } + + instanceARNS = append(instanceARNS, aws.StringValue(dbInstance.DBInstanceArn)) + instanceIdentifiers = append(instanceIdentifiers, aws.StringValue(dbInstance.DBInstanceIdentifier)) + } - err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *rds.DescribeDBInstancesOutput, lastPage bool) bool { - if page == nil { return !lastPage + }) + if err != nil { + return create.DiagError(names.RDS, create.ErrActionReading, DSNameInstances, "", err) + } + } + + if v, ok := d.GetOk("tag"); ok { + // Build map of tags to check, based on user request. + tags := v.(*schema.Set).List() + tagsToCheck := make(map[string]string) + for _, tag := range tags { + tagMap := tag.(map[string]interface{}) + key := tagMap["key"].(string) + value := tagMap["value"].(string) + tagsToCheck[key] = value } - for _, dbInstance := range page.DBInstances { - if dbInstance == nil { - continue + err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *rds.DescribeDBInstancesOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - instanceARNS = append(instanceARNS, aws.StringValue(dbInstance.DBInstanceArn)) - instanceIdentifiers = append(instanceIdentifiers, aws.StringValue(dbInstance.DBInstanceIdentifier)) + for _, dbInstance := range page.DBInstances { + log.Printf("[DEBUG] DBInstanceIdentifier: %v", aws.StringValue(dbInstance.DBInstanceIdentifier)) + if tagMatchKeyAndValue(tagsToCheck, dbInstance.TagList) { + instanceIdentifiers = append(instanceIdentifiers, aws.StringValue(dbInstance.DBInstanceIdentifier)) + instanceARNS = append(instanceARNS, aws.StringValue(dbInstance.DBInstanceArn)) + } + } + return !lastPage + }) + + if err != nil { + return create.DiagError(names.RDS, create.ErrActionReading, DSNameInstances, "", err) } - return !lastPage - }) - if err != nil { - return create.DiagError(names.RDS, create.ErrActionReading, DSNameInstances, "", err) + log.Printf("[DEBUG] instanceARNS: %+v\n", instanceARNS) + log.Printf("[DEBUG] instanceIdentifiers: %+v\n", instanceIdentifiers) } d.SetId(meta.(*conns.AWSClient).Region) @@ -79,3 +132,25 @@ func dataSourceInstancesRead(ctx context.Context, d *schema.ResourceData, meta i return nil } + +func tagMatchKeyAndValue(tagsToCheck map[string]string, rdsInstanceTags []*rds.Tag) bool { + log.Printf("[DEBUG] Check if the following tags are present in instance tags: %v", tagsToCheck) + for key, desiredValue := range tagsToCheck { + isAMatch := false + for _, tag := range rdsInstanceTags { + if aws.StringValue(tag.Key) == key { + if aws.StringValue(tag.Value) == desiredValue { + isAMatch = true + log.Printf("[DEBUG] Matching key (%v) and value (%v)", aws.StringValue(tag.Key), aws.StringValue(tag.Value)) + break + } else { + log.Printf("[DEBUG] Matching key (%v) but not value (%v)", aws.StringValue(tag.Key), aws.StringValue(tag.Value)) + } + } + } + if !isAMatch { + return false + } + } + return true +} diff --git a/internal/service/rds/instances_data_source_test.go b/internal/service/rds/instances_data_source_test.go index cec0a8faad64..c3d50dbb71dd 100644 --- a/internal/service/rds/instances_data_source_test.go +++ b/internal/service/rds/instances_data_source_test.go @@ -40,6 +40,34 @@ func TestAccRDSInstancesDataSource_filter(t *testing.T) { }) } +func TestAccRDSInstancesDataSource_tags(t *testing.T) { + ctx := acctest.Context(t) + var dbInstance rds.DBInstance + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + // Resources. + resourceInstanceBlueStaging := "aws_db_instance.blue_staging" + resourceInstanceGreenStaging := "aws_db_instance.green_staging" + // Data sources. + datasourceBlueTeamInstance := "data.aws_db_instances.get_instance_of_blue_team" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckInstanceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccInstancesDataSourceConfig_tag(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(ctx, resourceInstanceBlueStaging, &dbInstance), + testAccCheckInstanceExists(ctx, resourceInstanceGreenStaging, &dbInstance), + resource.TestCheckResourceAttrPair(datasourceBlueTeamInstance, "instance_arns.0", resourceInstanceBlueStaging, "arn"), + ), + }, + }, + }) +} + func testAccInstancesDataSourceConfig_filter(rName string) string { return fmt.Sprintf(` data "aws_rds_engine_version" "default" { @@ -85,3 +113,65 @@ data "aws_db_instances" "test" { } `, rName) } + +func testAccInstancesDataSourceConfig_tag(rName string) string { + return fmt.Sprintf(` +data "aws_rds_engine_version" "default" { + engine = "postgres" +} + +resource "aws_db_instance" "blue_staging" { + identifier = "blue-staging-%[1]s" + allocated_storage = 10 + engine = data.aws_rds_engine_version.default.engine + engine_version = data.aws_rds_engine_version.default.version + instance_class = "db.t4g.micro" + db_name = "test" + password = "avoid-plaintext-passwords" + username = "tfacctest" + parameter_group_name = "default.${data.aws_rds_engine_version.default.parameter_group_family}" + skip_final_snapshot = true + + tags = { + Name = "blue-staging-%[1]s", + CostCenter = "ResearchDepartment", + Team = "Blue", + Environment = "staging" + } + + apply_immediately = true +} + +resource "aws_db_instance" "green_staging" { + identifier = "green-staging-%[1]s" + allocated_storage = 10 + engine = data.aws_rds_engine_version.default.engine + engine_version = data.aws_rds_engine_version.default.version + instance_class = "db.t4g.micro" + db_name = "test" + password = "avoid-plaintext-passwords" + username = "tfacctest" + parameter_group_name = "default.${data.aws_rds_engine_version.default.parameter_group_family}" + skip_final_snapshot = true + + tags = { + Name = "green-staging-%[1]s", + CostCenter = "ResearchDepartment", + Team = "Green", + Environment = "staging" + } + + apply_immediately = true +} + + +data "aws_db_instances" "get_instance_of_blue_team" { + tag { + key = "Team" + value = "Blue" + } + + depends_on = [aws_db_instance.green_staging, aws_db_instance.blue_staging] +} +`, rName) +} From b29bedfe5581161ef1805e52728afd5da964eb04 Mon Sep 17 00:00:00 2001 From: Jeremy Chauvet Date: Fri, 28 Jul 2023 17:16:51 +0200 Subject: [PATCH 2/8] enhancement: add support of tags to filter RDS instances (#2988) --- .changelog/32740.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/32740.txt diff --git a/.changelog/32740.txt b/.changelog/32740.txt new file mode 100644 index 000000000000..6bd13007e87a --- /dev/null +++ b/.changelog/32740.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +datasource/aws_db_instances: add support of tags to filter RDS instances +``` \ No newline at end of file From 4f0b2f8545241d445f304c84dd98ce92633c8435 Mon Sep 17 00:00:00 2001 From: Jeremy Chauvet Date: Fri, 28 Jul 2023 22:29:27 +0200 Subject: [PATCH 3/8] enhancement: add support of tags to filter RDS instances (#2988) --- website/docs/d/db_instances.html.markdown | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/website/docs/d/db_instances.html.markdown b/website/docs/d/db_instances.html.markdown index cad4522b360e..32f9d8e36372 100644 --- a/website/docs/d/db_instances.html.markdown +++ b/website/docs/d/db_instances.html.markdown @@ -23,19 +23,43 @@ data "aws_db_instances" "example" { } ``` +### Using tags + +```terraform +data "aws_db_instances" "example" { + tag { + key = "Company" + value = "Hashicorp" + } + + tag { + key = "Provider" + value = "AWS" + } +} +``` + ## Argument Reference The following arguments are optional: -* `filter` - (Optional) Configuration block(s) for filtering. Detailed below. +* `filter` - (Optional) Configuration block(s) used to filter instances with AWS supported attributes, such as `engine`, `db-cluster-id` or `db-instance-id` for example. Detailed below. +* `tag` - (Optional) Configuration block(s) used to filter instances with tags. Detailed below. ### filter Configuration block The `filter` configuration block supports the following arguments: -* `name` - (Required) Name of the filter field. Valid values can be found in the [RDS DescribeDBClusters API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html). +* `name` - (Required) Name of the filter field. Valid values can be found in the [RDS DescribeDBClusters API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html) or [RDS DescribeDBInstances API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBInstances.html). * `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. +### tag Configuration block + +The `tag` configuration block supports the following arguments: + +* `key` - (Required) Key for the tag. +* `value` - (Required) Value for the tag. + ## Attribute Reference This data source exports the following attributes in addition to the arguments above: From 5b9380d0ec79e59e4f82809f82b62b4871388856 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Aug 2023 15:52:38 -0400 Subject: [PATCH 4/8] Fix importlint errors. --- internal/service/rds/instances_data_source.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/rds/instances_data_source.go b/internal/service/rds/instances_data_source.go index 53047625e24a..05e10f38f9b4 100644 --- a/internal/service/rds/instances_data_source.go +++ b/internal/service/rds/instances_data_source.go @@ -5,6 +5,8 @@ package rds import ( "context" + "log" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -14,7 +16,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/generate/namevaluesfilters" "github.com/hashicorp/terraform-provider-aws/names" - "log" ) // @SDKDataSource("aws_db_instances") From 6b1e63e5ed16ae99adb069853d4a298f00967d35 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Aug 2023 15:54:29 -0400 Subject: [PATCH 5/8] Tweak CHANGELOG entry. --- .changelog/32740.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/32740.txt b/.changelog/32740.txt index 6bd13007e87a..4cd549c9264a 100644 --- a/.changelog/32740.txt +++ b/.changelog/32740.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -datasource/aws_db_instances: add support of tags to filter RDS instances +data-source/aws_db_instances: Add ability to filter by `tags` ``` \ No newline at end of file From 1df2a1c9d21611515f713aebdcf8e6114272b695 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Aug 2023 16:43:09 -0400 Subject: [PATCH 6/8] rds: Add 'findDBInstance(s)SDKv1'. --- internal/service/rds/instance.go | 53 ++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/internal/service/rds/instance.go b/internal/service/rds/instance.go index 482e644333b5..45afa19e7f0b 100644 --- a/internal/service/rds/instance.go +++ b/internal/service/rds/instance.go @@ -30,6 +30,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -2368,9 +2369,10 @@ func parseDBInstanceARN(s string) (dbInstanceARN, error) { // "db-BE6UI2KLPQP3OVDYD74ZEV6NUM" rather than a DB identifier. However, in some cases only // the identifier is available, and can be used. func findDBInstanceByIDSDKv1(ctx context.Context, conn *rds.RDS, id string) (*rds.DBInstance, error) { + idLooksLikeDbiResourceId := regexp.MustCompile(`^db-[a-zA-Z0-9]{2,255}$`).MatchString(id) input := &rds.DescribeDBInstancesInput{} - if regexp.MustCompile(`^db-[a-zA-Z0-9]{2,255}$`).MatchString(id) { + if idLooksLikeDbiResourceId { input.Filters = []*rds.Filter{ { Name: aws.String("dbi-resource-id"), @@ -2381,16 +2383,51 @@ func findDBInstanceByIDSDKv1(ctx context.Context, conn *rds.RDS, id string) (*rd input.DBInstanceIdentifier = aws.String(id) } - output, err := conn.DescribeDBInstancesWithContext(ctx, input) + output, err := findDBInstanceSDKv1(ctx, conn, input) // in case a DB has an *identifier* starting with "db-"" - if regexp.MustCompile(`^db-[a-zA-Z0-9]{2,255}$`).MatchString(id) && (output == nil || len(output.DBInstances) == 0) { - input = &rds.DescribeDBInstancesInput{ + if idLooksLikeDbiResourceId && tfresource.NotFound(err) { + input := &rds.DescribeDBInstancesInput{ DBInstanceIdentifier: aws.String(id), } - output, err = conn.DescribeDBInstancesWithContext(ctx, input) + + output, err = findDBInstanceSDKv1(ctx, conn, input) + } + + if err != nil { + return nil, err + } + + return output, nil +} + +func findDBInstanceSDKv1(ctx context.Context, conn *rds.RDS, input *rds.DescribeDBInstancesInput) (*rds.DBInstance, error) { + output, err := findDBInstancesSDKv1(ctx, conn, input, tfslices.PredicateTrue[*rds.DBInstance]()) + + if err != nil { + return nil, err } + return tfresource.AssertSinglePtrResult(output) +} + +func findDBInstancesSDKv1(ctx context.Context, conn *rds.RDS, input *rds.DescribeDBInstancesInput, filter tfslices.Predicate[*rds.DBInstance]) ([]*rds.DBInstance, error) { + var output []*rds.DBInstance + + err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *rds.DescribeDBInstancesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.DBInstances { + if v != nil && filter(v) { + output = append(output, v) + } + } + + return !lastPage + }) + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBInstanceNotFoundFault) { return nil, &retry.NotFoundError{ LastError: err, @@ -2402,11 +2439,7 @@ func findDBInstanceByIDSDKv1(ctx context.Context, conn *rds.RDS, id string) (*rd return nil, err } - if output == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return tfresource.AssertSinglePtrResult(output.DBInstances) + return output, nil } // findDBInstanceByIDSDKv2 in general should be called with a DbiResourceId of the form From a8024ae7aaded044e799fc51a24adeb07733c5a1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Aug 2023 17:06:05 -0400 Subject: [PATCH 7/8] d/aws_db_instances: 'tag' -> 'tags'. --- internal/service/rds/instances_data_source.go | 119 +++--------------- .../service/rds/instances_data_source_test.go | 61 +++++---- website/docs/d/db_instances.html.markdown | 19 +-- 3 files changed, 51 insertions(+), 148 deletions(-) diff --git a/internal/service/rds/instances_data_source.go b/internal/service/rds/instances_data_source.go index 05e10f38f9b4..96aec2101df3 100644 --- a/internal/service/rds/instances_data_source.go +++ b/internal/service/rds/instances_data_source.go @@ -5,17 +5,16 @@ package rds import ( "context" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/generate/namevaluesfilters" - "github.com/hashicorp/terraform-provider-aws/names" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) // @SDKDataSource("aws_db_instances") @@ -25,25 +24,6 @@ func DataSourceInstances() *schema.Resource { Schema: map[string]*schema.Schema{ "filter": namevaluesfilters.Schema(), - "tag": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, - }, - "value": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, - }, - }, - }, - }, - // Computed values. "instance_arns": { Type: schema.TypeList, Computed: true, @@ -54,104 +34,45 @@ func DataSourceInstances() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "tags": tftags.TagsSchemaComputed(), }, } } -const ( - DSNameInstances = "Instances Data Source" -) - func dataSourceInstancesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics conn := meta.(*conns.AWSClient).RDSConn(ctx) input := &rds.DescribeDBInstancesInput{} - var instanceARNS []string - var instanceIdentifiers []string if v, ok := d.GetOk("filter"); ok { input.Filters = namevaluesfilters.New(v.(*schema.Set)).RDSFilters() - - err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *rds.DescribeDBInstancesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - for _, dbInstance := range page.DBInstances { - if dbInstance == nil { - continue - } - - instanceARNS = append(instanceARNS, aws.StringValue(dbInstance.DBInstanceArn)) - instanceIdentifiers = append(instanceIdentifiers, aws.StringValue(dbInstance.DBInstanceIdentifier)) - } - - return !lastPage - }) - if err != nil { - return create.DiagError(names.RDS, create.ErrActionReading, DSNameInstances, "", err) - } } - if v, ok := d.GetOk("tag"); ok { - // Build map of tags to check, based on user request. - tags := v.(*schema.Set).List() - tagsToCheck := make(map[string]string) - for _, tag := range tags { - tagMap := tag.(map[string]interface{}) - key := tagMap["key"].(string) - value := tagMap["value"].(string) - tagsToCheck[key] = value + filter := tfslices.PredicateTrue[*rds.DBInstance]() + if v, ok := d.GetOk("tags"); ok { + filter = func(x *rds.DBInstance) bool { + return KeyValueTags(ctx, x.TagList).ContainsAll(tftags.New(ctx, v.(map[string]interface{}))) } + } - err := conn.DescribeDBInstancesPagesWithContext(ctx, input, func(page *rds.DescribeDBInstancesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } + instances, err := findDBInstancesSDKv1(ctx, conn, input, filter) - for _, dbInstance := range page.DBInstances { - log.Printf("[DEBUG] DBInstanceIdentifier: %v", aws.StringValue(dbInstance.DBInstanceIdentifier)) - if tagMatchKeyAndValue(tagsToCheck, dbInstance.TagList) { - instanceIdentifiers = append(instanceIdentifiers, aws.StringValue(dbInstance.DBInstanceIdentifier)) - instanceARNS = append(instanceARNS, aws.StringValue(dbInstance.DBInstanceArn)) - } - } - return !lastPage - }) + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading RDS DB Instances: %s", err) + } - if err != nil { - return create.DiagError(names.RDS, create.ErrActionReading, DSNameInstances, "", err) - } + var instanceARNS []string + var instanceIdentifiers []string - log.Printf("[DEBUG] instanceARNS: %+v\n", instanceARNS) - log.Printf("[DEBUG] instanceIdentifiers: %+v\n", instanceIdentifiers) + for _, instance := range instances { + instanceARNS = append(instanceARNS, aws.StringValue(instance.DBInstanceArn)) + instanceIdentifiers = append(instanceIdentifiers, aws.StringValue(instance.DBInstanceIdentifier)) } d.SetId(meta.(*conns.AWSClient).Region) d.Set("instance_arns", instanceARNS) d.Set("instance_identifiers", instanceIdentifiers) - return nil -} - -func tagMatchKeyAndValue(tagsToCheck map[string]string, rdsInstanceTags []*rds.Tag) bool { - log.Printf("[DEBUG] Check if the following tags are present in instance tags: %v", tagsToCheck) - for key, desiredValue := range tagsToCheck { - isAMatch := false - for _, tag := range rdsInstanceTags { - if aws.StringValue(tag.Key) == key { - if aws.StringValue(tag.Value) == desiredValue { - isAMatch = true - log.Printf("[DEBUG] Matching key (%v) and value (%v)", aws.StringValue(tag.Key), aws.StringValue(tag.Value)) - break - } else { - log.Printf("[DEBUG] Matching key (%v) but not value (%v)", aws.StringValue(tag.Key), aws.StringValue(tag.Value)) - } - } - } - if !isAMatch { - return false - } - } - return true + return diags } diff --git a/internal/service/rds/instances_data_source_test.go b/internal/service/rds/instances_data_source_test.go index c3d50dbb71dd..b95684c8f287 100644 --- a/internal/service/rds/instances_data_source_test.go +++ b/internal/service/rds/instances_data_source_test.go @@ -44,11 +44,8 @@ func TestAccRDSInstancesDataSource_tags(t *testing.T) { ctx := acctest.Context(t) var dbInstance rds.DBInstance rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - // Resources. - resourceInstanceBlueStaging := "aws_db_instance.blue_staging" - resourceInstanceGreenStaging := "aws_db_instance.green_staging" - // Data sources. - datasourceBlueTeamInstance := "data.aws_db_instances.get_instance_of_blue_team" + dataSourceName := "data.aws_db_instances.test" + resourceName := "aws_db_instance.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -57,11 +54,13 @@ func TestAccRDSInstancesDataSource_tags(t *testing.T) { CheckDestroy: testAccCheckInstanceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccInstancesDataSourceConfig_tag(rName), + Config: testAccInstancesDataSourceConfig_tags(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckInstanceExists(ctx, resourceInstanceBlueStaging, &dbInstance), - testAccCheckInstanceExists(ctx, resourceInstanceGreenStaging, &dbInstance), - resource.TestCheckResourceAttrPair(datasourceBlueTeamInstance, "instance_arns.0", resourceInstanceBlueStaging, "arn"), + testAccCheckInstanceExists(ctx, resourceName, &dbInstance), + resource.TestCheckResourceAttr(dataSourceName, "instance_arns.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "instance_arns.0", resourceName, "arn"), + resource.TestCheckResourceAttr(dataSourceName, "instance_identifiers.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "instance_identifiers.0", resourceName, "identifier"), ), }, }, @@ -90,7 +89,7 @@ resource "aws_db_instance" "test" { } resource "aws_db_instance" "wrong" { - identifier = "wrong-%[1]s" + identifier = "%[1]s-wrong" allocated_storage = 10 engine = data.aws_rds_engine_version.default.engine engine_version = data.aws_rds_engine_version.default.version @@ -110,18 +109,20 @@ data "aws_db_instances" "test" { name = "db-instance-id" values = [aws_db_instance.test.identifier] } + + depends_on = [aws_db_instance.wrong] } `, rName) } -func testAccInstancesDataSourceConfig_tag(rName string) string { +func testAccInstancesDataSourceConfig_tags(rName string) string { return fmt.Sprintf(` data "aws_rds_engine_version" "default" { engine = "postgres" } -resource "aws_db_instance" "blue_staging" { - identifier = "blue-staging-%[1]s" +resource "aws_db_instance" "test" { + identifier = %[1]q allocated_storage = 10 engine = data.aws_rds_engine_version.default.engine engine_version = data.aws_rds_engine_version.default.version @@ -132,18 +133,16 @@ resource "aws_db_instance" "blue_staging" { parameter_group_name = "default.${data.aws_rds_engine_version.default.parameter_group_family}" skip_final_snapshot = true + apply_immediately = true + tags = { - Name = "blue-staging-%[1]s", - CostCenter = "ResearchDepartment", - Team = "Blue", - Environment = "staging" + Name = %[1]q + Test = "true" } - - apply_immediately = true } -resource "aws_db_instance" "green_staging" { - identifier = "green-staging-%[1]s" +resource "aws_db_instance" "wrong" { + identifier = "%[1]s-wrong" allocated_storage = 10 engine = data.aws_rds_engine_version.default.engine engine_version = data.aws_rds_engine_version.default.version @@ -154,24 +153,20 @@ resource "aws_db_instance" "green_staging" { parameter_group_name = "default.${data.aws_rds_engine_version.default.parameter_group_family}" skip_final_snapshot = true + apply_immediately = true + tags = { - Name = "green-staging-%[1]s", - CostCenter = "ResearchDepartment", - Team = "Green", - Environment = "staging" + Name = "%[1]s-wrong" + Test = "true" } - - apply_immediately = true } - -data "aws_db_instances" "get_instance_of_blue_team" { - tag { - key = "Team" - value = "Blue" +data "aws_db_instances" "test" { + tags = { + Name = %[1]q } - depends_on = [aws_db_instance.green_staging, aws_db_instance.blue_staging] + depends_on = [aws_db_instance.test, aws_db_instance.wrong] } `, rName) } diff --git a/website/docs/d/db_instances.html.markdown b/website/docs/d/db_instances.html.markdown index 32f9d8e36372..3bd004db4bc1 100644 --- a/website/docs/d/db_instances.html.markdown +++ b/website/docs/d/db_instances.html.markdown @@ -27,14 +27,8 @@ data "aws_db_instances" "example" { ```terraform data "aws_db_instances" "example" { - tag { - key = "Company" - value = "Hashicorp" - } - - tag { - key = "Provider" - value = "AWS" + tags = { + Env = "test" } } ``` @@ -44,7 +38,7 @@ data "aws_db_instances" "example" { The following arguments are optional: * `filter` - (Optional) Configuration block(s) used to filter instances with AWS supported attributes, such as `engine`, `db-cluster-id` or `db-instance-id` for example. Detailed below. -* `tag` - (Optional) Configuration block(s) used to filter instances with tags. Detailed below. +* `tags` - (Optional) Map of tags, each pair of which must exactly match a pair on the desired instances. ### filter Configuration block @@ -53,13 +47,6 @@ The `filter` configuration block supports the following arguments: * `name` - (Required) Name of the filter field. Valid values can be found in the [RDS DescribeDBClusters API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html) or [RDS DescribeDBInstances API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBInstances.html). * `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. -### tag Configuration block - -The `tag` configuration block supports the following arguments: - -* `key` - (Required) Key for the tag. -* `value` - (Required) Value for the tag. - ## Attribute Reference This data source exports the following attributes in addition to the arguments above: From 35302ef215a52033dfb052fdcd1e246e92422658 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Aug 2023 17:48:12 -0400 Subject: [PATCH 8/8] d/aws_db_instance: Add ability to filter by 'tags'. --- .changelog/32740.txt | 4 + internal/service/rds/instance_data_source.go | 155 +++++++++++------- .../service/rds/instance_data_source_test.go | 84 ++++++++++ internal/service/rds/service_package_gen.go | 2 + website/docs/d/db_instance.html.markdown | 3 +- 5 files changed, 184 insertions(+), 64 deletions(-) diff --git a/.changelog/32740.txt b/.changelog/32740.txt index 4cd549c9264a..f1c96526b1b4 100644 --- a/.changelog/32740.txt +++ b/.changelog/32740.txt @@ -1,3 +1,7 @@ ```release-note:enhancement data-source/aws_db_instances: Add ability to filter by `tags` +``` + +```release-note:enhancement +data-source/aws_db_instance: Add ability to filter by `tags` ``` \ No newline at end of file diff --git a/internal/service/rds/instance_data_source.go b/internal/service/rds/instance_data_source.go index 97eeb472ae2e..500871a8f4e7 100644 --- a/internal/service/rds/instance_data_source.go +++ b/internal/service/rds/instance_data_source.go @@ -8,16 +8,19 @@ import ( "fmt" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_db_instance") +// @SDKDataSource("aws_db_instance", name="DB Instance") +// @Tags func DataSourceInstance() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceInstanceRead, @@ -60,9 +63,9 @@ func DataSourceInstance() *schema.Resource { Computed: true, }, "db_instance_identifier": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, + Type: schema.TypeString, + Optional: true, + Computed: true, }, "db_instance_port": { Type: schema.TypeInt, @@ -199,7 +202,7 @@ func DataSourceInstance() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "tags": tftags.TagsSchemaComputed(), + names.AttrTags: tftags.TagsSchemaComputed(), "timezone": { Type: schema.TypeString, Computed: true, @@ -216,74 +219,104 @@ func DataSourceInstance() *schema.Resource { func dataSourceInstanceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).RDSConn(ctx) - ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - v, err := findDBInstanceByIDSDKv1(ctx, conn, d.Get("db_instance_identifier").(string)) - if err != nil { - return diag.FromErr(tfresource.SingularDataSourceFindError("RDS DB Instance", err)) + var instance *rds.DBInstance + + filter := tfslices.PredicateTrue[*rds.DBInstance]() + if tags := getTagsIn(ctx); len(tags) > 0 { + filter = func(v *rds.DBInstance) bool { + return KeyValueTags(ctx, v.TagList).ContainsAll(KeyValueTags(ctx, tags)) + } } - d.SetId(aws.StringValue(v.DBInstanceIdentifier)) - d.Set("allocated_storage", v.AllocatedStorage) - d.Set("auto_minor_version_upgrade", v.AutoMinorVersionUpgrade) - d.Set("availability_zone", v.AvailabilityZone) - d.Set("backup_retention_period", v.BackupRetentionPeriod) - d.Set("ca_cert_identifier", v.CACertificateIdentifier) - d.Set("db_cluster_identifier", v.DBClusterIdentifier) - d.Set("db_instance_arn", v.DBInstanceArn) - d.Set("db_instance_class", v.DBInstanceClass) - d.Set("db_instance_port", v.DbInstancePort) - d.Set("db_name", v.DBName) - var parameterGroupNames []string - for _, v := range v.DBParameterGroups { - parameterGroupNames = append(parameterGroupNames, aws.StringValue(v.DBParameterGroupName)) + if v, ok := d.GetOk("db_instance_identifier"); ok { + id := v.(string) + output, err := findDBInstanceByIDSDKv1(ctx, conn, id) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading RDS DB Instance (%s): %s", id, err) + } + + if !filter(output) { + return sdkdiag.AppendErrorf(diags, "Your query returned no results. Please change your search criteria and try again.") + } + + instance = output + } else { + input := &rds.DescribeDBInstancesInput{} + instances, err := findDBInstancesSDKv1(ctx, conn, input, filter) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading RDS DB Instances: %s", err) + } + + output, err := tfresource.AssertSinglePtrResult(instances) + + if err != nil { + return sdkdiag.AppendFromErr(diags, tfresource.SingularDataSourceFindError("RDS DB Instance", err)) + } + + instance = output } + + d.SetId(aws.StringValue(instance.DBInstanceIdentifier)) + d.Set("allocated_storage", instance.AllocatedStorage) + d.Set("auto_minor_version_upgrade", instance.AutoMinorVersionUpgrade) + d.Set("availability_zone", instance.AvailabilityZone) + d.Set("backup_retention_period", instance.BackupRetentionPeriod) + d.Set("ca_cert_identifier", instance.CACertificateIdentifier) + d.Set("db_cluster_identifier", instance.DBClusterIdentifier) + d.Set("db_instance_arn", instance.DBInstanceArn) + d.Set("db_instance_class", instance.DBInstanceClass) + d.Set("db_instance_port", instance.DbInstancePort) + d.Set("db_name", instance.DBName) + parameterGroupNames := tfslices.ApplyToAll(instance.DBParameterGroups, func(v *rds.DBParameterGroupStatus) string { + return aws.StringValue(v.DBParameterGroupName) + }) d.Set("db_parameter_groups", parameterGroupNames) - if v.DBSubnetGroup != nil { - d.Set("db_subnet_group", v.DBSubnetGroup.DBSubnetGroupName) + if instance.DBSubnetGroup != nil { + d.Set("db_subnet_group", instance.DBSubnetGroup.DBSubnetGroupName) } else { d.Set("db_subnet_group", "") } - d.Set("enabled_cloudwatch_logs_exports", aws.StringValueSlice(v.EnabledCloudwatchLogsExports)) - d.Set("engine", v.Engine) - d.Set("engine_version", v.EngineVersion) - d.Set("iops", v.Iops) - d.Set("kms_key_id", v.KmsKeyId) - d.Set("license_model", v.LicenseModel) - d.Set("master_username", v.MasterUsername) - if v.MasterUserSecret != nil { - if err := d.Set("master_user_secret", []interface{}{flattenManagedMasterUserSecret(v.MasterUserSecret)}); err != nil { + d.Set("enabled_cloudwatch_logs_exports", aws.StringValueSlice(instance.EnabledCloudwatchLogsExports)) + d.Set("engine", instance.Engine) + d.Set("engine_version", instance.EngineVersion) + d.Set("iops", instance.Iops) + d.Set("kms_key_id", instance.KmsKeyId) + d.Set("license_model", instance.LicenseModel) + d.Set("master_username", instance.MasterUsername) + if instance.MasterUserSecret != nil { + if err := d.Set("master_user_secret", []interface{}{flattenManagedMasterUserSecret(instance.MasterUserSecret)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting master_user_secret: %s", err) } } - d.Set("max_allocated_storage", v.MaxAllocatedStorage) - d.Set("monitoring_interval", v.MonitoringInterval) - d.Set("monitoring_role_arn", v.MonitoringRoleArn) - d.Set("multi_az", v.MultiAZ) - d.Set("network_type", v.NetworkType) - var optionGroupNames []string - for _, v := range v.OptionGroupMemberships { - optionGroupNames = append(optionGroupNames, aws.StringValue(v.OptionGroupName)) - } + d.Set("max_allocated_storage", instance.MaxAllocatedStorage) + d.Set("monitoring_interval", instance.MonitoringInterval) + d.Set("monitoring_role_arn", instance.MonitoringRoleArn) + d.Set("multi_az", instance.MultiAZ) + d.Set("network_type", instance.NetworkType) + optionGroupNames := tfslices.ApplyToAll(instance.OptionGroupMemberships, func(v *rds.OptionGroupMembership) string { + return aws.StringValue(v.OptionGroupName) + }) d.Set("option_group_memberships", optionGroupNames) - d.Set("preferred_backup_window", v.PreferredBackupWindow) - d.Set("preferred_maintenance_window", v.PreferredMaintenanceWindow) - d.Set("publicly_accessible", v.PubliclyAccessible) - d.Set("replicate_source_db", v.ReadReplicaSourceDBInstanceIdentifier) - d.Set("resource_id", v.DbiResourceId) - d.Set("storage_encrypted", v.StorageEncrypted) - d.Set("storage_throughput", v.StorageThroughput) - d.Set("storage_type", v.StorageType) - d.Set("timezone", v.Timezone) - var vpcSecurityGroupIDs []string - for _, v := range v.VpcSecurityGroups { - vpcSecurityGroupIDs = append(vpcSecurityGroupIDs, aws.StringValue(v.VpcSecurityGroupId)) - } + d.Set("preferred_backup_window", instance.PreferredBackupWindow) + d.Set("preferred_maintenance_window", instance.PreferredMaintenanceWindow) + d.Set("publicly_accessible", instance.PubliclyAccessible) + d.Set("replicate_source_db", instance.ReadReplicaSourceDBInstanceIdentifier) + d.Set("resource_id", instance.DbiResourceId) + d.Set("storage_encrypted", instance.StorageEncrypted) + d.Set("storage_throughput", instance.StorageThroughput) + d.Set("storage_type", instance.StorageType) + d.Set("timezone", instance.Timezone) + vpcSecurityGroupIDs := tfslices.ApplyToAll(instance.VpcSecurityGroups, func(v *rds.VpcSecurityGroupMembership) string { + return aws.StringValue(v.VpcSecurityGroupId) + }) d.Set("vpc_security_groups", vpcSecurityGroupIDs) // Per AWS SDK Go docs: // The endpoint might not be shown for instances whose status is creating. - if dbEndpoint := v.Endpoint; dbEndpoint != nil { + if dbEndpoint := instance.Endpoint; dbEndpoint != nil { d.Set("address", dbEndpoint.Address) d.Set("endpoint", fmt.Sprintf("%s:%d", aws.StringValue(dbEndpoint.Address), aws.Int64Value(dbEndpoint.Port))) d.Set("hosted_zone_id", dbEndpoint.HostedZoneId) @@ -295,11 +328,7 @@ func dataSourceInstanceRead(ctx context.Context, d *schema.ResourceData, meta in d.Set("port", nil) } - tags := KeyValueTags(ctx, v.TagList) - - if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) - } + setTagsOut(ctx, instance.TagList) return diags } diff --git a/internal/service/rds/instance_data_source_test.go b/internal/service/rds/instance_data_source_test.go index bada70ef3513..c2b217b81535 100644 --- a/internal/service/rds/instance_data_source_test.go +++ b/internal/service/rds/instance_data_source_test.go @@ -104,6 +104,51 @@ func TestAccRDSInstanceDataSource_ManagedMasterPassword_managed(t *testing.T) { }) } +func TestAccRDSInstanceDataSource_tags(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_db_instance.test" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccInstanceDataSourceConfig_tags(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "address", resourceName, "address"), + resource.TestCheckResourceAttrPair(dataSourceName, "allocated_storage", resourceName, "allocated_storage"), + resource.TestCheckResourceAttrPair(dataSourceName, "auto_minor_version_upgrade", resourceName, "auto_minor_version_upgrade"), + resource.TestCheckResourceAttrPair(dataSourceName, "db_instance_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "db_instance_class", resourceName, "instance_class"), + resource.TestCheckResourceAttrPair(dataSourceName, "db_name", resourceName, "db_name"), + resource.TestCheckResourceAttrPair(dataSourceName, "db_subnet_group", resourceName, "db_subnet_group_name"), + resource.TestCheckResourceAttrPair(dataSourceName, "enabled_cloudwatch_logs_exports.#", resourceName, "enabled_cloudwatch_logs_exports.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "endpoint", resourceName, "endpoint"), + resource.TestCheckResourceAttrPair(dataSourceName, "engine", resourceName, "engine"), + resource.TestCheckResourceAttrPair(dataSourceName, "hosted_zone_id", resourceName, "hosted_zone_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "iops", resourceName, "iops"), + resource.TestCheckResourceAttrPair(dataSourceName, "master_username", resourceName, "username"), + resource.TestCheckResourceAttrPair(dataSourceName, "max_allocated_storage", resourceName, "max_allocated_storage"), + resource.TestCheckResourceAttrPair(dataSourceName, "multi_az", resourceName, "multi_az"), + resource.TestCheckResourceAttrPair(dataSourceName, "network_type", resourceName, "network_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "port", resourceName, "port"), + resource.TestCheckResourceAttrPair(dataSourceName, "resource_id", resourceName, "resource_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "storage_throughput", resourceName, "storage_throughput"), + resource.TestCheckResourceAttrPair(dataSourceName, "storage_type", resourceName, "storage_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + ), + }, + }, + }) +} + func testAccInstanceDataSourceConfig_basic(rName string) string { return acctest.ConfigCompose( testAccInstanceConfig_orderableClassMariadb(), @@ -167,3 +212,42 @@ data "aws_db_instance" "test" { } `, rName)) } + +func testAccInstanceDataSourceConfig_tags(rName string) string { + return acctest.ConfigCompose( + testAccInstanceConfig_orderableClassMariadb(), + testAccInstanceConfig_baseVPC(rName), + fmt.Sprintf(` +resource "aws_db_instance" "test" { + allocated_storage = 10 + backup_retention_period = 0 + db_subnet_group_name = aws_db_subnet_group.test.name + engine = data.aws_rds_engine_version.default.engine + engine_version = data.aws_rds_engine_version.default.version + identifier = %[1]q + instance_class = data.aws_rds_orderable_db_instance.test.instance_class + db_name = "test" + password = "avoid-plaintext-passwords" + skip_final_snapshot = true + username = "tfacctest" + max_allocated_storage = 100 + + enabled_cloudwatch_logs_exports = [ + "audit", + "error", + ] + + tags = { + Name = %[1]q + } +} + +data "aws_db_instance" "test" { + tags = { + Name = %[1]q + } + + depends_on = [aws_db_instance.test] +} +`, rName)) +} diff --git a/internal/service/rds/service_package_gen.go b/internal/service/rds/service_package_gen.go index a8589234c255..e66ec36d2c06 100644 --- a/internal/service/rds/service_package_gen.go +++ b/internal/service/rds/service_package_gen.go @@ -44,6 +44,8 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac { Factory: DataSourceInstance, TypeName: "aws_db_instance", + Name: "DB Instance", + Tags: &types.ServicePackageResourceTags{}, }, { Factory: DataSourceInstances, diff --git a/website/docs/d/db_instance.html.markdown b/website/docs/d/db_instance.html.markdown index 4cf6f9604b76..ade4a86fbb64 100644 --- a/website/docs/d/db_instance.html.markdown +++ b/website/docs/d/db_instance.html.markdown @@ -22,7 +22,8 @@ data "aws_db_instance" "database" { This data source supports the following arguments: -* `db_instance_identifier` - (Required) Name of the RDS instance +* `db_instance_identifier` - (Optional) Name of the RDS instance. +* `tags` - (Optional) Map of tags, each pair of which must exactly match a pair on the desired instance. ## Attribute Reference