From 7eed98333cb3ca9cf45171d822c1a159d1ac7ab1 Mon Sep 17 00:00:00 2001 From: Dmytro Kryvenko Date: Tue, 15 Dec 2020 19:34:59 -0800 Subject: [PATCH 1/5] #507: aws_db_instance: Add support for in-place identifier update --- aws/resource_aws_db_instance.go | 105 +++--- aws/resource_aws_db_instance_migrate.go | 434 ++++++++++++++++++++++++ tools/go.mod | 1 + tools/go.sum | 2 + 4 files changed, 502 insertions(+), 40 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 762066309ec..bd1c38ba250 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -27,13 +27,18 @@ func resourceAwsDbInstance() *schema.Resource { State: resourceAwsDbInstanceImport, }, - SchemaVersion: 1, + SchemaVersion: 2, StateUpgraders: []schema.StateUpgrader{ { Type: resourceAwsDbInstanceResourceV0().CoreConfigSchema().ImpliedType(), Upgrade: resourceAwsDbInstanceStateUpgradeV0, Version: 0, }, + { + Type: resourceAwsDbInstanceResourceV1().CoreConfigSchema().ImpliedType(), + Upgrade: resourceAwsDbInstanceStateUpgradeV1, + Version: 1, + }, }, Timeouts: &schema.ResourceTimeout{ @@ -149,7 +154,6 @@ func resourceAwsDbInstance() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ForceNew: true, ConflictsWith: []string{"identifier_prefix"}, ValidateFunc: validateRdsIdentifier, }, @@ -157,7 +161,6 @@ func resourceAwsDbInstance() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validateRdsIdentifierPrefix, }, @@ -706,10 +709,12 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } log.Printf("[DEBUG] DB Instance Replica create configuration: %#v", opts) - _, err := conn.CreateDBInstanceReadReplica(&opts) + createDBInstanceReadReplicaOutput, err := conn.CreateDBInstanceReadReplica(&opts) if err != nil { return fmt.Errorf("Error creating DB Instance: %s", err) } + + d.Set("resource_id", createDBInstanceReadReplicaOutput.DBInstance.DbiResourceId) } else if v, ok := d.GetOk("s3_import"); ok { if _, ok := d.GetOk("allocated_storage"); !ok { @@ -837,10 +842,11 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } log.Printf("[DEBUG] DB Instance S3 Restore configuration: %#v", opts) + var restoreDBInstanceFromS3Output *rds.RestoreDBInstanceFromS3Output var err error // Retry for IAM eventual consistency err = resource.Retry(2*time.Minute, func() *resource.RetryError { - _, err = conn.RestoreDBInstanceFromS3(&opts) + restoreDBInstanceFromS3Output, err = conn.RestoreDBInstanceFromS3(&opts) if err != nil { if isAWSErr(err, "InvalidParameterValue", "ENHANCED_MONITORING") { return resource.RetryableError(err) @@ -860,15 +866,15 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error return nil }) if isResourceTimeoutError(err) { - _, err = conn.RestoreDBInstanceFromS3(&opts) + restoreDBInstanceFromS3Output, err = conn.RestoreDBInstanceFromS3(&opts) } if err != nil { return fmt.Errorf("Error creating DB Instance: %s", err) } - d.SetId(d.Get("identifier").(string)) + d.Set("resource_id", restoreDBInstanceFromS3Output.DBInstance.DbiResourceId) - log.Printf("[INFO] DB Instance ID: %s", d.Id()) + log.Printf("[INFO] DB Instance ID: %q; DB Resource ID: %q", identifier, d.Get("resource_id").(string)) log.Println( "[INFO] Waiting for DB Instance to be available") @@ -876,7 +882,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error stateConf := &resource.StateChangeConf{ Pending: resourceAwsDbInstanceCreatePendingStates, Target: []string{"available", "storage-optimization"}, - Refresh: resourceAwsDbInstanceStateRefreshFunc(d.Id(), conn), + Refresh: resourceAwsDbInstanceStateRefreshFunc(d.Get("resource_id").(string), conn), Timeout: d.Timeout(schema.TimeoutCreate), MinTimeout: 10 * time.Second, Delay: 30 * time.Second, // Wait 30 secs before starting @@ -1059,7 +1065,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } log.Printf("[DEBUG] DB Instance restore from snapshot configuration: %s", opts) - _, err := conn.RestoreDBInstanceFromDBSnapshot(&opts) + restoreDBInstanceFromDBSnapshotOutput, err := conn.RestoreDBInstanceFromDBSnapshot(&opts) // When using SQL Server engine with MultiAZ enabled, its not // possible to immediately enable mirroring since @@ -1073,12 +1079,14 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error opts.MultiAZ = aws.Bool(false) modifyDbInstanceInput.MultiAZ = aws.Bool(true) requiresModifyDbInstance = true - _, err = conn.RestoreDBInstanceFromDBSnapshot(&opts) + restoreDBInstanceFromDBSnapshotOutput, err = conn.RestoreDBInstanceFromDBSnapshot(&opts) } if err != nil { return fmt.Errorf("Error creating DB Instance: %s", err) } + + d.Set("resource_id", restoreDBInstanceFromDBSnapshotOutput.DBInstance.DbiResourceId) } else if v, ok := d.GetOk("restore_to_point_in_time"); ok { if input := expandRestoreToPointInTime(v.([]interface{})); input != nil { input.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) @@ -1163,10 +1171,12 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] DB Instance restore to point in time configuration: %s", input) - _, err := conn.RestoreDBInstanceToPointInTime(input) + restoreDBInstanceToPointInTime, err := conn.RestoreDBInstanceToPointInTime(input) if err != nil { return fmt.Errorf("error creating DB Instance: %w", err) } + + d.Set("resource_id", restoreDBInstanceToPointInTime.DBInstance.DbiResourceId) } } else { if _, ok := d.GetOk("allocated_storage"); !ok { @@ -1319,7 +1329,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error return nil }) if isResourceTimeoutError(err) { - _, err = conn.CreateDBInstance(&opts) + createdDBInstanceOutput, err = conn.CreateDBInstance(&opts) } if err != nil { if isAWSErr(err, "InvalidParameterValue", "") { @@ -1328,6 +1338,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } return fmt.Errorf("Error creating DB Instance: %s", err) } + d.Set("resource_id", createdDBInstanceOutput.DBInstance.DbiResourceId) // This is added here to avoid unnecessary modification when ca_cert_identifier is the default one if attr, ok := d.GetOk("ca_cert_identifier"); ok && attr.(string) != aws.StringValue(createdDBInstanceOutput.DBInstance.CACertificateIdentifier) { modifyDbInstanceInput.CACertificateIdentifier = aws.String(attr.(string)) @@ -1335,7 +1346,8 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } } - d.SetId(d.Get("identifier").(string)) + d.SetId(d.Get("resource_id").(string)) + log.Printf("[DEBUG] DB Instance ID: %q; DB Resource ID: %q", identifier, d.Id()) stateConf := &resource.StateChangeConf{ Pending: resourceAwsDbInstanceCreatePendingStates, @@ -1346,43 +1358,43 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error Delay: 30 * time.Second, // Wait 30 secs before starting } - log.Printf("[INFO] Waiting for DB Instance (%s) to be available", d.Id()) + log.Printf("[INFO] Waiting for DB Instance %q (%s) to become available", identifier, d.Id()) _, err := stateConf.WaitForState() if err != nil { return err } if requiresModifyDbInstance { - modifyDbInstanceInput.DBInstanceIdentifier = aws.String(d.Id()) + modifyDbInstanceInput.DBInstanceIdentifier = aws.String(identifier) - log.Printf("[INFO] DB Instance (%s) configuration requires ModifyDBInstance: %s", d.Id(), modifyDbInstanceInput) + log.Printf("[INFO] DB Instance %q (%s) configuration requires ModifyDBInstance: %s", identifier, d.Id(), modifyDbInstanceInput) _, err := conn.ModifyDBInstance(modifyDbInstanceInput) if err != nil { - return fmt.Errorf("error modifying DB Instance (%s): %s", d.Id(), err) + return fmt.Errorf("error modifying DB Instance %q (%s): %s", identifier, d.Id(), err) } - log.Printf("[INFO] Waiting for DB Instance (%s) to be available", d.Id()) + log.Printf("[INFO] Waiting for DB Instance %q (%s) to become available", identifier, 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 fmt.Errorf("error waiting for DB Instance %q (%s) to become available: %s", identifier, d.Id(), err) } } if requiresRebootDbInstance { rebootDbInstanceInput := &rds.RebootDBInstanceInput{ - DBInstanceIdentifier: aws.String(d.Id()), + DBInstanceIdentifier: aws.String(identifier), } - log.Printf("[INFO] DB Instance (%s) configuration requires RebootDBInstance: %s", d.Id(), rebootDbInstanceInput) + log.Printf("[INFO] DB Instance %q (%s) configuration requires RebootDBInstance: %s", identifier, d.Id(), rebootDbInstanceInput) _, err := conn.RebootDBInstance(rebootDbInstanceInput) if err != nil { - return fmt.Errorf("error rebooting DB Instance (%s): %s", d.Id(), err) + return fmt.Errorf("error rebooting DB Instance %q (%s): %s", identifier, d.Id(), err) } - log.Printf("[INFO] Waiting for DB Instance (%s) to be available", d.Id()) + log.Printf("[INFO] Waiting for DB Instance %q (%s) to become available", identifier, 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 fmt.Errorf("error waiting for DB Instance %q (%s) to become available: %s", identifier, d.Id(), err) } } @@ -1403,9 +1415,10 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { return nil } - d.Set("name", v.DBName) - d.Set("identifier", v.DBInstanceIdentifier) + d.SetId(*v.DbiResourceId) d.Set("resource_id", v.DbiResourceId) + d.Set("identifier", v.DBInstanceIdentifier) + d.Set("name", v.DBName) d.Set("username", v.MasterUsername) d.Set("deletion_protection", v.DeletionProtection) d.Set("engine", v.Engine) @@ -1481,7 +1494,7 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { tags, err := keyvaluetags.RdsListTags(conn, d.Get("arn").(string)) if err != nil { - return fmt.Errorf("error listing tags for RDS DB Instance (%s): %s", d.Get("arn").(string), err) + return fmt.Errorf("error listing tags for RDS DB Instance %q (%s): %s", d.Get("arn").(string), d.Id(), err) } if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { @@ -1525,9 +1538,9 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - log.Printf("[DEBUG] DB Instance destroy: %v", d.Id()) + log.Printf("[DEBUG] DB Instance destroy: %q (%s)", d.Get("arn"), d.Id()) - opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} + opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Get("identifier").(string))} skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) opts.SkipFinalSnapshot = aws.Bool(skipFinalSnapshot) @@ -1552,10 +1565,10 @@ func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error // InvalidDBInstanceState: Instance XXX is already being deleted. if err != nil && !isAWSErr(err, rds.ErrCodeInvalidDBInstanceStateFault, "is already being deleted") { - return fmt.Errorf("error deleting Database Instance %q: %s", d.Id(), err) + return fmt.Errorf("error deleting Database Instance %q (%s): %s", d.Get("identifier").(string), d.Id(), err) } - log.Println("[INFO] Waiting for DB Instance to be destroyed") + log.Printf("[INFO] Waiting for DB Instance %q (%s) to be destroyed", d.Get("identifier").(string), d.Id()) return waitUntilAwsDbInstanceIsDeleted(d.Id(), conn, d.Timeout(schema.TimeoutDelete)) } @@ -1588,9 +1601,11 @@ func waitUntilAwsDbInstanceIsDeleted(id string, conn *rds.RDS, timeout time.Dura func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn + oldIdentifier, newIdentifier := d.GetChange("identifier") + req := &rds.ModifyDBInstanceInput{ ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), - DBInstanceIdentifier: aws.String(d.Id()), + DBInstanceIdentifier: aws.String(oldIdentifier.(string)), } if !aws.BoolValue(req.ApplyImmediately) { @@ -1598,6 +1613,10 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error } requestUpdate := false + if d.HasChanges("identifier") { + req.NewDBInstanceIdentifier = aws.String(newIdentifier.(string)) + requestUpdate = true + } if d.HasChanges("allocated_storage", "iops") { req.Iops = aws.Int64(int64(d.Get("iops").(int))) req.AllocatedStorage = aws.Int64(int64(d.Get("allocated_storage").(int))) @@ -1785,13 +1804,13 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error } if err != nil { - return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) + return fmt.Errorf("Error modifying DB Instance %q (%s): %s", d.Get("identifier").(string), d.Id(), err) } - log.Printf("[DEBUG] Waiting for DB Instance (%s) to be available", d.Id()) + log.Printf("[DEBUG] Waiting for DB Instance %q (%s) to become available", d.Get("identifier").(string), 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 fmt.Errorf("error waiting for DB Instance %q (%s) to become available: %s", d.Get("identifier").(string), d.Id(), err) } } @@ -1800,7 +1819,7 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error if d.Get("replicate_source_db").(string) == "" { // promote opts := rds.PromoteReadReplicaInput{ - DBInstanceIdentifier: aws.String(d.Id()), + DBInstanceIdentifier: aws.String(d.Get("identifier").(string)), } attr := d.Get("backup_retention_period") opts.BackupRetentionPeriod = aws.Int64(int64(attr.(int))) @@ -1834,8 +1853,14 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error // error with AWS. When the DBInstance is not found, it returns no error and a // nil pointer. func resourceAwsDbInstanceRetrieve(id string, conn *rds.RDS) (*rds.DBInstance, error) { + resourceIdFilterName := "dbi-resource-id" opts := rds.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(id), + Filters: []*rds.Filter{ + { + Name: &resourceIdFilterName, + Values: []*string{&id}, + }, + }, } log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) @@ -1848,7 +1873,7 @@ func resourceAwsDbInstanceRetrieve(id string, conn *rds.RDS) (*rds.DBInstance, e return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) } - if len(resp.DBInstances) != 1 || resp.DBInstances[0] == nil || aws.StringValue(resp.DBInstances[0].DBInstanceIdentifier) != id { + if len(resp.DBInstances) != 1 || resp.DBInstances[0] == nil || aws.StringValue(resp.DBInstances[0].DbiResourceId) != id { return nil, nil } @@ -1879,7 +1904,7 @@ func resourceAwsDbInstanceStateRefreshFunc(id string, conn *rds.RDS) resource.St } if v.DBInstanceStatus != nil { - log.Printf("[DEBUG] DB Instance status for instance %s: %s", id, *v.DBInstanceStatus) + log.Printf("[DEBUG] DB Instance status for %q (%s): %s", *v.DBInstanceIdentifier, id, *v.DBInstanceStatus) } return v, *v.DBInstanceStatus, nil diff --git a/aws/resource_aws_db_instance_migrate.go b/aws/resource_aws_db_instance_migrate.go index 8514fe71146..c3fa3fa2781 100644 --- a/aws/resource_aws_db_instance_migrate.go +++ b/aws/resource_aws_db_instance_migrate.go @@ -388,3 +388,437 @@ func resourceAwsDbInstanceStateUpgradeV0(_ context.Context, rawState map[string] return rawState, nil } + +func resourceAwsDbInstanceResourceV1() *schema.Resource { + return &schema.Resource{ + SchemaVersion: 1, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "username": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "password": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + + "deletion_protection": { + Type: schema.TypeBool, + Optional: true, + }, + + "engine": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "engine_version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "ca_cert_identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "character_set_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "storage_encrypted": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + + "allocated_storage": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + + "storage_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"identifier_prefix"}, + }, + "identifier_prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "instance_class": { + Type: schema.TypeString, + Required: true, + }, + + "availability_zone": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "backup_retention_period": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + + "backup_window": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "iops": { + Type: schema.TypeInt, + Optional: true, + }, + + "latest_restorable_time": { + Type: schema.TypeString, + Computed: true, + }, + + "license_model": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "maintenance_window": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "max_allocated_storage": { + Type: schema.TypeInt, + Optional: true, + }, + + "multi_az": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "port": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + + "publicly_accessible": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "vpc_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "security_group_names": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "final_snapshot_identifier": { + Type: schema.TypeString, + Optional: true, + }, + + "restore_to_point_in_time": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ForceNew: true, + ConflictsWith: []string{ + "s3_import", + "snapshot_identifier", + "replicate_source_db", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "restore_time": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"restore_to_point_in_time.0.use_latest_restorable_time"}, + }, + + "source_db_instance_identifier": { + Type: schema.TypeString, + Optional: true, + }, + + "source_dbi_resource_id": { + Type: schema.TypeString, + Optional: true, + }, + + "use_latest_restorable_time": { + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"restore_to_point_in_time.0.restore_time"}, + }, + }, + }, + }, + + "s3_import": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{ + "snapshot_identifier", + "replicate_source_db", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bucket_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "bucket_prefix": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "ingestion_role": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "source_engine": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "source_engine_version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + + "skip_final_snapshot": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "copy_tags_to_snapshot": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "db_subnet_group_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "parameter_group_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "address": { + Type: schema.TypeString, + Computed: true, + }, + + "endpoint": { + Type: schema.TypeString, + Computed: true, + }, + + "hosted_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + + "status": { + Type: schema.TypeString, + Computed: true, + }, + + "apply_immediately": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "replicate_source_db": { + Type: schema.TypeString, + Optional: true, + }, + + "replicas": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "snapshot_identifier": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "auto_minor_version_upgrade": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "allow_major_version_upgrade": { + Type: schema.TypeBool, + Optional: true, + }, + + "monitoring_role_arn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "monitoring_interval": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + }, + + "option_group_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "timezone": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "iam_database_authentication_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + + "resource_id": { + Type: schema.TypeString, + Computed: true, + }, + + "enabled_cloudwatch_logs_exports": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "domain": { + Type: schema.TypeString, + Optional: true, + }, + + "domain_iam_role_name": { + Type: schema.TypeString, + Optional: true, + }, + + "performance_insights_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "performance_insights_kms_key_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "performance_insights_retention_period": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + + "delete_automated_backups": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "tags": tagsSchema(), + }, + } +} + +func resourceAwsDbInstanceStateUpgradeV1(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + if rawState == nil { + return nil, nil + } + + rawState["id"] = rawState["resource_id"] + + return rawState, nil +} diff --git a/tools/go.mod b/tools/go.mod index 748e315d1bb..0440c631e81 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -7,6 +7,7 @@ require ( github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.33.0 github.com/katbyte/terrafmt v0.2.1-0.20200913185704-5ff4421407b4 + github.com/pavius/impi v0.0.3 // indirect github.com/terraform-linters/tflint v0.20.3 ) diff --git a/tools/go.sum b/tools/go.sum index 1384a0fce44..76d6b9d5d22 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -640,6 +640,8 @@ github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pavius/impi v0.0.3 h1:DND6MzU+BLABhOZXbELR3FU8b+zDgcq4dOCNLhiTYuI= +github.com/pavius/impi v0.0.3/go.mod h1:x/hU0bfdWIhuOT1SKwiJg++yvkk6EuOtJk8WtDZqgr8= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= From 18e82bed33c4637c7bf3bcead65ca49b64fc9d79 Mon Sep 17 00:00:00 2001 From: Dmytro Kryvenko Date: Tue, 15 Dec 2020 20:11:16 -0800 Subject: [PATCH 2/5] Unnecessary d.SetId as resource ID is immutable --- aws/resource_aws_db_instance.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index bd1c38ba250..4a5d757aa41 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -1415,7 +1415,6 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { return nil } - d.SetId(*v.DbiResourceId) d.Set("resource_id", v.DbiResourceId) d.Set("identifier", v.DBInstanceIdentifier) d.Set("name", v.DBName) From 10f539f5247209432babb5686076e00b92f2626f Mon Sep 17 00:00:00 2001 From: Dmytro Kryvenko Date: Wed, 16 Dec 2020 17:07:52 -0800 Subject: [PATCH 3/5] aws_db_instance: Use CustomizeDiff to inform terraform about address, arn and endpoint changes on identifier change --- aws/resource_aws_db_instance.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 4a5d757aa41..fbf2419680d 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "regexp" @@ -11,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -540,6 +542,18 @@ func resourceAwsDbInstance() *schema.Resource { "tags": tagsSchema(), }, + + CustomizeDiff: customdiff.All( + customdiff.ComputedIf("address", func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) bool { + return diff.HasChange("identifier") + }), + customdiff.ComputedIf("arn", func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) bool { + return diff.HasChange("identifier") + }), + customdiff.ComputedIf("endpoint", func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) bool { + return diff.HasChange("identifier") + }), + ), } } @@ -1600,11 +1614,13 @@ func waitUntilAwsDbInstanceIsDeleted(id string, conn *rds.RDS, timeout time.Dura func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - oldIdentifier, newIdentifier := d.GetChange("identifier") + oldIdentifierPtr, newIdentifierPtr := d.GetChange("identifier") + oldIdentifier := oldIdentifierPtr.(string) + newIdentifier := newIdentifierPtr.(string) req := &rds.ModifyDBInstanceInput{ ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), - DBInstanceIdentifier: aws.String(oldIdentifier.(string)), + DBInstanceIdentifier: aws.String(oldIdentifier), } if !aws.BoolValue(req.ApplyImmediately) { @@ -1613,7 +1629,7 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error requestUpdate := false if d.HasChanges("identifier") { - req.NewDBInstanceIdentifier = aws.String(newIdentifier.(string)) + req.NewDBInstanceIdentifier = aws.String(newIdentifier) requestUpdate = true } if d.HasChanges("allocated_storage", "iops") { From ae645768ea80fa3cb1703be0a7942b7da2aa5068 Mon Sep 17 00:00:00 2001 From: Dmytro Kryvenko Date: Wed, 16 Dec 2020 18:53:40 -0800 Subject: [PATCH 4/5] aws_db_instance: Add identifier change tests (and fix other tests that were relying on ID=identifier) --- aws/resource_aws_db_instance_test.go | 69 +++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index fc086b55d1b..3dd12373c80 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -125,6 +125,36 @@ func TestAccAWSDBInstance_basic(t *testing.T) { }) } +func TestAccAWSDBInstance_identifierUpdate(t *testing.T) { + var dbInstance1, dbInstance2 rds.DBInstance + + rIdentifier1 := acctest.RandString(10) + rIdentifier2 := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_identifier(rIdentifier1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &dbInstance1), + resource.TestCheckResourceAttr("aws_db_instance.bar", "identifier", rIdentifier1), + ), + }, + { + Config: testAccAWSDBInstanceConfig_identifier(rIdentifier2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists("aws_db_instance.bar", &dbInstance2), + testAccCheckAWSDBInstanceSameResourceId(&dbInstance1, &dbInstance2), + resource.TestCheckResourceAttr("aws_db_instance.bar", "identifier", rIdentifier2), + ), + }, + }, + }) +} + func TestAccAWSDBInstance_namePrefix(t *testing.T) { var v rds.DBInstance @@ -2716,8 +2746,14 @@ func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestC conn := testAccProvider.Meta().(*AWSClient).rdsconn + resourceIdFilterName := "dbi-resource-id" opts := rds.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(rs.Primary.ID), + Filters: []*rds.Filter{ + { + Name: &resourceIdFilterName, + Values: []*string{aws.String(rs.Primary.ID)}, + }, + }, } resp, err := conn.DescribeDBInstances(&opts) @@ -2727,7 +2763,7 @@ func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestC } if len(resp.DBInstances) != 1 || - *resp.DBInstances[0].DBInstanceIdentifier != rs.Primary.ID { + *resp.DBInstances[0].DbiResourceId != rs.Primary.ID { return fmt.Errorf("DB Instance not found") } @@ -2737,6 +2773,16 @@ func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestC } } +func testAccCheckAWSDBInstanceSameResourceId(v1, v2 *rds.DBInstance) resource.TestCheckFunc { + return func(s *terraform.State) error { + if *v1.DbiResourceId != *v2.DbiResourceId { + return fmt.Errorf("DB Instances has different Resource ID") + } + + return nil + } +} + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/8792 func TestAccAWSDBInstance_PerformanceInsightsEnabled_DisabledToEnabled(t *testing.T) { var dbInstance rds.DBInstance @@ -3100,6 +3146,25 @@ resource "aws_db_instance" "bar" { `)) } +func testAccAWSDBInstanceConfig_identifier(rIdentifier string) string { + return composeConfig(testAccAWSDBInstanceConfig_orderableClassMysql(), fmt.Sprintf(` +resource "aws_db_instance" "bar" { + identifier = %[1]q + allocated_storage = 10 + backup_retention_period = 0 + 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 + parameter_group_name = "default.mysql5.6" + password = "barbarbarbar" + skip_final_snapshot = true + username = "foo" + + apply_immediately = true +} +`, rIdentifier)) +} + func testAccAWSDBInstanceConfig_namePrefix() string { return composeConfig(testAccAWSDBInstanceConfig_orderableClassMysql(), fmt.Sprintf(` resource "aws_db_instance" "test" { From 876773995174f2b62399df56c047ac325320d2ab Mon Sep 17 00:00:00 2001 From: Dmytro Kryvenko Date: Thu, 17 Dec 2020 04:42:27 -0800 Subject: [PATCH 5/5] aws_db_instance: Fix tests and docs --- aws/resource_aws_db_instance.go | 4 +- aws/resource_aws_db_instance_test.go | 142 +++++++++++++---------- website/docs/r/db_instance.html.markdown | 18 +-- 3 files changed, 92 insertions(+), 72 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index fbf2419680d..3f55b4875c6 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -19,6 +19,8 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) +const DbiResourceIdFilterName = "dbi-resource-id" + func resourceAwsDbInstance() *schema.Resource { return &schema.Resource{ Create: resourceAwsDbInstanceCreate, @@ -1868,7 +1870,7 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error // error with AWS. When the DBInstance is not found, it returns no error and a // nil pointer. func resourceAwsDbInstanceRetrieve(id string, conn *rds.RDS) (*rds.DBInstance, error) { - resourceIdFilterName := "dbi-resource-id" + resourceIdFilterName := DbiResourceIdFilterName opts := rds.DescribeDBInstancesInput{ Filters: []*rds.Filter{ { diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 3dd12373c80..2ee9f58e844 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -128,8 +128,8 @@ func TestAccAWSDBInstance_basic(t *testing.T) { func TestAccAWSDBInstance_identifierUpdate(t *testing.T) { var dbInstance1, dbInstance2 rds.DBInstance - rIdentifier1 := acctest.RandString(10) - rIdentifier2 := acctest.RandString(10) + rIdentifier1 := acctest.RandomWithPrefix("tf-acc-test") + rIdentifier2 := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -360,7 +360,7 @@ func TestAccAWSDBInstance_DbSubnetGroupName(t *testing.T) { Config: testAccAWSDBInstanceConfig_DbSubnetGroupName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), - testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), ), }, @@ -415,7 +415,7 @@ func TestAccAWSDBInstance_DbSubnetGroupName_VpcSecurityGroupIds(t *testing.T) { Config: testAccAWSDBInstanceConfig_DbSubnetGroupName_VpcSecurityGroupIds(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), - testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), ), }, @@ -815,7 +815,7 @@ func TestAccAWSDBInstance_ReplicateSourceDb_DbSubnetGroupName(t *testing.T) { Config: testAccAWSDBInstanceConfig_ReplicateSourceDb_DbSubnetGroupName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), - testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), ), }, @@ -875,7 +875,7 @@ func TestAccAWSDBInstance_ReplicateSourceDb_DbSubnetGroupName_VpcSecurityGroupId Config: testAccAWSDBInstanceConfig_ReplicateSourceDb_DbSubnetGroupName_VpcSecurityGroupIds(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), - testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), ), }, @@ -1442,7 +1442,7 @@ func TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName(t *testing.T) { testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance), testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot), testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), - testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), ), }, @@ -1507,7 +1507,7 @@ func TestAccAWSDBInstance_SnapshotIdentifier_DbSubnetGroupName_VpcSecurityGroupI testAccCheckAWSDBInstanceExists(sourceDbResourceName, &sourceDbInstance), testAccCheckDbSnapshotExists(snapshotResourceName, &dbSnapshot), testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), - testAccCheckDBSubnetGroupExists(resourceName, &dbSubnetGroup), + testAccCheckDBSubnetGroupExists(dbSubnetGroupResourceName, &dbSubnetGroup), resource.TestCheckResourceAttrPair(resourceName, "db_subnet_group_name", dbSubnetGroupResourceName, "name"), ), }, @@ -2492,7 +2492,7 @@ func testAccCheckAWSDBInstanceAutomatedBackups(s *terraform.State) error { log.Printf("[INFO] Trying to locate the DBInstance Automated Backup") describeOutput, err := conn.DescribeDBInstanceAutomatedBackups( &rds.DescribeDBInstanceAutomatedBackupsInput{ - DBInstanceIdentifier: aws.String(rs.Primary.ID), + DbiResourceId: aws.String(rs.Primary.ID), }) if err != nil { return err @@ -2524,10 +2524,16 @@ func testAccCheckAWSDBInstanceDestroy(s *terraform.State) error { } // Try to find the Group + resourceIdFilterName := DbiResourceIdFilterName var err error resp, err := conn.DescribeDBInstances( &rds.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(rs.Primary.ID), + Filters: []*rds.Filter{ + { + Name: &resourceIdFilterName, + Values: []*string{aws.String(rs.Primary.ID)}, + }, + }, }) if err != nil { @@ -2538,7 +2544,7 @@ func testAccCheckAWSDBInstanceDestroy(s *terraform.State) error { } if len(resp.DBInstances) != 0 && - *resp.DBInstances[0].DBInstanceIdentifier == rs.Primary.ID { + *resp.DBInstances[0].DbiResourceId == rs.Primary.ID { return fmt.Errorf("DB Instance still exists") } } @@ -2678,9 +2684,15 @@ func testAccCheckAWSDBInstanceSnapshot(s *terraform.State) error { return err } + resourceIdFilterName := DbiResourceIdFilterName resp, err := conn.DescribeDBInstances( &rds.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(rs.Primary.ID), + Filters: []*rds.Filter{ + { + Name: &resourceIdFilterName, + Values: []*string{aws.String(rs.Primary.ID)}, + }, + }, }) if err != nil { @@ -2691,7 +2703,7 @@ func testAccCheckAWSDBInstanceSnapshot(s *terraform.State) error { } - if len(resp.DBInstances) != 0 && aws.StringValue(resp.DBInstances[0].DBInstanceIdentifier) == rs.Primary.ID { + if len(resp.DBInstances) != 0 && aws.StringValue(resp.DBInstances[0].DbiResourceId) == rs.Primary.ID { return fmt.Errorf("DB Instance still exists") } } @@ -2707,16 +2719,22 @@ func testAccCheckAWSDBInstanceNoSnapshot(s *terraform.State) error { continue } + resourceIdFilterName := DbiResourceIdFilterName resp, err := conn.DescribeDBInstances( &rds.DescribeDBInstancesInput{ - DBInstanceIdentifier: aws.String(rs.Primary.ID), + Filters: []*rds.Filter{ + { + Name: &resourceIdFilterName, + Values: []*string{aws.String(rs.Primary.ID)}, + }, + }, }) if err != nil && !isAWSErr(err, rds.ErrCodeDBInstanceNotFoundFault, "") { return err } - if len(resp.DBInstances) != 0 && aws.StringValue(resp.DBInstances[0].DBInstanceIdentifier) == rs.Primary.ID { + if len(resp.DBInstances) != 0 && aws.StringValue(resp.DBInstances[0].DbiResourceId) == rs.Primary.ID { return fmt.Errorf("DB Instance still exists") } @@ -2746,7 +2764,7 @@ func testAccCheckAWSDBInstanceExists(n string, v *rds.DBInstance) resource.TestC conn := testAccProvider.Meta().(*AWSClient).rdsconn - resourceIdFilterName := "dbi-resource-id" + resourceIdFilterName := DbiResourceIdFilterName opts := rds.DescribeDBInstancesInput{ Filters: []*rds.Filter{ { @@ -4445,7 +4463,7 @@ resource "aws_db_instance" "mssql" { } resource "aws_db_snapshot" "mssql-snap" { - db_instance_identifier = aws_db_instance.mssql.id + db_instance_identifier = aws_db_instance.mssql.identifier db_snapshot_identifier = "tf-acc-test-%[1]d" } @@ -4581,7 +4599,7 @@ resource "aws_db_instance" "mysql" { } resource "aws_db_snapshot" "mysql-snap" { - db_instance_identifier = aws_db_instance.mysql.id + db_instance_identifier = aws_db_instance.mysql.identifier db_snapshot_identifier = "tf-acc-test-%[1]d" } @@ -5258,7 +5276,7 @@ resource "aws_db_instance" "source" { resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName)) @@ -5281,7 +5299,7 @@ resource "aws_db_instance" "test" { allocated_storage = %[2]d identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, allocatedStorage)) @@ -5304,7 +5322,7 @@ resource "aws_db_instance" "test" { allow_major_version_upgrade = %[2]t identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, allowMajorVersionUpgrade)) @@ -5327,7 +5345,7 @@ resource "aws_db_instance" "test" { auto_minor_version_upgrade = %[2]t identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, autoMinorVersionUpgrade)) @@ -5353,7 +5371,7 @@ resource "aws_db_instance" "test" { availability_zone = data.aws_availability_zones.available.names[0] identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName)) @@ -5376,7 +5394,7 @@ resource "aws_db_instance" "test" { backup_retention_period = %[2]d identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, backupRetentionPeriod)) @@ -5402,7 +5420,7 @@ resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class maintenance_window = %[3]q - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, backupWindow, maintenanceWindow)) @@ -5793,7 +5811,7 @@ resource "aws_db_instance" "test" { deletion_protection = %[2]t identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, deletionProtection)) @@ -5816,7 +5834,7 @@ resource "aws_db_instance" "test" { iam_database_authentication_enabled = %[2]t identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, iamDatabaseAuthenticationEnabled)) @@ -5842,7 +5860,7 @@ resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class maintenance_window = %[3]q - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, backupWindow, maintenanceWindow)) @@ -5866,7 +5884,7 @@ resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class max_allocated_storage = %[2]d - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, maxAllocatedStorage)) @@ -5917,7 +5935,7 @@ resource "aws_db_instance" "test" { instance_class = aws_db_instance.source.instance_class monitoring_interval = %[2]d monitoring_role_arn = aws_iam_role.test.arn - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, monitoringInterval)) @@ -5940,7 +5958,7 @@ resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class multi_az = %[2]t - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, multiAz)) @@ -5974,7 +5992,7 @@ resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class parameter_group_name = aws_db_parameter_group.test.id - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName)) @@ -5997,7 +6015,7 @@ resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class port = %[2]d - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName, port)) @@ -6028,7 +6046,7 @@ resource "aws_db_instance" "source" { resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true vpc_security_group_ids = [aws_security_group.test.id] } @@ -6056,7 +6074,7 @@ resource "aws_db_instance" "source" { resource "aws_db_instance" "test" { identifier = %[1]q instance_class = aws_db_instance.source.instance_class - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier ca_cert_identifier = data.aws_rds_certificate.latest.id skip_final_snapshot = true } @@ -6076,7 +6094,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6102,7 +6120,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6138,7 +6156,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6177,7 +6195,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6215,7 +6233,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6245,7 +6263,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6272,7 +6290,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6300,7 +6318,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6329,7 +6347,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6385,7 +6403,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6486,7 +6504,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6547,7 +6565,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6575,7 +6593,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6602,7 +6620,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6631,7 +6649,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6659,7 +6677,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6714,7 +6732,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6742,7 +6760,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6779,7 +6797,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6821,7 +6839,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6850,7 +6868,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6879,7 +6897,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6913,7 +6931,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6950,7 +6968,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -6986,7 +7004,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } @@ -7223,7 +7241,7 @@ resource "aws_db_instance" "test" { performance_insights_enabled = true performance_insights_kms_key_id = aws_kms_key.test.arn performance_insights_retention_period = 7 - replicate_source_db = aws_db_instance.source.id + replicate_source_db = aws_db_instance.source.identifier skip_final_snapshot = true } `, rName) @@ -7278,7 +7296,7 @@ resource "aws_db_instance" "source" { } resource "aws_db_snapshot" "test" { - db_instance_identifier = aws_db_instance.source.id + db_instance_identifier = aws_db_instance.source.identifier db_snapshot_identifier = %[1]q } diff --git a/website/docs/r/db_instance.html.markdown b/website/docs/r/db_instance.html.markdown index 9030a8d2e6b..5315475a6a3 100644 --- a/website/docs/r/db_instance.html.markdown +++ b/website/docs/r/db_instance.html.markdown @@ -124,9 +124,9 @@ set to `false`. * `iam_database_authentication_enabled` - (Optional) Specifies whether or mappings of AWS Identity and Access Management (IAM) accounts to database accounts is enabled. -* `identifier` - (Optional, Forces new resource) The name of the RDS instance, +* `identifier` - (Optional) The name of the RDS instance, if omitted, Terraform will assign a random, unique identifier. Required if `restore_to_point_in_time` is specified. -* `identifier_prefix` - (Optional, Forces new resource) Creates a unique +* `identifier_prefix` - (Optional) Creates a unique identifier beginning with the specified prefix. Conflicts with `identifier`. * `instance_class` - (Required) The instance type of the RDS instance. * `iops` - (Optional) The amount of provisioned IOPS. Setting this implies a @@ -265,8 +265,8 @@ https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Ma In addition to all arguments above, the following attributes are exported: -* `address` - The hostname of the RDS instance. See also `endpoint` and `port`. -* `arn` - The ARN of the RDS instance. +* `address` - The hostname of the RDS instance. See also `endpoint` and `port`. It will change together with `identifier` change. +* `arn` - The ARN of the RDS instance. It will change together with `identifier` change. * `allocated_storage` - The amount of allocated storage. * `availability_zone` - The availability zone of the instance. * `backup_retention_period` - The backup retention period. @@ -275,19 +275,19 @@ In addition to all arguments above, the following attributes are exported: DB instance. * `domain` - The ID of the Directory Service Active Directory domain the instance is joined to * `domain_iam_role_name` - The name of the IAM role to be used when making API calls to the Directory Service. -* `endpoint` - The connection endpoint in `address:port` format. +* `endpoint` - The connection endpoint in `address:port` format. It will change together with `identifier` change. * `engine` - The database engine. * `engine_version` - The database engine version. * `hosted_zone_id` - The canonical hosted zone ID of the DB instance (to be used in a Route 53 Alias record). -* `id` - The RDS instance ID. +* `id` - The RDS Resource ID of this instance (same as `resource_id`). It is immutable. * `instance_class`- The RDS instance class. * `latest_restorable_time` - The latest time, in UTC [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8), to which a database can be restored with point-in-time restore. * `maintenance_window` - The instance maintenance window. * `multi_az` - If the RDS instance is multi AZ enabled. * `name` - The database name. * `port` - The database port. -* `resource_id` - The RDS Resource ID of this instance. +* `resource_id` - The RDS Resource ID of this instance (immutable). * `status` - The RDS instance status. * `storage_encrypted` - Specifies whether the DB instance is encrypted. * `username` - The master username for the database. @@ -298,8 +298,8 @@ On Oracle and Microsoft SQL instances the following is exported additionally: ## Import -DB Instances can be imported using the `identifier`, e.g. +DB Instances can be imported using the `resource_id`, e.g. ``` -$ terraform import aws_db_instance.default mydb-rds-instance +$ terraform import aws_db_instance.default db-L5GOU4KU6U3KKMIVY5JG54IAHQ ```