diff --git a/.changelog/36080.txt b/.changelog/36080.txt new file mode 100644 index 00000000000..b9b0bdbf5ec --- /dev/null +++ b/.changelog/36080.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_db_instance: Correctly sets `parameter_group_name` when `replicate_source_db` is in different region. +``` diff --git a/docs/running-and-writing-acceptance-tests.md b/docs/running-and-writing-acceptance-tests.md index b4b31e5afc3..44691313d7b 100644 --- a/docs/running-and-writing-acceptance-tests.md +++ b/docs/running-and-writing-acceptance-tests.md @@ -897,7 +897,8 @@ func TestAccExample_basic(t *testing.T) { } func testAccExampleConfig() string { - return acctest.ConfigAlternateAccountProvider() + fmt.Sprintf(` + return acctest.ConfigCompose( + acctest.ConfigAlternateAccountProvider(), fmt.Sprintf(` # Cross account resources should be handled by the cross account provider. # The standardized provider block to use is awsalternate as seen below. resource "aws_cross_account_example" "test" { @@ -911,7 +912,7 @@ resource "aws_cross_account_example" "test" { resource "aws_example" "test" { # ... configuration ... } -`) +`, ...)) } ``` @@ -961,7 +962,8 @@ func TestAccExample_basic(t *testing.T) { } func testAccExampleConfig() string { - return acctest.ConfigMultipleRegionProvider(2) + fmt.Sprintf(` + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` # Cross region resources should be handled by the cross region provider. # The standardized provider is awsalternate as seen below. resource "aws_cross_region_example" "test" { @@ -975,7 +977,7 @@ resource "aws_cross_region_example" "test" { resource "aws_example" "test" { # ... configuration ... } -`) +`, ...)) } ``` diff --git a/internal/service/rds/instance.go b/internal/service/rds/instance.go index 53857e25d1c..269e37933b6 100644 --- a/internal/service/rds/instance.go +++ b/internal/service/rds/instance.go @@ -768,6 +768,20 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, meta in input.OptionGroupName = aws.String(v.(string)) } + if v, ok := d.GetOk("parameter_group_name"); ok { + crossRegion := false + if arn.IsARN(sourceDBInstanceID) { + sourceARN, err := arn.Parse(sourceDBInstanceID) + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating RDS DB Instance (read replica) (%s): %s", identifier, err) + } + crossRegion = sourceARN.Region != meta.(*conns.AWSClient).Region + } + if crossRegion { + input.DBParameterGroupName = aws.String(v.(string)) + } + } + if v, ok := d.GetOk("performance_insights_enabled"); ok { input.EnablePerformanceInsights = aws.Bool(v.(bool)) } diff --git a/internal/service/rds/instance_test.go b/internal/service/rds/instance_test.go index 7661f7f24de..fd0d9fdb136 100644 --- a/internal/service/rds/instance_test.go +++ b/internal/service/rds/instance_test.go @@ -19,6 +19,7 @@ import ( "github.com/aws/aws-sdk-go/service/rds" tfawserr_sdkv2 "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/plancheck" @@ -1040,6 +1041,7 @@ func TestAccRDSInstance_ReplicateSourceDB_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "identifier", rName), resource.TestCheckResourceAttr(resourceName, "identifier_prefix", ""), testAccCheckInstanceReplicaAttributes(&sourceDbInstance, &dbInstance), + resource.TestCheckResourceAttrPair(resourceName, "replicate_source_db", sourceResourceName, "identifier"), resource.TestCheckResourceAttrPair(resourceName, "db_name", sourceResourceName, "db_name"), resource.TestCheckResourceAttrPair(resourceName, "username", sourceResourceName, "username"), @@ -2145,6 +2147,50 @@ func TestAccRDSInstance_ReplicateSourceDB_parameterGroupTwoStep(t *testing.T) { }) } +func TestAccRDSInstance_ReplicateSourceDB_CrossRegion_parameterGroupNameEquivalent(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var dbInstance, sourceDbInstance rds.DBInstance + var providers []*schema.Provider + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + sourceResourceName := "aws_db_instance.source" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RDSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesPlusProvidersAlternate(ctx, t, &providers), + CheckDestroy: testAccCheckInstanceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfig_ReplicateSourceDB_CrossRegion_ParameterGroupName_equivalent(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInstanceExistsWithProvider(ctx, sourceResourceName, &sourceDbInstance, acctest.RegionProviderFunc(acctest.AlternateRegion(), &providers)), + resource.TestCheckResourceAttr(sourceResourceName, "parameter_group_name", fmt.Sprintf("%s-source", rName)), + testAccCheckInstanceExistsWithProvider(ctx, resourceName, &dbInstance, acctest.RegionProviderFunc(acctest.Region(), &providers)), + resource.TestCheckResourceAttrPair(resourceName, "replicate_source_db", sourceResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "parameter_group_name", "aws_db_parameter_group.test", "name"), + testAccCheckInstanceParameterApplyStatusInSync(&dbInstance), + testAccCheckInstanceParameterApplyStatusInSync(&sourceDbInstance), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "apply_immediately", + "password", + }, + }, + }, + }) +} + func TestAccRDSInstance_s3Import(t *testing.T) { acctest.Skip(t, "RestoreDBInstanceFromS3 cannot restore from MySQL version 5.6") @@ -6204,6 +6250,10 @@ func dbInstanceIdentity(v *rds.DBInstance) string { } func testAccCheckInstanceExists(ctx context.Context, n string, v *rds.DBInstance) resource.TestCheckFunc { + return testAccCheckInstanceExistsWithProvider(ctx, n, v, func() *schema.Provider { return acctest.Provider }) +} + +func testAccCheckInstanceExistsWithProvider(ctx context.Context, n string, v *rds.DBInstance, providerF func() *schema.Provider) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -6214,7 +6264,7 @@ func testAccCheckInstanceExists(ctx context.Context, n string, v *rds.DBInstance return fmt.Errorf("No RDS DB Instance ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).RDSConn(ctx) + conn := providerF().Meta().(*conns.AWSClient).RDSConn(ctx) output, err := tfrds.FindDBInstanceByID(ctx, conn, rs.Primary.ID) if err != nil { @@ -9585,6 +9635,79 @@ resource "aws_db_parameter_group" "test" { `, rName)) } +func testAccInstanceConfig_ReplicateSourceDB_CrossRegion_ParameterGroupName_equivalent(rName string) string { + parameters := ` +parameter { + # "max_string_size" cannot be changed after creation + name = "max_string_size" + value = "EXTENDED" + apply_method = "immediate" +} +` + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(2), fmt.Sprintf(` +resource "aws_db_instance" "test" { + provider = "aws" + + identifier = %[1]q + replicate_source_db = aws_db_instance.source.arn + instance_class = data.aws_rds_orderable_db_instance.test.instance_class + skip_final_snapshot = true + apply_immediately = true + parameter_group_name = aws_db_parameter_group.test.name +} + +resource "aws_db_parameter_group" "test" { + provider = "aws" + + family = data.aws_rds_engine_version.default.parameter_group_family + name = %[1]q + + %[4]s +} + +resource "aws_db_instance" "source" { + provider = "awsalternate" + + identifier = "%[1]s-source" + allocated_storage = 20 + engine = data.aws_rds_orderable_db_instance.test.engine + engine_version = data.aws_rds_orderable_db_instance.test.engine_version + instance_class = data.aws_rds_orderable_db_instance.test.instance_class + storage_type = data.aws_rds_orderable_db_instance.test.storage_type + db_name = "MAINDB" + username = "oadmin" + password = "avoid-plaintext-passwords" + skip_final_snapshot = true + apply_immediately = true + backup_retention_period = 3 + parameter_group_name = aws_db_parameter_group.source.name +} + +resource "aws_db_parameter_group" "source" { + provider = "awsalternate" + + family = data.aws_rds_engine_version.default.parameter_group_family + name = "%[1]s-source" + + %[4]s +} + +data "aws_rds_engine_version" "default" { + engine = %[2]q +} + +data "aws_rds_orderable_db_instance" "test" { + engine = data.aws_rds_engine_version.default.engine + engine_version = data.aws_rds_engine_version.default.version + license_model = "bring-your-own-license" + storage_type = "gp2" + read_replica_capable = true + preferred_instance_classes = [%[3]s] +} +`, rName, tfrds.InstanceEngineOracleEnterprise, strings.Replace(mainInstanceClasses, "db.t3.small", "frodo", 1), parameters)) +} + func testAccInstanceConfig_baseMonitoringRole(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {}