diff --git a/aws/resource_aws_rds_cluster_instance.go b/aws/resource_aws_rds_cluster_instance.go index d20facd407fb..d8c48280b388 100644 --- a/aws/resource_aws_rds_cluster_instance.go +++ b/aws/resource_aws_rds_cluster_instance.go @@ -206,6 +206,11 @@ func resourceAwsRDSClusterInstance() *schema.Resource { Optional: true, Default: false, }, + "ca_cert_identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "tags": tagsSchema(), }, @@ -314,6 +319,63 @@ func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{ return err } + // See also: resource_aws_db_instance.go + // Some API calls (e.g. CreateDBInstanceReadReplica and + // RestoreDBInstanceFromDBSnapshot do not support all parameters to + // correctly apply all settings in one pass. For missing parameters or + // unsupported configurations, we may need to call ModifyDBInstance + // afterwards to prevent Terraform operators from API errors or needing + // to double apply. + var requiresModifyDbInstance bool + modifyDbInstanceInput := &rds.ModifyDBInstanceInput{ + ApplyImmediately: aws.Bool(true), + } + + // Some ModifyDBInstance parameters (e.g. DBParameterGroupName) require + // a database instance reboot to take affect. During resource creation, + // we expect everything to be in sync before returning completion. + var requiresRebootDbInstance bool + + if attr, ok := d.GetOk("ca_cert_identifier"); ok && attr.(string) != aws.StringValue(resp.DBInstance.CACertificateIdentifier) { + modifyDbInstanceInput.CACertificateIdentifier = aws.String(attr.(string)) + requiresModifyDbInstance = true + requiresRebootDbInstance = true + } + + if requiresModifyDbInstance { + modifyDbInstanceInput.DBInstanceIdentifier = aws.String(d.Id()) + + log.Printf("[INFO] DB Instance (%s) configuration requires ModifyDBInstance: %s", d.Id(), modifyDbInstanceInput) + _, err := conn.ModifyDBInstance(modifyDbInstanceInput) + if err != nil { + return fmt.Errorf("error modifying DB Instance (%s): %s", d.Id(), err) + } + + log.Printf("[INFO] Waiting for DB Instance (%s) to be available", d.Id()) + err = waitUntilAwsDbInstanceIsAvailableAfterUpdate(d.Id(), conn, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return fmt.Errorf("error waiting for DB Instance (%s) to be available: %s", d.Id(), err) + } + } + + if requiresRebootDbInstance { + rebootDbInstanceInput := &rds.RebootDBInstanceInput{ + DBInstanceIdentifier: aws.String(d.Id()), + } + + log.Printf("[INFO] DB Instance (%s) configuration requires RebootDBInstance: %s", d.Id(), rebootDbInstanceInput) + _, err := conn.RebootDBInstance(rebootDbInstanceInput) + if err != nil { + return fmt.Errorf("error rebooting DB Instance (%s): %s", d.Id(), err) + } + + log.Printf("[INFO] Waiting for DB Instance (%s) to be available", d.Id()) + err = waitUntilAwsDbInstanceIsAvailableAfterUpdate(d.Id(), conn, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return fmt.Errorf("error waiting for DB Instance (%s) to be available: %s", d.Id(), err) + } + } + return resourceAwsRDSClusterInstanceRead(d, meta) } @@ -391,6 +453,7 @@ func resourceAwsRDSClusterInstanceRead(d *schema.ResourceData, meta interface{}) d.Set("promotion_tier", db.PromotionTier) d.Set("publicly_accessible", db.PubliclyAccessible) d.Set("storage_encrypted", db.StorageEncrypted) + d.Set("ca_cert_identifier", db.CACertificateIdentifier) if len(db.DBParameterGroups) > 0 { d.Set("db_parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName) @@ -486,6 +549,12 @@ func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{ requestUpdate = true } + if d.HasChange("ca_cert_identifier") { + d.SetPartial("ca_cert_identifier") + req.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) + requestUpdate = true + } + log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) if requestUpdate { log.Printf("[DEBUG] DB Instance Modification request: %#v", req) diff --git a/aws/resource_aws_rds_cluster_instance_test.go b/aws/resource_aws_rds_cluster_instance_test.go index 24551f7f4aed..07d9954633c6 100644 --- a/aws/resource_aws_rds_cluster_instance_test.go +++ b/aws/resource_aws_rds_cluster_instance_test.go @@ -805,6 +805,43 @@ func TestAccAWSRDSClusterInstance_PerformanceInsightsKmsKeyId_AuroraPostgresql_D }) } +func TestAccAWSRDSClusterInstance_CACertificateIdentifier(t *testing.T) { + var dbInstance rds.DBInstance + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_rds_cluster_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRDSClusterInstanceConfig_CACertificateIdentifier(rName, "rds-ca-2015"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterInstanceExists(resourceName, &dbInstance), + resource.TestCheckResourceAttr(resourceName, "ca_cert_identifier", "rds-ca-2015"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "apply_immediately", + "identifier_prefix", + }, + }, + { + Config: testAccAWSRDSClusterInstanceConfig_CACertificateIdentifier(rName, "rds-ca-2019"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterInstanceExists(resourceName, &dbInstance), + resource.TestCheckResourceAttr(resourceName, "ca_cert_identifier", "rds-ca-2019"), + ), + }, + }, + }) +} + // Add some random to the name, to avoid collision func testAccAWSClusterInstanceConfig(n int) string { return fmt.Sprintf(` @@ -1378,3 +1415,22 @@ resource "aws_rds_cluster_instance" "cluster_instances" { } `, n, n, f) } + +func testAccAWSRDSClusterInstanceConfig_CACertificateIdentifier(rName string, caCertificateIdentifier string) string { + return fmt.Sprintf(` +resource "aws_rds_cluster" "test" { + cluster_identifier = %q + master_username = "foo" + master_password = "mustbeeightcharacters" + skip_final_snapshot = true +} + +resource "aws_rds_cluster_instance" "test" { + apply_immediately = true + cluster_identifier = "${aws_rds_cluster.test.id}" + identifier = %q + instance_class = "db.t2.small" + ca_cert_identifier = %q +} +`, rName, rName, caCertificateIdentifier) +} diff --git a/website/docs/r/rds_cluster_instance.html.markdown b/website/docs/r/rds_cluster_instance.html.markdown index 42bc20c59682..799cd0933e63 100644 --- a/website/docs/r/rds_cluster_instance.html.markdown +++ b/website/docs/r/rds_cluster_instance.html.markdown @@ -80,6 +80,7 @@ what IAM permissions are needed to allow Enhanced Monitoring for RDS Instances. * `performance_insights_enabled` - (Optional) Specifies whether Performance Insights is enabled or not. * `performance_insights_kms_key_id` - (Optional) The ARN for the KMS key to encrypt Performance Insights data. When specifying `performance_insights_kms_key_id`, `performance_insights_enabled` needs to be set to true. * `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`. +* `ca_cert_identifier` - (Optional) The identifier of the CA certificate for the DB instance. * `tags` - (Optional) A mapping of tags to assign to the instance. ## Attributes Reference