Skip to content

Commit

Permalink
Merge pull request #23996 from hashicorp/elasticache-auto-update
Browse files Browse the repository at this point in the history
elasticache/aws_elasticache_cluster: Enable `auto_minor_version_upgrade`
  • Loading branch information
gdavison authored Apr 7, 2022
2 parents 831b4ed + 625cab9 commit b599209
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 55 deletions.
7 changes: 7 additions & 0 deletions .changelog/23996.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_elasticache_cluster: Add `auto_minor_version_upgrade` argument
```

```release-note:bug
resource/aws_elasticache_replication_group: Allow disabling `auto_minor_version_upgrade`
```
30 changes: 27 additions & 3 deletions internal/service/elasticache/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"regexp"
"sort"
"strconv"
"strings"
"time"

Expand All @@ -18,6 +19,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/experimental/nullable"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
Expand Down Expand Up @@ -53,6 +55,12 @@ func ResourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"auto_minor_version_upgrade": {
Type: nullable.TypeNullableBool,
Optional: true,
Default: "true",
ValidateFunc: nullable.ValidateTypeStringNullableBool,
},
"availability_zone": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -340,8 +348,15 @@ func resourceClusterCreate(d *schema.ResourceData, meta interface{}) error {
req.Engine = aws.String(v.(string))
}

if v, ok := d.GetOk("engine_version"); ok {
req.EngineVersion = aws.String(v.(string))
version := d.Get("engine_version").(string)
if version != "" {
req.EngineVersion = aws.String(version)
}

if v, ok := d.GetOk("auto_minor_version_upgrade"); ok {
if v, null, _ := nullable.Bool(v.(string)).Value(); !null {
req.AutoMinorVersionUpgrade = aws.Bool(v)
}
}

if v, ok := d.GetOk("port"); ok {
Expand Down Expand Up @@ -523,6 +538,7 @@ func setFromCacheCluster(d *schema.ResourceData, c *elasticache.CacheCluster) er
if err := setEngineVersionFromCacheCluster(d, c); err != nil {
return err
}
d.Set("auto_minor_version_upgrade", strconv.FormatBool(aws.BoolValue(c.AutoMinorVersionUpgrade)))

d.Set("subnet_group_name", c.CacheSubnetGroupName)
if err := d.Set("security_group_names", flattenSecurityGroupNames(c.CacheSecurityGroups)); err != nil {
Expand Down Expand Up @@ -594,7 +610,7 @@ func resourceClusterUpdate(d *schema.ResourceData, meta interface{}) error {
previousLogDeliveryConfig := oldLogDeliveryConfig.(*schema.Set).List()
for _, previous := range previousLogDeliveryConfig {
logDeliveryConfigurationRequest := expandEmptyLogDeliveryConfigurations(previous.(map[string]interface{}))
//if something was removed, send an empty request
// if something was removed, send an empty request
if !logTypesToSubmit[*logDeliveryConfigurationRequest.LogType] {
req.LogDeliveryConfigurations = append(req.LogDeliveryConfigurations, &logDeliveryConfigurationRequest)
}
Expand Down Expand Up @@ -623,6 +639,14 @@ func resourceClusterUpdate(d *schema.ResourceData, meta interface{}) error {
requestUpdate = true
}

if d.HasChange("auto_minor_version_upgrade") {
v := d.Get("auto_minor_version_upgrade")
if v, null, _ := nullable.Bool(v.(string)).Value(); !null {
req.AutoMinorVersionUpgrade = aws.Bool(v)
}
requestUpdate = true
}

if d.HasChange("snapshot_window") {
req.SnapshotWindow = aws.String(d.Get("snapshot_window").(string))
requestUpdate = true
Expand Down
108 changes: 103 additions & 5 deletions internal/service/elasticache/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestAccElastiCacheCluster_Engine_memcached(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccClusterConfig_Engine_Memcached(rName),
Check: resource.ComposeTestCheckFunc(
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckClusterExists(resourceName, &ec),
resource.TestCheckResourceAttr(resourceName, "cache_nodes.0.id", "0001"),
resource.TestCheckResourceAttrSet(resourceName, "configuration_endpoint"),
Expand Down Expand Up @@ -77,11 +77,46 @@ func TestAccElastiCacheCluster_Engine_redis(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccClusterConfig_Engine_Redis(rName),
Check: resource.ComposeTestCheckFunc(
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckClusterExists(resourceName, &ec),
resource.TestCheckResourceAttr(resourceName, "cache_nodes.0.id", "0001"),
resource.TestCheckResourceAttr(resourceName, "engine", "redis"),
resource.TestMatchResourceAttr(resourceName, "engine_version_actual", regexp.MustCompile(`^6\.[[:digit:]]+\.[[:digit:]]+$`)),
resource.TestCheckResourceAttr(resourceName, "port", "6379"),
resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"apply_immediately",
},
},
},
})
}

func TestAccElastiCacheCluster_Engine_redis_v5(t *testing.T) {
var ec elasticache.CacheCluster
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_elasticache_cluster.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccClusterConfig_Engine_Redis_v5(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckClusterExists(resourceName, &ec),
resource.TestCheckResourceAttr(resourceName, "engine", "redis"),
resource.TestCheckResourceAttr(resourceName, "engine_version_actual", "5.0.6"),
// Even though it is ignored, the API returns `true` in this case
resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"),
),
},
{
Expand Down Expand Up @@ -763,6 +798,43 @@ func TestAccElastiCacheCluster_Redis_finalSnapshot(t *testing.T) {
})
}

func TestAccElastiCacheCluster_Redis_autoMinorVersionUpgrade(t *testing.T) {
var cluster elasticache.CacheCluster
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_elasticache_cluster.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckClusterDestroy,
Steps: []resource.TestStep{
{
Config: testAccClusterConfig_Redis_AutoMinorVersionUpgrade(rName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckClusterExists(resourceName, &cluster),
resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"apply_immediately",
},
},
{
Config: testAccClusterConfig_Redis_AutoMinorVersionUpgrade(rName, true),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckClusterExists(resourceName, &cluster),
resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"),
),
},
},
})
}

func TestAccElastiCacheCluster_Engine_Redis_LogDeliveryConfigurations(t *testing.T) {
var ec elasticache.CacheCluster
rName := sdkacctest.RandomWithPrefix("tf-acc-test")
Expand Down Expand Up @@ -1110,7 +1182,7 @@ func testAccCheckClusterEC2ClassicExists(n string, v *elasticache.CacheCluster)
func testAccClusterConfig_Engine_Memcached(rName string) string {
return fmt.Sprintf(`
resource "aws_elasticache_cluster" "test" {
cluster_id = "%s"
cluster_id = "%[1]s"
engine = "memcached"
node_type = "cache.t3.small"
num_cache_nodes = 1
Expand All @@ -1121,7 +1193,19 @@ resource "aws_elasticache_cluster" "test" {
func testAccClusterConfig_Engine_Redis(rName string) string {
return fmt.Sprintf(`
resource "aws_elasticache_cluster" "test" {
cluster_id = "%s"
cluster_id = "%[1]s"
engine = "redis"
node_type = "cache.t3.small"
num_cache_nodes = 1
}
`, rName)
}

func testAccClusterConfig_Engine_Redis_v5(rName string) string {
return fmt.Sprintf(`
resource "aws_elasticache_cluster" "test" {
cluster_id = "%[1]s"
engine_version = "5.0.6"
engine = "redis"
node_type = "cache.t3.small"
num_cache_nodes = 1
Expand All @@ -1132,7 +1216,7 @@ resource "aws_elasticache_cluster" "test" {
func testAccClusterConfig_Engine_None(rName string) string {
return fmt.Sprintf(`
resource "aws_elasticache_cluster" "test" {
cluster_id = "%s"
cluster_id = "%[1]s"
node_type = "cache.t3.small"
num_cache_nodes = 1
}
Expand Down Expand Up @@ -1619,6 +1703,20 @@ resource "aws_elasticache_cluster" "test" {
`, rName)
}

func testAccClusterConfig_Redis_AutoMinorVersionUpgrade(rName string, enable bool) string {
return fmt.Sprintf(`
resource "aws_elasticache_cluster" "test" {
cluster_id = %[1]q
engine = "redis"
engine_version = "6.x"
node_type = "cache.t3.small"
num_cache_nodes = 1
auto_minor_version_upgrade = %[2]t
}
`, rName, enable)
}

func testAccClusterConfig_Engine_Redis_LogDeliveryConfigurations(rName string, slowLogDeliveryEnabled bool, slowDeliveryDestination string, slowDeliveryFormat string, engineLogDeliveryEnabled bool, engineDeliveryDestination string, engineLogDeliveryFormat string) string {
return fmt.Sprintf(`
data "aws_iam_policy_document" "p" {
Expand Down
62 changes: 34 additions & 28 deletions internal/service/elasticache/replication_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/experimental/nullable"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
Expand Down Expand Up @@ -59,9 +60,10 @@ func ResourceReplicationGroup() *schema.Resource {
ConflictsWith: []string{"user_group_ids"},
},
"auto_minor_version_upgrade": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Type: nullable.TypeNullableBool,
Optional: true,
Default: "true",
ValidateFunc: nullable.ValidateTypeStringNullableBool,
},
"automatic_failover_enabled": {
Type: schema.TypeBool,
Expand Down Expand Up @@ -407,8 +409,7 @@ func resourceReplicationGroupCreate(d *schema.ResourceData, meta interface{}) er
tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{})))

params := &elasticache.CreateReplicationGroupInput{
ReplicationGroupId: aws.String(d.Get("replication_group_id").(string)),
AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
ReplicationGroupId: aws.String(d.Get("replication_group_id").(string)),
}

if len(tags) > 0 {
Expand Down Expand Up @@ -443,6 +444,12 @@ func resourceReplicationGroupCreate(d *schema.ResourceData, meta interface{}) er
params.EngineVersion = aws.String(v.(string))
}

if v, ok := d.GetOk("auto_minor_version_upgrade"); ok {
if v, null, _ := nullable.Bool(v.(string)).Value(); !null {
params.AutoMinorVersionUpgrade = aws.Bool(v)
}
}

if preferredAZs, ok := d.GetOk("preferred_cache_cluster_azs"); ok {
params.PreferredCacheClusterAZs = flex.ExpandStringList(preferredAZs.([]interface{}))
}
Expand Down Expand Up @@ -670,6 +677,21 @@ func resourceReplicationGroupRead(d *schema.ResourceData, meta interface{}) erro
d.Set("arn", rgp.ARN)
d.Set("data_tiering_enabled", aws.StringValue(rgp.DataTiering) == elasticache.DataTieringStatusEnabled)

d.Set("log_delivery_configuration", flattenLogDeliveryConfigurations(rgp.LogDeliveryConfigurations))
d.Set("snapshot_window", rgp.SnapshotWindow)
d.Set("snapshot_retention_limit", rgp.SnapshotRetentionLimit)

if rgp.ConfigurationEndpoint != nil {
d.Set("port", rgp.ConfigurationEndpoint.Port)
d.Set("configuration_endpoint_address", rgp.ConfigurationEndpoint.Address)
} else {
d.Set("port", rgp.NodeGroups[0].PrimaryEndpoint.Port)
d.Set("primary_endpoint_address", rgp.NodeGroups[0].PrimaryEndpoint.Address)
d.Set("reader_endpoint_address", rgp.NodeGroups[0].ReaderEndpoint.Address)
}

d.Set("user_group_ids", rgp.UserGroupIds)

// Tags cannot be read when the replication group is not Available
_, err = WaitReplicationGroupAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate))
if err != nil {
Expand Down Expand Up @@ -700,12 +722,9 @@ func resourceReplicationGroupRead(d *schema.ResourceData, meta interface{}) erro
}
}

if rgp.NodeGroups != nil {
if len(rgp.NodeGroups[0].NodeGroupMembers) == 0 {
return nil
}

cacheCluster := *rgp.NodeGroups[0].NodeGroupMembers[0] // nosemgrep: prefer-aws-go-sdk-pointer-conversion-assignment // false positive
// This section reads settings that require checking the underlying cache clusters
if rgp.NodeGroups != nil && len(rgp.NodeGroups[0].NodeGroupMembers) != 0 {
cacheCluster := rgp.NodeGroups[0].NodeGroupMembers[0]

res, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
CacheClusterId: cacheCluster.CacheClusterId,
Expand All @@ -725,23 +744,7 @@ func resourceReplicationGroupRead(d *schema.ResourceData, meta interface{}) erro
return err
}

d.Set("log_delivery_configuration", flattenLogDeliveryConfigurations(rgp.LogDeliveryConfigurations))
d.Set("snapshot_window", rgp.SnapshotWindow)
d.Set("snapshot_retention_limit", rgp.SnapshotRetentionLimit)

if rgp.ConfigurationEndpoint != nil {
d.Set("port", rgp.ConfigurationEndpoint.Port)
d.Set("configuration_endpoint_address", rgp.ConfigurationEndpoint.Address)
} else {
d.Set("port", rgp.NodeGroups[0].PrimaryEndpoint.Port)
d.Set("primary_endpoint_address", rgp.NodeGroups[0].PrimaryEndpoint.Address)
d.Set("reader_endpoint_address", rgp.NodeGroups[0].ReaderEndpoint.Address)
}

d.Set("user_group_ids", rgp.UserGroupIds)

d.Set("at_rest_encryption_enabled", c.AtRestEncryptionEnabled)
d.Set("auto_minor_version_upgrade", c.AutoMinorVersionUpgrade)
d.Set("transit_encryption_enabled", c.TransitEncryptionEnabled)

if c.AuthTokenEnabled != nil && !aws.BoolValue(c.AuthTokenEnabled) {
Expand Down Expand Up @@ -800,7 +803,10 @@ func resourceReplicationGroupUpdate(d *schema.ResourceData, meta interface{}) er
}

if d.HasChange("auto_minor_version_upgrade") {
params.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool))
v := d.Get("auto_minor_version_upgrade")
if v, null, _ := nullable.Bool(v.(string)).Value(); !null {
params.AutoMinorVersionUpgrade = aws.Bool(v)
}
requestUpdate = true
}

Expand Down
Loading

0 comments on commit b599209

Please sign in to comment.