Skip to content

Commit 62ebec3

Browse files
authored
Merge pull request #31336 from AdamTylerLynch/f-rds_aurora_storage_type
Aurora I/O-Optimized (storage_type)
2 parents 5ed9cbe + 9d852cf commit 62ebec3

File tree

6 files changed

+243
-20
lines changed

6 files changed

+243
-20
lines changed

.changelog/31336.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resource/aws_rds_cluster: Add ability to specify Aurora IO Optimized `storage_type`
3+
```

internal/service/rds/cluster.go

+24-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/aws/aws-sdk-go/service/rds"
1414
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
1515
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
16+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
1617
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
1718
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
1819
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -489,7 +490,7 @@ func ResourceCluster() *schema.Resource {
489490
"storage_type": {
490491
Type: schema.TypeString,
491492
Optional: true,
492-
ForceNew: true,
493+
Computed: true,
493494
},
494495
names.AttrTags: tftags.TagsSchema(),
495496
names.AttrTagsAll: tftags.TagsSchemaComputed(),
@@ -501,7 +502,28 @@ func ResourceCluster() *schema.Resource {
501502
},
502503
},
503504

504-
CustomizeDiff: verify.SetTagsDiff,
505+
CustomizeDiff: customdiff.Sequence(
506+
verify.SetTagsDiff,
507+
customdiff.ForceNewIf("storage_type", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool {
508+
// Aurora supports mutation of the storage_type parameter, other engines do not
509+
return !strings.HasPrefix(d.Get("engine").(string), "aurora")
510+
}),
511+
func(_ context.Context, diff *schema.ResourceDiff, _ any) error {
512+
if diff.Id() == "" {
513+
return nil
514+
}
515+
// The control plane will always return an empty string if a cluster is created with a storage_type of aurora
516+
old, new := diff.GetChange("storage_type")
517+
518+
if new.(string) == "aurora" && old.(string) == "" {
519+
if err := diff.SetNew("storage_type", ""); err != nil {
520+
return err
521+
}
522+
return nil
523+
}
524+
return nil
525+
},
526+
),
505527
}
506528
}
507529

internal/service/rds/cluster_test.go

+200-3
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ func TestAccRDSCluster_availabilityZones(t *testing.T) {
525525
})
526526
}
527527

528-
func TestAccRDSCluster_storageType(t *testing.T) {
528+
func TestAccRDSCluster_storageTypeIo1(t *testing.T) {
529529
if testing.Short() {
530530
t.Skip("skipping long-running test in short mode")
531531
}
@@ -542,7 +542,7 @@ func TestAccRDSCluster_storageType(t *testing.T) {
542542
CheckDestroy: testAccCheckClusterDestroy(ctx),
543543
Steps: []resource.TestStep{
544544
{
545-
Config: testAccClusterConfig_storageType(rName),
545+
Config: testAccClusterConfig_storageTypeIo1(rName),
546546
Check: resource.ComposeTestCheckFunc(
547547
testAccCheckClusterExists(ctx, resourceName, &dbCluster),
548548
resource.TestCheckResourceAttr(resourceName, "storage_type", "io1"),
@@ -552,6 +552,101 @@ func TestAccRDSCluster_storageType(t *testing.T) {
552552
})
553553
}
554554

555+
// For backwards compatibility, the control plane should always return a blank string even if sending "aurora" as the storage type
556+
func TestAccRDSCluster_storageTypeAuroraReturnsBlank(t *testing.T) {
557+
if testing.Short() {
558+
t.Skip("skipping long-running test in short mode")
559+
}
560+
561+
ctx := acctest.Context(t)
562+
var dbCluster1 rds.DBCluster
563+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
564+
storageTypeAurora := "aurora"
565+
storageTypeEmpty := ""
566+
resourceName := "aws_rds_cluster.test"
567+
568+
resource.ParallelTest(t, resource.TestCase{
569+
PreCheck: func() { acctest.PreCheck(ctx, t) },
570+
ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID),
571+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
572+
CheckDestroy: testAccCheckClusterDestroy(ctx),
573+
Steps: []resource.TestStep{
574+
{
575+
Config: testAccClusterConfig_auroraStorageType(rName, storageTypeAurora),
576+
Check: resource.ComposeTestCheckFunc(
577+
testAccCheckClusterExists(ctx, resourceName, &dbCluster1),
578+
resource.TestCheckResourceAttr(resourceName, "storage_type", storageTypeEmpty),
579+
),
580+
},
581+
},
582+
})
583+
}
584+
585+
func TestAccRDSCluster_storageTypeAuroraIopt1(t *testing.T) {
586+
if testing.Short() {
587+
t.Skip("skipping long-running test in short mode")
588+
}
589+
590+
ctx := acctest.Context(t)
591+
var dbCluster rds.DBCluster
592+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
593+
storageType := "aurora-iopt1"
594+
resourceName := "aws_rds_cluster.test"
595+
596+
resource.ParallelTest(t, resource.TestCase{
597+
PreCheck: func() { acctest.PreCheck(ctx, t) },
598+
ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID),
599+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
600+
CheckDestroy: testAccCheckClusterDestroy(ctx),
601+
Steps: []resource.TestStep{
602+
{
603+
Config: testAccClusterConfig_auroraStorageType(rName, storageType),
604+
Check: resource.ComposeTestCheckFunc(
605+
testAccCheckClusterExists(ctx, resourceName, &dbCluster),
606+
resource.TestCheckResourceAttr(resourceName, "storage_type", storageType),
607+
),
608+
},
609+
},
610+
})
611+
}
612+
613+
func TestAccRDSCluster_storageTypeAuroraUpdateAuroraIopt1(t *testing.T) {
614+
if testing.Short() {
615+
t.Skip("skipping long-running test in short mode")
616+
}
617+
618+
ctx := acctest.Context(t)
619+
var dbCluster1, dbCluster2 rds.DBCluster
620+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
621+
storageTypeEmpty := ""
622+
storageTypeAuroraIOPT1 := "aurora-iopt1"
623+
resourceName := "aws_rds_cluster.test"
624+
625+
resource.ParallelTest(t, resource.TestCase{
626+
PreCheck: func() { acctest.PreCheck(ctx, t) },
627+
ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID),
628+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
629+
CheckDestroy: testAccCheckClusterDestroy(ctx),
630+
Steps: []resource.TestStep{
631+
{
632+
Config: testAccClusterConfig_auroraStorageTypeNotDefined(rName),
633+
Check: resource.ComposeTestCheckFunc(
634+
testAccCheckClusterExists(ctx, resourceName, &dbCluster1),
635+
resource.TestCheckResourceAttr(resourceName, "storage_type", storageTypeEmpty),
636+
),
637+
},
638+
{
639+
Config: testAccClusterConfig_auroraStorageType(rName, storageTypeAuroraIOPT1),
640+
Check: resource.ComposeTestCheckFunc(
641+
testAccCheckClusterExists(ctx, resourceName, &dbCluster2),
642+
testAccCheckClusterNotRecreated(&dbCluster1, &dbCluster2),
643+
resource.TestCheckResourceAttr(resourceName, "storage_type", storageTypeAuroraIOPT1),
644+
),
645+
},
646+
},
647+
})
648+
}
649+
555650
func TestAccRDSCluster_allocatedStorage(t *testing.T) {
556651
if testing.Short() {
557652
t.Skip("skipping long-running test in short mode")
@@ -579,6 +674,45 @@ func TestAccRDSCluster_allocatedStorage(t *testing.T) {
579674
})
580675
}
581676

677+
// Verify storage_type from aurora-iopt1 to aurora
678+
func TestAccRDSCluster_storageTypeAuroraIopt1UpdateAurora(t *testing.T) {
679+
if testing.Short() {
680+
t.Skip("skipping long-running test in short mode")
681+
}
682+
683+
ctx := acctest.Context(t)
684+
var dbCluster1, dbCluster2 rds.DBCluster
685+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
686+
storageTypeAuroraIOPT1 := "aurora-iopt1"
687+
storageTypeAurora := "aurora"
688+
storageTypeEmpty := ""
689+
resourceName := "aws_rds_cluster.test"
690+
691+
resource.ParallelTest(t, resource.TestCase{
692+
PreCheck: func() { acctest.PreCheck(ctx, t) },
693+
ErrorCheck: acctest.ErrorCheck(t, rds.EndpointsID),
694+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
695+
CheckDestroy: testAccCheckClusterDestroy(ctx),
696+
Steps: []resource.TestStep{
697+
{
698+
Config: testAccClusterConfig_auroraStorageType(rName, storageTypeAuroraIOPT1),
699+
Check: resource.ComposeTestCheckFunc(
700+
testAccCheckClusterExists(ctx, resourceName, &dbCluster1),
701+
resource.TestCheckResourceAttr(resourceName, "storage_type", storageTypeAuroraIOPT1),
702+
),
703+
},
704+
{
705+
Config: testAccClusterConfig_auroraStorageType(rName, storageTypeAurora),
706+
Check: resource.ComposeTestCheckFunc(
707+
testAccCheckClusterExists(ctx, resourceName, &dbCluster2),
708+
testAccCheckClusterNotRecreated(&dbCluster1, &dbCluster2),
709+
resource.TestCheckResourceAttr(resourceName, "storage_type", storageTypeEmpty),
710+
),
711+
},
712+
},
713+
})
714+
}
715+
582716
func TestAccRDSCluster_iops(t *testing.T) {
583717
if testing.Short() {
584718
t.Skip("skipping long-running test in short mode")
@@ -2498,6 +2632,16 @@ func testAccCheckClusterRecreated(i, j *rds.DBCluster) resource.TestCheckFunc {
24982632
}
24992633
}
25002634

2635+
func testAccCheckClusterNotRecreated(i, j *rds.DBCluster) resource.TestCheckFunc {
2636+
return func(s *terraform.State) error {
2637+
if !aws.TimeValue(i.ClusterCreateTime).Equal(aws.TimeValue(j.ClusterCreateTime)) {
2638+
return errors.New("RDS Cluster was recreated")
2639+
}
2640+
2641+
return nil
2642+
}
2643+
}
2644+
25012645
func testAccClusterConfig_basic(rName string) string {
25022646
return fmt.Sprintf(`
25032647
resource "aws_rds_cluster" "test" {
@@ -2801,7 +2945,7 @@ resource "aws_rds_cluster" "test" {
28012945
`, rName))
28022946
}
28032947

2804-
func testAccClusterConfig_storageType(rName string) string {
2948+
func testAccClusterConfig_storageTypeIo1(rName string) string {
28052949
return fmt.Sprintf(`
28062950
resource "aws_rds_cluster" "test" {
28072951
apply_immediately = true
@@ -4493,6 +4637,59 @@ resource "aws_rds_cluster" "test" {
44934637
`, n, f)
44944638
}
44954639

4640+
func testAccClusterConfig_auroraStorageType(rName, storageType string) string {
4641+
return fmt.Sprintf(`
4642+
data "aws_rds_engine_version" "default" {
4643+
engine = "aurora-postgresql"
4644+
preferred_versions = ["14.7", "15.2"]
4645+
}
4646+
4647+
data "aws_rds_orderable_db_instance" "default" {
4648+
engine = data.aws_rds_engine_version.default.engine
4649+
engine_version = data.aws_rds_engine_version.default.version
4650+
preferred_instance_classes = ["db.m6g.large", "db.m5.large", "db.r5.large", "db.c5.large"]
4651+
}
4652+
4653+
resource "aws_rds_cluster" "test" {
4654+
apply_immediately = true
4655+
cluster_identifier = %[1]q
4656+
engine = data.aws_rds_engine_version.default.engine
4657+
engine_version = data.aws_rds_engine_version.default.version
4658+
master_password = "avoid-plaintext-passwords"
4659+
master_username = "tfacctest"
4660+
skip_final_snapshot = true
4661+
storage_type = %[2]q
4662+
}
4663+
4664+
`, rName, storageType)
4665+
}
4666+
4667+
func testAccClusterConfig_auroraStorageTypeNotDefined(rName string) string {
4668+
return fmt.Sprintf(`
4669+
data "aws_rds_engine_version" "default" {
4670+
engine = "aurora-postgresql"
4671+
preferred_versions = ["14.7", "15.2"]
4672+
}
4673+
4674+
data "aws_rds_orderable_db_instance" "default" {
4675+
engine = data.aws_rds_engine_version.default.engine
4676+
engine_version = data.aws_rds_engine_version.default.version
4677+
preferred_instance_classes = ["db.m6g.large", "db.m5.large", "db.r5.large", "db.c5.large"]
4678+
}
4679+
4680+
resource "aws_rds_cluster" "test" {
4681+
apply_immediately = true
4682+
cluster_identifier = %[1]q
4683+
engine = data.aws_rds_engine_version.default.engine
4684+
engine_version = data.aws_rds_engine_version.default.version
4685+
master_password = "avoid-plaintext-passwords"
4686+
master_username = "tfacctest"
4687+
skip_final_snapshot = true
4688+
}
4689+
4690+
`, rName)
4691+
}
4692+
44964693
func testAccClusterConfig_enableHTTPEndpoint(rName string, enableHttpEndpoint bool) string {
44974694
return fmt.Sprintf(`
44984695
resource "aws_rds_cluster" "test" {

internal/service/rds/consts.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ const (
3131
)
3232

3333
const (
34-
storageTypeStandard = "standard"
35-
storageTypeGP2 = "gp2"
36-
storageTypeGP3 = "gp3"
37-
storageTypeIO1 = "io1"
34+
storageTypeStandard = "standard"
35+
storageTypeGP2 = "gp2"
36+
storageTypeGP3 = "gp3"
37+
storageTypeIO1 = "io1"
38+
storageTypeAuroraIOPT1 = "aurora-iopt1"
3839
)
3940

4041
func StorageType_Values() []string {
@@ -43,6 +44,7 @@ func StorageType_Values() []string {
4344
storageTypeGP2,
4445
storageTypeGP3,
4546
storageTypeIO1,
47+
storageTypeAuroraIOPT1,
4648
}
4749
}
4850

internal/service/rds/instance.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,9 @@ func ResourceInstance() *schema.Resource {
576576
Computed: true,
577577
},
578578
"storage_type": {
579-
Type: schema.TypeString,
580-
Optional: true,
581-
Computed: true,
582-
ValidateFunc: validation.StringInSlice(StorageType_Values(), false),
579+
Type: schema.TypeString,
580+
Optional: true,
581+
Computed: true,
583582
},
584583
names.AttrTags: tftags.TagsSchema(),
585584
names.AttrTagsAll: tftags.TagsSchemaComputed(),

0 commit comments

Comments
 (0)