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

provider/aws: Add new parameter az_mode and availabiliy_zone(s) in ElastiCache #4631

Merged
merged 2 commits into from
Jan 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions builtin/providers/aws/resource_aws_elasticache_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ func resourceAwsElasticacheCluster() *schema.Resource {
Type: schema.TypeInt,
Computed: true,
},
"availability_zone": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
},
},
Expand Down Expand Up @@ -162,6 +166,30 @@ func resourceAwsElasticacheCluster() *schema.Resource {
},
},

"az_mode": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"availability_zone": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"availability_zones": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: func(v interface{}) int {
return hashcode.String(v.(string))
},
},

"tags": tagsSchema(),

// apply_immediately is used to determine when the update modifications
Expand Down Expand Up @@ -234,6 +262,20 @@ func resourceAwsElasticacheClusterCreate(d *schema.ResourceData, meta interface{
log.Printf("[DEBUG] Restoring Redis cluster from S3 snapshot: %#v", s)
}

if v, ok := d.GetOk("az_mode"); ok {
req.AZMode = aws.String(v.(string))
}

if v, ok := d.GetOk("availability_zone"); ok {
req.PreferredAvailabilityZone = aws.String(v.(string))
}

preferred_azs := d.Get("availability_zones").(*schema.Set).List()
if len(preferred_azs) > 0 {
azs := expandStringList(preferred_azs)
req.PreferredAvailabilityZones = azs
}

resp, err := conn.CreateCacheCluster(req)
if err != nil {
return fmt.Errorf("Error creating Elasticache: %s", err)
Expand Down Expand Up @@ -306,6 +348,7 @@ func resourceAwsElasticacheClusterRead(d *schema.ResourceData, meta interface{})
d.Set("notification_topic_arn", c.NotificationConfiguration.TopicArn)
}
}
d.Set("availability_zone", c.PreferredAvailabilityZone)

if err := setCacheNodeData(d, c); err != nil {
return err
Expand Down Expand Up @@ -398,6 +441,9 @@ func resourceAwsElasticacheClusterUpdate(d *schema.ResourceData, meta interface{
oraw, nraw := d.GetChange("num_cache_nodes")
o := oraw.(int)
n := nraw.(int)
if v, ok := d.GetOk("az_mode"); ok && v.(string) == "cross-az" && n == 1 {
return fmt.Errorf("[WARN] Error updateing Elasticache cluster (%s), error: Cross-AZ mode is not supported in a single cache node.", d.Id())
}
if n < o {
log.Printf("[INFO] Cluster %s is marked for Decreasing cache nodes from %d to %d", d.Id(), o, n)
nodesToRemove := getCacheNodesToRemove(d, o, o-n)
Expand Down Expand Up @@ -454,13 +500,14 @@ func setCacheNodeData(d *schema.ResourceData, c *elasticache.CacheCluster) error
cacheNodeData := make([]map[string]interface{}, 0, len(sortedCacheNodes))

for _, node := range sortedCacheNodes {
if node.CacheNodeId == nil || node.Endpoint == nil || node.Endpoint.Address == nil || node.Endpoint.Port == nil {
if node.CacheNodeId == nil || node.Endpoint == nil || node.Endpoint.Address == nil || node.Endpoint.Port == nil || node.CustomerAvailabilityZone == nil {
return fmt.Errorf("Unexpected nil pointer in: %s", node)
}
cacheNodeData = append(cacheNodeData, map[string]interface{}{
"id": *node.CacheNodeId,
"address": *node.Endpoint.Address,
"port": int(*node.Endpoint.Port),
"id": *node.CacheNodeId,
"address": *node.Endpoint.Address,
"port": int(*node.Endpoint.Port),
"availability_zone": *node.CustomerAvailabilityZone,
})
}

Expand Down
88 changes: 88 additions & 0 deletions builtin/providers/aws/resource_aws_elasticache_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,29 @@ func TestAccAWSElasticacheCluster_vpc(t *testing.T) {
testAccCheckAWSElasticacheSubnetGroupExists("aws_elasticache_subnet_group.bar", &csg),
testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
testAccCheckAWSElasticacheClusterAttributes(&ec),
resource.TestCheckResourceAttr(
"aws_elasticache_cluster.bar", "availability_zone", "us-west-2a"),
),
},
},
})
}

func TestAccAWSElasticacheCluster_multiAZInVpc(t *testing.T) {
var csg elasticache.CacheSubnetGroup
var ec elasticache.CacheCluster
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSElasticacheClusterDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSElasticacheClusterMultiAZInVPCConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSElasticacheSubnetGroupExists("aws_elasticache_subnet_group.bar", &csg),
testAccCheckAWSElasticacheClusterExists("aws_elasticache_cluster.bar", &ec),
resource.TestCheckResourceAttr(
"aws_elasticache_cluster.bar", "availability_zone", "Multiple"),
),
},
},
Expand Down Expand Up @@ -414,9 +437,74 @@ resource "aws_elasticache_cluster" "bar" {
security_group_ids = ["${aws_security_group.bar.id}"]
parameter_group_name = "default.redis2.8"
notification_topic_arn = "${aws_sns_topic.topic_example.arn}"
availability_zone = "us-west-2a"
}

resource "aws_sns_topic" "topic_example" {
name = "tf-ecache-cluster-test"
}
`, genRandInt(), genRandInt(), genRandInt())

var testAccAWSElasticacheClusterMultiAZInVPCConfig = fmt.Sprintf(`
resource "aws_vpc" "foo" {
cidr_block = "192.168.0.0/16"
tags {
Name = "tf-test"
}
}

resource "aws_subnet" "foo" {
vpc_id = "${aws_vpc.foo.id}"
cidr_block = "192.168.0.0/20"
availability_zone = "us-west-2a"
tags {
Name = "tf-test-%03d"
}
}

resource "aws_subnet" "bar" {
vpc_id = "${aws_vpc.foo.id}"
cidr_block = "192.168.16.0/20"
availability_zone = "us-west-2b"
tags {
Name = "tf-test-%03d"
}
}

resource "aws_elasticache_subnet_group" "bar" {
name = "tf-test-cache-subnet-%03d"
description = "tf-test-cache-subnet-group-descr"
subnet_ids = [
"${aws_subnet.foo.id}",
"${aws_subnet.bar.id}"
]
}

resource "aws_security_group" "bar" {
name = "tf-test-security-group-%03d"
description = "tf-test-security-group-descr"
vpc_id = "${aws_vpc.foo.id}"
ingress {
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "aws_elasticache_cluster" "bar" {
cluster_id = "tf-test-%03d"
engine = "memcached"
node_type = "cache.m1.small"
num_cache_nodes = 2
port = 11211
subnet_group_name = "${aws_elasticache_subnet_group.bar.name}"
security_group_ids = ["${aws_security_group.bar.id}"]
parameter_group_name = "default.memcached1.4"
az_mode = "cross-az"
availability_zones = [
"us-west-2a",
"us-west-2b"
]
}
`, genRandInt(), genRandInt(), genRandInt(), genRandInt(), genRandInt())
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ Can only be used for the Redis engine.
SNS topic to send ElastiCache notifications to. Example:
`arn:aws:sns:us-east-1:012345678999:my_sns_topic`

* `az_mode` - (Optional, Memcached only) Specifies whether the nodes in this Memcached node group are created in a single Availability Zone or created across multiple Availability Zones in the cluster's region. Valid values for this parameter are `single-az` or `cross-az`, default is `single-az`. If you want to choose `cross-az`, `num_cache_nodes` must be greater than `1`.

* `availability_zone` - (Optional) The AZ for the cache cluster. If you want to create cache nodes in multi-az, use `availability_zones`.

* `availability_zones` - (Optional, Memcached only) List of AZ in which the cache nodes will be created. If you want to create cache nodes in single-az, use `availability_zone`.

* `tags` - (Optional) A mapping of tags to assign to the resource.

~> **NOTE:** Snapshotting functionality is not compatible with t2 instance types.
Expand All @@ -106,7 +112,7 @@ SNS topic to send ElastiCache notifications to. Example:

The following attributes are exported:

* `cache_nodes` - List of node objects including `id`, `address` and `port`.
* `cache_nodes` - List of node objects including `id`, `address`, `port` and `availability_zone`.
Referenceable e.g. as `${aws_elasticache_cluster.bar.cache_nodes.0.address}`

* `configuration_endpoint` - (Memcached only) The configuration endpoint to allow host discovery
Expand Down