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

resource/aws_elasticache_replication_group: Enable Multi-AZ #17320

Merged
merged 14 commits into from
Jan 28, 2021
Merged
7 changes: 7 additions & 0 deletions .changelog/17320.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
data-source/aws_elasticache_replication_group: Add `multi_az_enabled` argument
```

```release-note:enhancement
resource/aws_elasticache_replication_group: Add `multi_az_enabled` argument
```
19 changes: 19 additions & 0 deletions aws/data_source_aws_elasticache_replication_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package aws

import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elasticache"
Expand Down Expand Up @@ -58,6 +60,10 @@ func dataSourceAwsElasticacheReplicationGroup() *schema.Resource {
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"multi_az_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"node_type": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -88,6 +94,7 @@ func dataSourceAwsElasticacheReplicationGroupRead(d *schema.ResourceData, meta i
d.Set("replication_group_description", rg.Description)
d.Set("arn", rg.ARN)
d.Set("auth_token_enabled", rg.AuthTokenEnabled)

if rg.AutomaticFailover != nil {
switch aws.StringValue(rg.AutomaticFailover) {
case elasticache.AutomaticFailoverStatusDisabled, elasticache.AutomaticFailoverStatusDisabling:
Expand All @@ -96,6 +103,18 @@ func dataSourceAwsElasticacheReplicationGroupRead(d *schema.ResourceData, meta i
d.Set("automatic_failover_enabled", true)
}
}

if rg.MultiAZ != nil {
switch strings.ToLower(aws.StringValue(rg.MultiAZ)) {
case elasticache.MultiAZStatusEnabled:
d.Set("multi_az_enabled", true)
case elasticache.MultiAZStatusDisabled:
d.Set("multi_az_enabled", false)
default:
log.Printf("Unknown MultiAZ state %q", aws.StringValue(rg.MultiAZ))
}
}

if rg.ConfigurationEndpoint != nil {
d.Set("port", rg.ConfigurationEndpoint.Port)
d.Set("configuration_endpoint_address", rg.ConfigurationEndpoint.Address)
Expand Down
39 changes: 39 additions & 0 deletions aws/data_source_aws_elasticache_replication_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestAccDataSourceAwsElasticacheReplicationGroup_basic(t *testing.T) {
resource.TestCheckResourceAttr(dataSourceName, "auth_token_enabled", "false"),
resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "automatic_failover_enabled", resourceName, "automatic_failover_enabled"),
resource.TestCheckResourceAttrPair(dataSourceName, "multi_az_enabled", resourceName, "multi_az_enabled"),
resource.TestCheckResourceAttrPair(dataSourceName, "member_clusters.#", resourceName, "member_clusters.#"),
resource.TestCheckResourceAttrPair(dataSourceName, "node_type", resourceName, "node_type"),
resource.TestCheckResourceAttrPair(dataSourceName, "number_cache_clusters", resourceName, "number_cache_clusters"),
Expand Down Expand Up @@ -53,6 +54,7 @@ func TestAccDataSourceAwsElasticacheReplicationGroup_ClusterMode(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "auth_token_enabled", "false"),
resource.TestCheckResourceAttrPair(dataSourceName, "automatic_failover_enabled", resourceName, "automatic_failover_enabled"),
resource.TestCheckResourceAttrPair(dataSourceName, "multi_az_enabled", resourceName, "multi_az_enabled"),
resource.TestCheckResourceAttrPair(dataSourceName, "configuration_endpoint_address", resourceName, "configuration_endpoint_address"),
resource.TestCheckResourceAttrPair(dataSourceName, "node_type", resourceName, "node_type"),
resource.TestCheckResourceAttrPair(dataSourceName, "port", resourceName, "port"),
Expand All @@ -64,6 +66,26 @@ func TestAccDataSourceAwsElasticacheReplicationGroup_ClusterMode(t *testing.T) {
})
}

func TestAccDataSourceAwsElasticacheReplicationGroup_MultiAZ(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_elasticache_replication_group.test"
dataSourceName := "data.aws_elasticache_replication_group.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsElasticacheReplicationGroupConfig_MultiAZ(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(dataSourceName, "automatic_failover_enabled", resourceName, "automatic_failover_enabled"),
resource.TestCheckResourceAttrPair(dataSourceName, "multi_az_enabled", resourceName, "multi_az_enabled"),
),
},
},
})
}

func TestAccDataSourceAwsElasticacheReplicationGroup_NonExistent(t *testing.T) {

resource.ParallelTest(t, resource.TestCase{
Expand Down Expand Up @@ -118,6 +140,23 @@ data "aws_elasticache_replication_group" "test" {
`, rName)
}

func testAccDataSourceAwsElasticacheReplicationGroupConfig_MultiAZ(rName string) string {
return fmt.Sprintf(`
resource "aws_elasticache_replication_group" "test" {
replication_group_id = %[1]q
replication_group_description = "test description"
node_type = "cache.t3.small"
number_cache_clusters = 2
automatic_failover_enabled = true
multi_az_enabled = true
}

data "aws_elasticache_replication_group" "test" {
replication_group_id = aws_elasticache_replication_group.test.replication_group_id
}
`, rName)
}

const testAccDataSourceAwsElasticacheReplicationGroupConfig_NonExistent = `
data "aws_elasticache_replication_group" "test" {
replication_group_id = "tf-acc-test-nonexistent"
Expand Down
99 changes: 59 additions & 40 deletions aws/resource_aws_elasticache_replication_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package aws

import (
"context"
"errors"
"fmt"
"log"
"regexp"
Expand Down Expand Up @@ -110,7 +111,7 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource {
Optional: true,
ForceNew: true,
Default: "redis",
ValidateFunc: validateAwsElastiCacheReplicationGroupEngine,
ValidateFunc: validation.StringInSlice([]string{"redis"}, true),
},
"engine_version": {
Type: schema.TypeString,
Expand All @@ -122,8 +123,7 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource {
Optional: true,
Computed: true,
StateFunc: func(val interface{}) string {
// ElastiCache always changes the maintenance
// to lowercase
// Elasticache always changes the maintenance to lowercase
return strings.ToLower(val.(string))
},
ValidateFunc: validateOnceAWeekWindowFormat,
Expand All @@ -134,6 +134,11 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource {
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"multi_az_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"node_type": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -278,6 +283,36 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource {
},

CustomizeDiff: customdiff.Sequence(
func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error {
if v := diff.Get("multi_az_enabled").(bool); !v {
return nil
}
if v := diff.Get("automatic_failover_enabled").(bool); !v {
return errors.New(`automatic_failover_enabled must be true if multi_az_enabled is true`)
}
return nil
},
func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error {
if v := diff.Get("automatic_failover_enabled").(bool); !v {
return nil
}

if v, ok := diff.GetOkExists("number_cache_clusters"); ok {
if v.(int) > 1 {
return nil
}
return errors.New(`if automatic_failover_enabled is true, number_cache_clusters must be greater than 1`)
}

if v, ok := diff.GetOkExists("cluster_mode.0.replicas_per_node_group"); ok {
if v.(int) > 0 {
return nil
}
return errors.New(`if automatic_failover_enabled is true, cluster_mode[0].replicas_per_node_group must be greater than 0`)
}

return nil
},
customdiff.ComputedIf("member_clusters", func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) bool {
return diff.HasChange("number_cache_clusters") || diff.HasChange("cluster_mode.0.num_node_groups")
}),
Expand Down Expand Up @@ -335,6 +370,10 @@ func resourceAwsElasticacheReplicationGroupCreate(d *schema.ResourceData, meta i
params.PreferredMaintenanceWindow = aws.String(v.(string))
}

if _, ok := d.GetOk("multi_az_enabled"); ok {
params.MultiAZEnabled = aws.Bool(d.Get("multi_az_enabled").(bool))
}

if v, ok := d.GetOk("notification_topic_arn"); ok {
params.NotificationTopicArn = aws.String(v.(string))
}
Expand Down Expand Up @@ -426,12 +465,22 @@ func resourceAwsElasticacheReplicationGroupRead(d *schema.ResourceData, meta int
case elasticache.AutomaticFailoverStatusEnabled, elasticache.AutomaticFailoverStatusEnabling:
d.Set("automatic_failover_enabled", true)
default:
log.Printf("Unknown AutomaticFailover state %s", aws.StringValue(rgp.AutomaticFailover))
log.Printf("Unknown AutomaticFailover state %q", aws.StringValue(rgp.AutomaticFailover))
}
}

d.Set("kms_key_id", rgp.KmsKeyId)
if rgp.MultiAZ != nil {
switch strings.ToLower(aws.StringValue(rgp.MultiAZ)) {
case elasticache.MultiAZStatusEnabled:
d.Set("multi_az_enabled", true)
case elasticache.MultiAZStatusDisabled:
d.Set("multi_az_enabled", false)
default:
log.Printf("Unknown MultiAZ state %q", aws.StringValue(rgp.MultiAZ))
}
}

d.Set("kms_key_id", rgp.KmsKeyId)
d.Set("replication_group_description", rgp.Description)
d.Set("number_cache_clusters", len(rgp.MemberClusters))
if err := d.Set("member_clusters", flattenStringSet(rgp.MemberClusters)); err != nil {
Expand Down Expand Up @@ -573,6 +622,11 @@ func resourceAwsElasticacheReplicationGroupUpdate(d *schema.ResourceData, meta i
requestUpdate = true
}

if d.HasChange("multi_az_enabled") {
params.MultiAZEnabled = aws.Bool(d.Get("multi_az_enabled").(bool))
requestUpdate = true
}

if d.HasChange("notification_topic_arn") {
params.NotificationTopicArn = aws.String(d.Get("notification_topic_arn").(string))
requestUpdate = true
Expand Down Expand Up @@ -706,13 +760,6 @@ func flattenElasticacheNodeGroupsToClusterMode(nodeGroups []*elasticache.NodeGro
return []map[string]interface{}{m}
}

func validateAwsElastiCacheReplicationGroupEngine(v interface{}, k string) (ws []string, errors []error) {
if strings.ToLower(v.(string)) != "redis" {
errors = append(errors, fmt.Errorf("The only acceptable Engine type when using Replication Groups is Redis"))
}
return
}

func elasticacheReplicationGroupModifyShardConfiguration(conn *elasticache.ElastiCache, d *schema.ResourceData) error {
o, n := d.GetChange("cluster_mode.0.num_node_groups")
oldNumNodeGroups := o.(int)
Expand Down Expand Up @@ -801,30 +848,6 @@ func elasticacheReplicationGroupDecreaseNumCacheClusters(conn *elasticache.Elast
return nil
}

func resourceAwsElasticacheReplicationGroupDisableAutomaticFailover(conn *elasticache.ElastiCache, replicationGroupID string, timeout time.Duration) error {
return resourceAwsElasticacheReplicationGroupModify(conn, timeout, &elasticache.ModifyReplicationGroupInput{
ReplicationGroupId: aws.String(replicationGroupID),
ApplyImmediately: aws.Bool(true),
AutomaticFailoverEnabled: aws.Bool(false),
})
}

func resourceAwsElasticacheReplicationGroupEnableAutomaticFailover(conn *elasticache.ElastiCache, replicationGroupID string, timeout time.Duration) error {
return resourceAwsElasticacheReplicationGroupModify(conn, timeout, &elasticache.ModifyReplicationGroupInput{
ReplicationGroupId: aws.String(replicationGroupID),
ApplyImmediately: aws.Bool(true),
AutomaticFailoverEnabled: aws.Bool(true),
})
}

func resourceAwsElasticacheReplicationGroupSetPrimaryClusterID(conn *elasticache.ElastiCache, replicationGroupID, primaryClusterID string, timeout time.Duration) error {
return resourceAwsElasticacheReplicationGroupModify(conn, timeout, &elasticache.ModifyReplicationGroupInput{
ReplicationGroupId: aws.String(replicationGroupID),
ApplyImmediately: aws.Bool(true),
PrimaryClusterId: aws.String(primaryClusterID),
})
}

func resourceAwsElasticacheReplicationGroupModify(conn *elasticache.ElastiCache, timeout time.Duration, input *elasticache.ModifyReplicationGroupInput) error {
_, err := conn.ModifyReplicationGroup(input)
if err != nil {
Expand All @@ -837,7 +860,3 @@ func resourceAwsElasticacheReplicationGroupModify(conn *elasticache.ElastiCache,
}
return nil
}

func formatReplicationGroupClusterID(replicationGroupID string, clusterID int) string {
return fmt.Sprintf("%s-%03d", replicationGroupID, clusterID)
}
Loading