Skip to content

Commit

Permalink
Merge pull request #38437 from hashicorp/b-aws_rds_cluster-wait-for-m…
Browse files Browse the repository at this point in the history
…odification

r/aws_rds_cluster: Wait for no pending modified values on Update if `apply_immediately` is `true`
  • Loading branch information
ewbankkit authored Jul 22, 2024
2 parents a506c01 + 5810bc4 commit abf1e95
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 62 deletions.
7 changes: 7 additions & 0 deletions .changelog/38437.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_rds_cluster: Mark `ca_certificate_identifier` as Computed
```

```release-note:bug
resource/aws_rds_cluster: Wait for no pending modified values on Update if `apply_immediately` is `true`. This fixes `InvalidParameterCombination` errors when updating `engine_version`
```
84 changes: 49 additions & 35 deletions internal/service/rds/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
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"
itypes "github.com/hashicorp/terraform-provider-aws/internal/types"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
"github.com/hashicorp/terraform-provider-aws/names"
)
Expand All @@ -40,7 +41,7 @@ const (
// @SDKResource("aws_rds_cluster", name="Cluster")
// @Tags(identifierAttribute="arn")
// @Testing(tagsTest=false)
func ResourceCluster() *schema.Resource {
func resourceCluster() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceClusterCreate,
ReadWithoutTimeout: resourceClusterRead,
Expand Down Expand Up @@ -116,6 +117,7 @@ func ResourceCluster() *schema.Resource {
"ca_certificate_identifier": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"ca_certificate_valid_till": {
Type: schema.TypeString,
Expand Down Expand Up @@ -1174,7 +1176,7 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
return sdkdiag.AppendErrorf(diags, "updating RDS Cluster (%s): %s", d.Id(), err)
}

if _, err := waitDBClusterUpdated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
if _, err := waitDBClusterUpdated(ctx, conn, d.Id(), true, d.Timeout(schema.TimeoutCreate)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for RDS Cluster (%s) update: %s", d.Id(), err)
}
}
Expand Down Expand Up @@ -1333,8 +1335,9 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta int
"replication_source_identifier",
"skip_final_snapshot",
names.AttrTags, names.AttrTagsAll) {
applyImmediately := d.Get(names.AttrApplyImmediately).(bool)
input := &rds.ModifyDBClusterInput{
ApplyImmediately: aws.Bool(d.Get(names.AttrApplyImmediately).(bool)),
ApplyImmediately: aws.Bool(applyImmediately),
DBClusterIdentifier: aws.String(d.Id()),
}

Expand Down Expand Up @@ -1509,7 +1512,7 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta int
return sdkdiag.AppendErrorf(diags, "updating RDS Cluster (%s): %s", d.Id(), err)
}

if _, err := waitDBClusterUpdated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
if _, err := waitDBClusterUpdated(ctx, conn, d.Id(), applyImmediately, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for RDS Cluster (%s) update: %s", d.Id(), err)
}
}
Expand Down Expand Up @@ -1636,7 +1639,7 @@ func resourceClusterDelete(ctx context.Context, d *schema.ResourceData, meta int
return false, fmt.Errorf("modifying RDS Cluster (%s) DeletionProtection=false: %s", d.Id(), err)
}

if _, err := waitDBClusterUpdated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
if _, err := waitDBClusterUpdated(ctx, conn, d.Id(), false, d.Timeout(schema.TimeoutDelete)); err != nil {
return false, fmt.Errorf("waiting for RDS Cluster (%s) update: %s", d.Id(), err)
}
}
Expand Down Expand Up @@ -1785,7 +1788,7 @@ func findDBClusters(ctx context.Context, conn *rds.RDS, input *rds.DescribeDBClu
return output, nil
}

func statusDBCluster(ctx context.Context, conn *rds.RDS, id string) retry.StateRefreshFunc {
func statusDBCluster(ctx context.Context, conn *rds.RDS, id string, waitNoPendingModifiedValues bool) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := FindDBClusterByID(ctx, conn, id)

Expand All @@ -1797,23 +1800,29 @@ func statusDBCluster(ctx context.Context, conn *rds.RDS, id string) retry.StateR
return nil, "", err
}

return output, aws.StringValue(output.Status), nil
status := aws.StringValue(output.Status)

if status == clusterStatusAvailable && waitNoPendingModifiedValues && !itypes.IsZero(output.PendingModifiedValues) {
status = clusterStatusAvailableWithPendingModifiedValues
}

return output, status, nil
}
}

func waitDBClusterCreated(ctx context.Context, conn *rds.RDS, id string, timeout time.Duration) (*rds.DBCluster, error) {
stateConf := &retry.StateChangeConf{
Pending: []string{
ClusterStatusBackingUp,
ClusterStatusCreating,
ClusterStatusMigrating,
ClusterStatusModifying,
ClusterStatusPreparingDataMigration,
ClusterStatusRebooting,
ClusterStatusResettingMasterCredentials,
clusterStatusBackingUp,
clusterStatusCreating,
clusterStatusMigrating,
clusterStatusModifying,
clusterStatusPreparingDataMigration,
clusterStatusRebooting,
clusterStatusResettingMasterCredentials,
},
Target: []string{ClusterStatusAvailable},
Refresh: statusDBCluster(ctx, conn, id),
Target: []string{clusterStatusAvailable},
Refresh: statusDBCluster(ctx, conn, id, false),
Timeout: timeout,
MinTimeout: 10 * time.Second,
Delay: 30 * time.Second,
Expand All @@ -1828,19 +1837,24 @@ func waitDBClusterCreated(ctx context.Context, conn *rds.RDS, id string, timeout
return nil, err
}

func waitDBClusterUpdated(ctx context.Context, conn *rds.RDS, id string, timeout time.Duration) (*rds.DBCluster, error) { //nolint:unparam
func waitDBClusterUpdated(ctx context.Context, conn *rds.RDS, id string, waitNoPendingModifiedValues bool, timeout time.Duration) (*rds.DBCluster, error) { //nolint:unparam
pendingStatuses := []string{
clusterStatusBackingUp,
clusterStatusConfiguringIAMDatabaseAuth,
clusterStatusModifying,
clusterStatusRenaming,
clusterStatusResettingMasterCredentials,
clusterStatusScalingCompute,
clusterStatusUpgrading,
}
if waitNoPendingModifiedValues {
pendingStatuses = append(pendingStatuses, clusterStatusAvailableWithPendingModifiedValues)
}

stateConf := &retry.StateChangeConf{
Pending: []string{
ClusterStatusBackingUp,
ClusterStatusConfiguringIAMDatabaseAuth,
ClusterStatusModifying,
ClusterStatusRenaming,
ClusterStatusResettingMasterCredentials,
ClusterStatusScalingCompute,
ClusterStatusUpgrading,
},
Target: []string{ClusterStatusAvailable},
Refresh: statusDBCluster(ctx, conn, id),
Pending: pendingStatuses,
Target: []string{clusterStatusAvailable},
Refresh: statusDBCluster(ctx, conn, id, waitNoPendingModifiedValues),
Timeout: timeout,
MinTimeout: 10 * time.Second,
Delay: 30 * time.Second,
Expand All @@ -1858,15 +1872,15 @@ func waitDBClusterUpdated(ctx context.Context, conn *rds.RDS, id string, timeout
func waitDBClusterDeleted(ctx context.Context, conn *rds.RDS, id string, timeout time.Duration) (*rds.DBCluster, error) {
stateConf := &retry.StateChangeConf{
Pending: []string{
ClusterStatusAvailable,
ClusterStatusBackingUp,
ClusterStatusDeleting,
ClusterStatusModifying,
ClusterStatusPromoting,
ClusterStatusScalingCompute,
clusterStatusAvailable,
clusterStatusBackingUp,
clusterStatusDeleting,
clusterStatusModifying,
clusterStatusPromoting,
clusterStatusScalingCompute,
},
Target: []string{},
Refresh: statusDBCluster(ctx, conn, id),
Refresh: statusDBCluster(ctx, conn, id, false),
Timeout: timeout,
MinTimeout: 10 * time.Second,
Delay: 30 * time.Second,
Expand Down
4 changes: 2 additions & 2 deletions internal/service/rds/cluster_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ func statusDBClusterSnapshot(ctx context.Context, conn *rds.RDS, id string) retr

func waitDBClusterSnapshotCreated(ctx context.Context, conn *rds.RDS, id string, timeout time.Duration) (*rds.DBClusterSnapshot, error) {
stateConf := &retry.StateChangeConf{
Pending: []string{ClusterSnapshotStatusCreating},
Target: []string{ClusterSnapshotStatusAvailable},
Pending: []string{clusterSnapshotStatusCreating},
Target: []string{clusterSnapshotStatusAvailable},
Refresh: statusDBClusterSnapshot(ctx, conn, id),
Timeout: timeout,
MinTimeout: 10 * time.Second,
Expand Down
41 changes: 22 additions & 19 deletions internal/service/rds/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,34 @@ import (
)

const (
ClusterRoleStatusActive = "ACTIVE"
ClusterRoleStatusDeleted = "DELETED"
ClusterRoleStatusPending = "PENDING"
clusterRoleStatusActive = "ACTIVE"
clusterRoleStatusDeleted = "DELETED"
clusterRoleStatusPending = "PENDING"
)

const (
ClusterStatusAvailable = "available"
ClusterStatusBackingUp = "backing-up"
ClusterStatusConfiguringIAMDatabaseAuth = "configuring-iam-database-auth"
ClusterStatusCreating = "creating"
ClusterStatusDeleting = "deleting"
ClusterStatusMigrating = "migrating"
ClusterStatusModifying = "modifying"
ClusterStatusPreparingDataMigration = "preparing-data-migration"
ClusterStatusPromoting = "promoting"
ClusterStatusRebooting = "rebooting"
ClusterStatusRenaming = "renaming"
ClusterStatusResettingMasterCredentials = "resetting-master-credentials"
ClusterStatusScalingCompute = "scaling-compute"
ClusterStatusUpgrading = "upgrading"
clusterStatusAvailable = "available"
clusterStatusBackingUp = "backing-up"
clusterStatusConfiguringIAMDatabaseAuth = "configuring-iam-database-auth"
clusterStatusCreating = "creating"
clusterStatusDeleting = "deleting"
clusterStatusMigrating = "migrating"
clusterStatusModifying = "modifying"
clusterStatusPreparingDataMigration = "preparing-data-migration"
clusterStatusPromoting = "promoting"
clusterStatusRebooting = "rebooting"
clusterStatusRenaming = "renaming"
clusterStatusResettingMasterCredentials = "resetting-master-credentials"
clusterStatusScalingCompute = "scaling-compute"
clusterStatusUpgrading = "upgrading"

// Non-standard status values.
clusterStatusAvailableWithPendingModifiedValues = "tf-available-with-pending-modified-values"
)

const (
ClusterSnapshotStatusAvailable = "available"
ClusterSnapshotStatusCreating = "creating"
clusterSnapshotStatusAvailable = "available"
clusterSnapshotStatusCreating = "creating"
)

const (
Expand Down
1 change: 1 addition & 0 deletions internal/service/rds/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package rds
// Exports for use in tests only.
var (
ResourceCertificate = resourceCertificate
ResourceCluster = resourceCluster
ResourceEventSubscription = resourceEventSubscription
ResourceProxy = resourceProxy
ResourceProxyDefaultTargetGroup = resourceProxyDefaultTargetGroup
Expand Down
2 changes: 1 addition & 1 deletion internal/service/rds/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func FindDBClusterRoleByDBClusterIDAndRoleARN(ctx context.Context, conn *rds.RDS

for _, associatedRole := range dbCluster.AssociatedRoles {
if aws.StringValue(associatedRole.RoleArn) == roleARN {
if status := aws.StringValue(associatedRole.Status); status == ClusterRoleStatusDeleted {
if status := aws.StringValue(associatedRole.Status); status == clusterRoleStatusDeleted {
return nil, &retry.NotFoundError{
Message: status,
}
Expand Down
2 changes: 1 addition & 1 deletion internal/service/rds/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/service/rds/sweep.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func sweepClusters(region string) error {
for _, v := range page.DBClusters {
arn := aws.StringValue(v.DBClusterArn)
id := aws.StringValue(v.DBClusterIdentifier)
r := ResourceCluster()
r := resourceCluster()
d := r.Data(nil)
d.SetId(id)
d.Set(names.AttrApplyImmediately, true)
Expand Down
6 changes: 3 additions & 3 deletions internal/service/rds/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (

func waitDBClusterRoleAssociationCreated(ctx context.Context, conn *rds.RDS, dbClusterID, roleARN string, timeout time.Duration) (*rds.DBClusterRole, error) {
stateConf := &retry.StateChangeConf{
Pending: []string{ClusterRoleStatusPending},
Target: []string{ClusterRoleStatusActive},
Pending: []string{clusterRoleStatusPending},
Target: []string{clusterRoleStatusActive},
Refresh: statusDBClusterRole(ctx, conn, dbClusterID, roleARN),
Timeout: timeout,
MinTimeout: 10 * time.Second,
Expand All @@ -32,7 +32,7 @@ func waitDBClusterRoleAssociationCreated(ctx context.Context, conn *rds.RDS, dbC

func waitDBClusterRoleAssociationDeleted(ctx context.Context, conn *rds.RDS, dbClusterID, roleARN string, timeout time.Duration) (*rds.DBClusterRole, error) {
stateConf := &retry.StateChangeConf{
Pending: []string{ClusterRoleStatusActive, ClusterRoleStatusPending},
Pending: []string{clusterRoleStatusActive, clusterRoleStatusPending},
Target: []string{},
Refresh: statusDBClusterRole(ctx, conn, dbClusterID, roleARN),
Timeout: timeout,
Expand Down

0 comments on commit abf1e95

Please sign in to comment.