diff --git a/.changelog/20207.txt b/.changelog/20207.txt new file mode 100644 index 00000000000..868f0d7e406 --- /dev/null +++ b/.changelog/20207.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_db_instance: Use engine_version and engine_version_actual to set and track engine versions +``` diff --git a/aws/diff_suppress_funcs.go b/aws/diff_suppress_funcs.go index 911559ea5a7..fc3676bff30 100644 --- a/aws/diff_suppress_funcs.go +++ b/aws/diff_suppress_funcs.go @@ -5,7 +5,6 @@ import ( "encoding/json" "log" "net/url" - "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -43,32 +42,6 @@ func suppressMissingOptionalConfigurationBlock(k, old, new string, d *schema.Res return old == "1" && new == "0" } -// Suppresses minor version changes to the db_instance engine_version attribute -func suppressAwsDbEngineVersionDiffs(k, old, new string, d *schema.ResourceData) bool { - // First check if the old/new values are nil. - // If both are nil, we have no state to compare the values with, so register a diff. - // This populates the attribute field during a plan/apply with fresh state, allowing - // the attribute to still be used in future resources. - // See https://github.com/hashicorp/terraform/issues/11881 - if old == "" && new == "" { - return false - } - - if v, ok := d.GetOk("auto_minor_version_upgrade"); ok { - if v.(bool) { - // If we're set to auto upgrade minor versions - // ignore a minor version diff between versions - if strings.HasPrefix(old, new) { - log.Printf("[DEBUG] Ignoring minor version diff") - return true - } - } - } - - // Throw a diff by default - return false -} - func suppressEquivalentJsonDiffs(k, old, new string, d *schema.ResourceData) bool { ob := bytes.NewBufferString("") if err := json.Compact(ob, []byte(old)); err != nil { diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 91e5e0bd92f..5c1e9cdc0b7 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -86,10 +86,14 @@ func resourceAwsDbInstance() *schema.Resource { }, "engine_version": { - Type: schema.TypeString, - Optional: true, - Computed: true, - DiffSuppressFunc: suppressAwsDbEngineVersionDiffs, + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "engine_version_actual": { + Type: schema.TypeString, + Computed: true, }, "ca_cert_identifier": { @@ -1407,7 +1411,6 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { d.Set("username", v.MasterUsername) d.Set("deletion_protection", v.DeletionProtection) d.Set("engine", v.Engine) - d.Set("engine_version", v.EngineVersion) d.Set("allocated_storage", v.AllocatedStorage) d.Set("iops", v.Iops) d.Set("copy_tags_to_snapshot", v.CopyTagsToSnapshot) @@ -1433,6 +1436,8 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { d.Set("db_subnet_group_name", v.DBSubnetGroup.DBSubnetGroupName) } + dbSetResourceDataEngineVersionFromInstance(d, v) + if v.CharacterSetName != nil { d.Set("character_set_name", v.CharacterSetName) } @@ -1993,3 +1998,12 @@ func expandRestoreToPointInTime(l []interface{}) *rds.RestoreDBInstanceToPointIn return input } + +func dbSetResourceDataEngineVersionFromInstance(d *schema.ResourceData, c *rds.DBInstance) { + oldVersion := d.Get("engine_version").(string) + newVersion := aws.StringValue(c.EngineVersion) + if oldVersion != newVersion && string(append([]byte(oldVersion), []byte(".")...)) != string([]byte(newVersion)[0:len(oldVersion)+1]) { + d.Set("engine_version", newVersion) + } + d.Set("engine_version_actual", newVersion) +} diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 22130346aeb..8dfbd2765cc 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -116,6 +116,39 @@ func TestAccAWSDBInstance_basic(t *testing.T) { }) } +func TestAccAWSDBInstance_OnlyMajorVersion(t *testing.T) { + var dbInstance1 rds.DBInstance + resourceName := "aws_db_instance.test" + engine := "mysql" + engineVersion1 := "5.6" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_MajorVersionOnly(engine, engineVersion1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance1), + resource.TestCheckResourceAttr(resourceName, "engine", engine), + resource.TestCheckResourceAttr(resourceName, "engine_version", engineVersion1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "engine_version", + "password", + }, + }, + }, + }) +} + func TestAccAWSDBInstance_namePrefix(t *testing.T) { var v rds.DBInstance @@ -3281,6 +3314,28 @@ resource "aws_db_instance" "bar" { `) } +func testAccAWSDBInstanceConfig_MajorVersionOnly(engine, engineVersion string) string { + return composeConfig(testAccAWSDBInstanceConfig_orderableClassMysql(), fmt.Sprintf(` +resource "aws_db_instance" "test" { + allocated_storage = 10 + backup_retention_period = 0 + engine = %[1]q + engine_version = %[2]q + instance_class = "db.r4.large" + name = "baz" + parameter_group_name = "default.mysql5.6" + password = "barbarbarbar" + skip_final_snapshot = true + username = "foo" + + # Maintenance Window is stored in lower case in the API, though not strictly + # documented. Terraform will downcase this to match (as opposed to throw a + # validation error). + maintenance_window = "Fri:09:00-Fri:09:30" +} +`, engine, engineVersion)) +} + func testAccAWSDBInstanceConfig_namePrefix() string { return composeConfig(testAccAWSDBInstanceConfig_orderableClassMysql(), ` resource "aws_db_instance" "test" { diff --git a/website/docs/r/db_instance.html.markdown b/website/docs/r/db_instance.html.markdown index d24318f255d..d4c3cdc13c6 100644 --- a/website/docs/r/db_instance.html.markdown +++ b/website/docs/r/db_instance.html.markdown @@ -116,8 +116,8 @@ For information on the difference between the available Aurora MySQL engines see [Comparison between Aurora MySQL 1 and Aurora MySQL 2](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/AuroraMySQL.Updates.20180206.html) in the Amazon RDS User Guide. * `engine_version` - (Optional) The engine version to use. If `auto_minor_version_upgrade` -is enabled, you can provide a prefix of the version such as `5.7` (for `5.7.10`) and -this attribute will ignore differences in the patch version automatically (e.g. `5.7.17`). +is enabled, you can provide a prefix of the version such as `5.7` (for `5.7.10`). +The actual engine version used is returned in the attribute `engine_version_actual`, [defined below](#engine_version_actual). For supported values, see the EngineVersion parameter in [API action CreateDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html). Note that for Amazon Aurora instances the engine version must match the [DB cluster](/docs/providers/aws/r/rds_cluster.html)'s engine version'. * `final_snapshot_identifier` - (Optional) The name of your final DB snapshot @@ -279,7 +279,7 @@ DB instance. * `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. * `engine` - The database engine. -* `engine_version` - The database engine version. +* `engine_version_actual` - The running version of the database. * `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.