Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RDS Custom enhancements #32846

Merged
merged 27 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8989dda
removed clientside cluster engine validation
AdamTylerLynch Jun 30, 2023
131cb60
added custom_iam_instance_profile
AdamTylerLynch Jun 30, 2023
f66fa22
added db_system_id
AdamTylerLynch Jun 30, 2023
ca5bb83
added support for RDS Custom
AdamTylerLynch Jun 30, 2023
317f7b0
addeed skip_final_snapshot to schema
AdamTylerLynch Aug 2, 2023
a2009fd
addedc RDS custom enum
AdamTylerLynch Aug 2, 2023
38a59d7
added instance status incompatible create
AdamTylerLynch Aug 2, 2023
c282162
added skipfinalsnapshot logic to delete
AdamTylerLynch Aug 2, 2023
f636b1f
removed skipfinalsnapshot shema changes
AdamTylerLynch Aug 2, 2023
24292ba
updated const value for engines
AdamTylerLynch Aug 3, 2023
1472c30
updated engine const
AdamTylerLynch Aug 3, 2023
4aed9ed
updated engine check for custom instances
AdamTylerLynch Aug 3, 2023
f5fbfec
updated cluster engine check for custom
AdamTylerLynch Aug 3, 2023
3d36985
Merge branch 'main' into e-rds_custom_for_oracle
AdamTylerLynch Aug 3, 2023
8fc6e4c
leverage validat cluster engines func
AdamTylerLynch Aug 3, 2023
f8ffab4
moved clusterengine vaidation inline
AdamTylerLynch Aug 4, 2023
65c26bd
updated changelog
AdamTylerLynch Aug 4, 2023
d58ca6d
Update 32846.txt
ewbankkit Aug 4, 2023
b180d2d
TestAccRDSCluster_basic: Check 'db_system_id'.
ewbankkit Aug 6, 2023
22bc727
TestAccRDSClusterInstance_basic: Check 'custom_iam_instance_profile'.
ewbankkit Aug 6, 2023
f3cf5e0
Merge branch 'main' into HEAD
ewbankkit Aug 6, 2023
d793cf1
rds: Add 'findDBCluster(s)'.
ewbankkit Aug 6, 2023
d92d92d
r/aws_rds_cluster: Document 'db_system_id'.
ewbankkit Aug 6, 2023
dc30e93
r/aws_rds_cluster_instance: Document 'custom_iam_instance_profile'.
ewbankkit Aug 6, 2023
214cab9
d/aws_rds_cluster: Add 'db_system_id' attribute.
ewbankkit Aug 6, 2023
92810db
Fix markdown-lint 'website/docs/r/rds_cluster.html.markdown:236:54 MD…
ewbankkit Aug 6, 2023
9f5e1de
d/aws_rds_cluster: Set 'db_system_id'.
ewbankkit Aug 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changelog/32846.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```release-note:enhancement
resource/aws_rds_cluster_instance: Add `custom_iam_instance_profile` argument to allow RDS Custom users to specify an IAM Instance Profile for the RDS Cluster Instance
```

```release-note:enhancement
resource/aws_rds_cluster_instance: Update `engine` plan-time validation to allow for RDS Custom engine types
```

```release-note:enhancement
resource/aws_rds_cluster: Add `db_system_id` argument to support RDS Custom engine types
```

```release-note:enhancement
data-source/aws_rds_cluster: Add `db_system_id` attribute
```
80 changes: 59 additions & 21 deletions internal/service/rds/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"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"
Expand Down Expand Up @@ -150,6 +151,12 @@ func ResourceCluster() *schema.Resource {
ForceNew: true,
Computed: true,
},
"db_system_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
"deletion_protection": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -177,10 +184,13 @@ func ResourceCluster() *schema.Resource {
Computed: true,
},
"engine": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validClusterEngine(),
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.Any(
validation.StringMatch(regexp.MustCompile(fmt.Sprintf(`^%s.*$`, InstanceEngineCustomPrefix)), fmt.Sprintf("must begin with %s", InstanceEngineCustomPrefix)),
validation.StringInSlice(ClusterEngine_Values(), false),
),
},
"engine_mode": {
Type: schema.TypeString,
Expand Down Expand Up @@ -941,6 +951,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
input.DBSubnetGroupName = aws.String(v.(string))
}

if v, ok := d.GetOk("db_system_id"); ok {
input.DBSystemId = aws.String(v.(string))
}

if v, ok := d.GetOk("enable_global_write_forwarding"); ok {
input.EnableGlobalWriteForwarding = aws.Bool(v.(bool))
}
Expand Down Expand Up @@ -1116,6 +1130,7 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter
d.Set("db_cluster_instance_class", dbc.DBClusterInstanceClass)
d.Set("db_cluster_parameter_group_name", dbc.DBClusterParameterGroup)
d.Set("db_subnet_group_name", dbc.DBSubnetGroup)
d.Set("db_system_id", dbc.DBSystemId)
d.Set("deletion_protection", dbc.DeletionProtection)
d.Set("enabled_cloudwatch_logs_exports", aws.StringValueSlice(dbc.EnabledCloudwatchLogsExports))
d.Set("enable_http_endpoint", dbc.HttpEndpointEnabled)
Expand Down Expand Up @@ -1586,44 +1601,67 @@ func FindDBClusterByID(ctx context.Context, conn *rds.RDS, id string) (*rds.DBCl
input := &rds.DescribeDBClustersInput{
DBClusterIdentifier: aws.String(id),
}
output, err := findDBCluster(ctx, conn, input)

output, err := conn.DescribeDBClustersWithContext(ctx, input)
if err != nil {
return nil, err
}

if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBClusterNotFoundFault) {
// Eventual consistency check.
if arn.IsARN(id) {
if aws.StringValue(output.DBClusterArn) != id {
return nil, &retry.NotFoundError{
LastRequest: input,
}
}
} else if aws.StringValue(output.DBClusterIdentifier) != id {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

return output, nil
}

func findDBCluster(ctx context.Context, conn *rds.RDS, input *rds.DescribeDBClustersInput) (*rds.DBCluster, error) {
output, err := findDBClusters(ctx, conn, input, tfslices.PredicateTrue[*rds.DBCluster]())

if err != nil {
return nil, err
}

if output == nil || len(output.DBClusters) == 0 || output.DBClusters[0] == nil {
return nil, tfresource.NewEmptyResultError(input)
}
return tfresource.AssertSinglePtrResult(output)
}

if count := len(output.DBClusters); count > 1 {
return nil, tfresource.NewTooManyResultsError(count, input)
}
func findDBClusters(ctx context.Context, conn *rds.RDS, input *rds.DescribeDBClustersInput, filter tfslices.Predicate[*rds.DBCluster]) ([]*rds.DBCluster, error) {
var output []*rds.DBCluster

dbCluster := output.DBClusters[0]
err := conn.DescribeDBClustersPagesWithContext(ctx, input, func(page *rds.DescribeDBClustersOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

// Eventual consistency check.
if arn.IsARN(id) {
if aws.StringValue(dbCluster.DBClusterArn) != id {
return nil, &retry.NotFoundError{
LastRequest: input,
for _, v := range page.DBClusters {
if v != nil && filter(v) {
output = append(output, v)
}
}
} else if aws.StringValue(dbCluster.DBClusterIdentifier) != id {

return !lastPage
})

if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBClusterNotFoundFault) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

return dbCluster, nil
if err != nil {
return nil, err
}

return output, nil
}

func statusDBCluster(ctx context.Context, conn *rds.RDS, id string) retry.StateRefreshFunc {
Expand Down
5 changes: 5 additions & 0 deletions internal/service/rds/cluster_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ func DataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"db_system_id": {
Type: schema.TypeString,
Computed: true,
},
"enabled_cloudwatch_logs_exports": {
Type: schema.TypeList,
Computed: true,
Expand Down Expand Up @@ -201,6 +205,7 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta int
}
d.Set("db_cluster_parameter_group_name", dbc.DBClusterParameterGroup)
d.Set("db_subnet_group_name", dbc.DBSubnetGroup)
d.Set("db_system_id", dbc.DBSystemId)
d.Set("enabled_cloudwatch_logs_exports", aws.StringValueSlice(dbc.EnabledCloudwatchLogsExports))
d.Set("endpoint", dbc.Endpoint)
d.Set("engine", dbc.Engine)
Expand Down
1 change: 1 addition & 0 deletions internal/service/rds/cluster_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestAccRDSClusterDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName, "database_name", resourceName, "database_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "db_cluster_parameter_group_name", resourceName, "db_cluster_parameter_group_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "db_subnet_group_name", resourceName, "db_subnet_group_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "db_system_id", resourceName, "db_system_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "engine", resourceName, "engine"),
resource.TestCheckResourceAttrPair(dataSourceName, "engine_mode", resourceName, "engine_mode"),
resource.TestCheckResourceAttrPair(dataSourceName, "engine_version", resourceName, "engine_version"),
Expand Down
30 changes: 26 additions & 4 deletions internal/service/rds/cluster_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package rds

import (
"context"
"fmt"
"log"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -81,6 +83,12 @@ func ResourceClusterInstance() *schema.Resource {
Optional: true,
Default: false,
},
"custom_iam_instance_profile": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^AWSRDSCustom.*$`), "must begin with AWSRDSCustom"),
},
"db_parameter_group_name": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -101,10 +109,13 @@ func ResourceClusterInstance() *schema.Resource {
Computed: true,
},
"engine": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validClusterEngine(),
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.Any(
validation.StringMatch(regexp.MustCompile(fmt.Sprintf(`^%s.*$`, InstanceEngineCustomPrefix)), fmt.Sprintf("must begin with %s", InstanceEngineCustomPrefix)),
validation.StringInSlice(ClusterEngine_Values(), false),
),
},
"engine_version": {
Type: schema.TypeString,
Expand Down Expand Up @@ -265,6 +276,10 @@ func resourceClusterInstanceCreate(ctx context.Context, d *schema.ResourceData,
input.DBSubnetGroupName = aws.String(v.(string))
}

if v, ok := d.GetOk("custom_iam_instance_profile"); ok {
input.CustomIamInstanceProfile = aws.String(v.(string))
}

if v, ok := d.GetOk("engine_version"); ok {
input.EngineVersion = aws.String(v.(string))
}
Expand Down Expand Up @@ -391,6 +406,7 @@ func resourceClusterInstanceRead(ctx context.Context, d *schema.ResourceData, me
d.Set("ca_cert_identifier", db.CACertificateIdentifier)
d.Set("cluster_identifier", db.DBClusterIdentifier)
d.Set("copy_tags_to_snapshot", db.CopyTagsToSnapshot)
d.Set("custom_iam_instance_profile", db.CustomIamInstanceProfile)
if len(db.DBParameterGroups) > 0 && db.DBParameterGroups[0] != nil {
d.Set("db_parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName)
}
Expand Down Expand Up @@ -512,6 +528,12 @@ func resourceClusterInstanceDelete(ctx context.Context, d *schema.ResourceData,
DBInstanceIdentifier: aws.String(d.Id()),
}

// Automatically set skip_final_snapshot = true for RDS Custom instances
if strings.HasPrefix(d.Get("engine").(string), InstanceEngineCustomPrefix) {
log.Printf("[DEBUG] RDS Custom engine detected (%s) applying SkipFinalSnapshot: %s", d.Get("engine").(string), "true")
input.SkipFinalSnapshot = aws.Bool(true)
}

log.Printf("[DEBUG] Deleting RDS Cluster Instance: %s", d.Id())
_, err := tfresource.RetryWhenAWSErrMessageContains(ctx, d.Timeout(schema.TimeoutDelete),
func() (interface{}, error) {
Expand Down
1 change: 1 addition & 0 deletions internal/service/rds/cluster_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func TestAccRDSClusterInstance_basic(t *testing.T) {
resource.TestCheckResourceAttrSet(resourceName, "availability_zone"),
resource.TestCheckResourceAttr(resourceName, "cluster_identifier", rName),
resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "false"),
resource.TestCheckResourceAttr(resourceName, "custom_iam_instance_profile", ""),
resource.TestCheckResourceAttrSet(resourceName, "dbi_resource_id"),
resource.TestCheckResourceAttr(resourceName, "engine", "aurora-mysql"),
resource.TestCheckResourceAttrSet(resourceName, "engine_version"),
Expand Down
1 change: 1 addition & 0 deletions internal/service/rds/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func TestAccRDSCluster_basic(t *testing.T) {
resource.TestCheckResourceAttrSet(resourceName, "cluster_resource_id"),
resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "false"),
resource.TestCheckResourceAttr(resourceName, "db_cluster_parameter_group_name", "default.aurora-mysql5.7"),
resource.TestCheckResourceAttr(resourceName, "db_system_id", ""),
resource.TestCheckResourceAttr(resourceName, "enabled_cloudwatch_logs_exports.#", "0"),
resource.TestCheckResourceAttr(resourceName, "engine", "aurora-mysql"),
resource.TestCheckResourceAttrSet(resourceName, "engine_version"),
Expand Down
3 changes: 3 additions & 0 deletions internal/service/rds/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const (
InstanceEngineSQLServerExpress = "sqlserver-ex"
InstanceEngineSQLServerStandard = "sqlserver-se"
InstanceEngineSQLServerWeb = "sqlserver-ewb"
InstanceEngineCustomPrefix = "custom-"
)

// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/accessing-monitoring.html#Overview.DBInstance.Status.
Expand All @@ -80,6 +81,7 @@ const (
InstanceStatusFailed = "failed"
InstanceStatusInaccessibleEncryptionCredentials = "inaccessible-encryption-credentials"
InstanceStatusInaccessibleEncryptionCredentialsRecoverable = "inaccessible-encryption-credentials-recoverable"
InstanceStatusIncompatiblCreate = "incompatible-create"
InstanceStatusIncompatibleNetwork = "incompatible-network"
InstanceStatusIncompatibleOptionGroup = "incompatible-option-group"
InstanceStatusIncompatibleParameters = "incompatible-parameters"
Expand Down Expand Up @@ -117,6 +119,7 @@ const (
ClusterEngineAuroraPostgreSQL = "aurora-postgresql"
ClusterEngineMySQL = "mysql"
ClusterEnginePostgres = "postgres"
ClusterEngineCustomPrefix = "custom-"
)

func ClusterEngine_Values() []string {
Expand Down
7 changes: 0 additions & 7 deletions internal/service/rds/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ package rds
import (
"fmt"
"regexp"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func validEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) {
Expand Down Expand Up @@ -146,10 +143,6 @@ func validSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []
return
}

func validClusterEngine() schema.SchemaValidateFunc {
return validation.StringInSlice(ClusterEngine_Values(), false)
}

func validIdentifier(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/rds_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ This argument supports the following arguments:
* `db_cluster_instance_class` - (Optional) (Required for Multi-AZ DB cluster) The compute and memory capacity of each DB instance in the Multi-AZ DB cluster, for example db.m6g.xlarge. Not all DB instance classes are available in all AWS Regions, or for all database engines. For the full list of DB instance classes and availability for your engine, see [DB instance class](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html) in the Amazon RDS User Guide.
* `db_instance_parameter_group_name` - (Optional) Instance parameter group to associate with all instances of the DB cluster. The `db_instance_parameter_group_name` parameter is only valid in combination with the `allow_major_version_upgrade` parameter.
* `db_subnet_group_name` - (Optional) DB subnet group to associate with this DB instance. **NOTE:** This must match the `db_subnet_group_name` specified on every [`aws_rds_cluster_instance`](/docs/providers/aws/r/rds_cluster_instance.html) in the cluster.
* `db_system_id` - (Optional) For use with RDS Custom.
* `deletion_protection` - (Optional) If the DB instance should have deletion protection enabled. The database can't be deleted when this value is set to `true`. The default is `false`.
* `enable_global_write_forwarding` - (Optional) Whether cluster should forward writes to an associated global cluster. Applied to secondary clusters to enable them to forward writes to an [`aws_rds_global_cluster`](/docs/providers/aws/r/rds_global_cluster.html)'s primary cluster. See the [Aurora Userguide documentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-write-forwarding.html) for more information.
* `enable_http_endpoint` - (Optional) Enable HTTP endpoint (data API). Only valid when `engine_mode` is set to `serverless`.
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/rds_cluster_instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ This argument supports the following arguments:
* `ca_cert_identifier` - (Optional) Identifier of the CA certificate for the DB instance.
* `cluster_identifier` - (Required, Forces new resource) Identifier of the [`aws_rds_cluster`](/docs/providers/aws/r/rds_cluster.html) in which to launch this instance.
* `copy_tags_to_snapshot` – (Optional, boolean) Indicates whether to copy all of the user-defined tags from the DB instance to snapshots of the DB instance. Default `false`.
* `custom_iam_instance_profile` - (Optional) Instance profile associated with the underlying Amazon EC2 instance of an RDS Custom DB instance.
* `db_parameter_group_name` - (Optional) Name of the DB parameter group to associate with this instance.
* `db_subnet_group_name` - (Required if `publicly_accessible = false`, Optional otherwise, Forces new resource) DB subnet group to associate with this DB instance. **NOTE:** This must match the `db_subnet_group_name` of the attached [`aws_rds_cluster`](/docs/providers/aws/r/rds_cluster.html).
* `engine_version` - (Optional) Database engine version.
Expand Down