diff --git a/LICENSE b/LICENSE index 8dada3e..5704492 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -178,7 +179,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" + boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2017 Cloud Posse, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 6ae9e4b..fcea99a 100644 --- a/README.md +++ b/README.md @@ -1 +1,66 @@ -# tf_redis \ No newline at end of file +# tf_redis + +Terraform module to provision a ElastiCache Redis Cluster + +## Usage + +Include this repository as a module in your existing terraform code: + +``` +module "example_redis" { + source = "git::https://github.com/cloudposse/tf_redis.git?ref=tags/0.1.0" + namespace = "general" + name = "redis" + stage = "prod" + zone_id = "${var.route52_zone_id}" + security_groups = ["${var.security_group_id}"] + + vpc_id = "${var.vpc_id}" + subnets = "${var.private_subnets}" + maintenance_window = "wed:03:00-wed:04:00" + cluster_size = "2" + instance_type = "cache.t2.micro" + engine_version = "3.2.4" + alarm_cpu_threshold_percent = "${var.cache_alarm_cpu_threshold_percent}" + alarm_memory_threshold_bytes = "${var.cache_alarm_memory_threshold_bytes}" + apply_immediately = "true" + availability_zones = "${var.availability_zones}" + + automatic_failover = "false" +} +``` + +## Input + +| Name | Default | Decription | +|:----------------------------:|:-------------------:|:------------------------------------------------------:| +| namespace |global |Namespace | +| stage |default |Stage | +| name |redis |Name | +| security_groups |[] |AWS security group ids | +| vpc_id |__REQUIRED__ |AWS VPC id | +| subnets | [] | AWS subnet ids | +| cluster_size | 1 | Count of nodes in cluster | +| instance_type | cache.t2.micro | Elastic cache instance type | +| family | redis3.2 | Redis family | +| engine_version | 3.2.4 | Redis engine version | +| port | 6379 | Redis port | +| maintenance_window | wed:03:00-wed:04:00 | Maintenance window | +| notification_topic_arn | | Notificate topic arn | +| alarm_cpu_threshold_percent | 75 | CPU threshold alarm level | +| alarm_memory_threshold_bytes | 10000000 | Ram threshold alarm level | +| alarm_actions | [] | Alarm action list | +| apply_immediately | true | Apply changes immediately | +| automatic_failover | false | Automatic failover (Not available for T1/T2 instances) | +| availability_zones | [] | Availability zone ids | +| zone_id | false | Route53 dns zone id | + +## Output + +| Name | Decription | +|:-----------------:|:-----------------:| +| id | Redis cluster id | +| security_group_id | Security group id | +| host | Redis host | +| port | Redis port | + diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..f0f7d0a --- /dev/null +++ b/main.tf @@ -0,0 +1,115 @@ +# Define composite variables for resources +module "label" { + source = "git::https://github.com/cloudposse/tf_label.git?ref=tags/0.1.0" + namespace = "${var.namespace}" + name = "${var.name}" + stage = "${var.stage}" +} + +# +# Security Group Resources +# +resource "aws_security_group" "default" { + vpc_id = "${var.vpc_id}" + name = "${module.label.id}" + ingress { + from_port = "${var.port}" # Redis + to_port = "${var.port}" + protocol = "tcp" + security_groups = ["${var.security_groups}"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags { + Name = "${module.label.id}" + Namespace = "${var.namespace}" + Stage = "${var.stage}" + } +} + +resource "aws_elasticache_subnet_group" "default" { + name = "${module.label.id}" + subnet_ids = ["${var.subnets}"] +} + +resource "aws_elasticache_parameter_group" "default" { + name = "${module.label.id}" + family = "${var.family}" +} + +resource "aws_elasticache_replication_group" "default" { + replication_group_id = "${module.label.id}" + replication_group_description = "${module.label.id}" + node_type = "${var.instance_type}" + number_cache_clusters = "${var.cluster_size}" + port = "${var.port}" + parameter_group_name = "${aws_elasticache_parameter_group.default.name}" + availability_zones = ["${slice(var.availability_zones, 0, var.cluster_size)}"] + automatic_failover_enabled = "${var.automatic_failover}" + subnet_group_name = "${aws_elasticache_subnet_group.default.name}" + security_group_ids = ["${aws_security_group.default.id}"] + maintenance_window = "${var.maintenance_window}" + notification_topic_arn = "${var.notification_topic_arn}" + + tags = "${module.label.tags}" +} + +# +# CloudWatch Resources +# +resource "aws_cloudwatch_metric_alarm" "cache_cpu" { + alarm_name = "${module.label.id}-cpu-utilization" + alarm_description = "Redis cluster CPU utilization" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = "1" + metric_name = "CPUUtilization" + namespace = "AWS/ElastiCache" + period = "300" + statistic = "Average" + + threshold = "${var.alarm_cpu_threshold_percent}" + + dimensions { + CacheClusterId = "${module.label.id}" + } + + alarm_actions = ["${var.alarm_actions}"] + depends_on = ["aws_elasticache_replication_group.default"] +} + +resource "aws_cloudwatch_metric_alarm" "cache_memory" { + alarm_name = "${module.label.id}-freeable-memory" + alarm_description = "Redis cluster freeable memory" + comparison_operator = "LessThanThreshold" + evaluation_periods = "1" + metric_name = "FreeableMemory" + namespace = "AWS/ElastiCache" + period = "60" + statistic = "Average" + + threshold = "${var.alarm_memory_threshold_bytes}" + + dimensions { + CacheClusterId = "${module.label.id}" + } + + alarm_actions = ["${var.alarm_actions}"] + depends_on = ["aws_elasticache_replication_group.default"] +} + + +module "dns" { + source = "git::https://github.com/cloudposse/tf_hostname.git?ref=tags/0.1.0" + namespace = "${var.namespace}" + name = "${var.name}" + stage = "${var.stage}" + ttl = 60 + zone_id = "${var.zone_id}" + records = ["${aws_elasticache_replication_group.default.primary_endpoint_address}"] +} diff --git a/output.tf b/output.tf new file mode 100644 index 0000000..a0053e7 --- /dev/null +++ b/output.tf @@ -0,0 +1,16 @@ +output "id" { + value = "${aws_elasticache_replication_group.default.id}" +} + +output "security_group_id" { + value = "${aws_security_group.default.id}" +} + +output "port" { + value = "11211" +} + +output "host" { + value = "${module.dns.hostname}" +} + diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..3c29581 --- /dev/null +++ b/variables.tf @@ -0,0 +1,82 @@ +variable "namespace" { + default = "global" +} + +variable "stage" { + default = "default" +} + +variable "name" { + default = "redis" +} + +variable "security_groups" { + type = "list" +} + +variable "vpc_id" { + default = "" +} + +variable "subnets" { + type = "list" + default = [] +} + +variable "maintenance_window" { + default = "wed:03:00-wed:04:00" +} + +variable "cluster_size" { + default = "1" +} + + +variable "port" { + default = "6379" +} + + +variable "instance_type" { + default = "cache.t2.micro" +} + +variable "family" { + default = "redis3.2" +} + +variable "engine_version" { + default = "3.2.4" +} + +variable "notification_topic_arn" { + default = "" +} + +variable "alarm_cpu_threshold_percent" { + default = "75" +} + +variable "alarm_memory_threshold_bytes" { + # 10MB + default = "10000000" +} + +variable "alarm_actions" { + type = "list" + default = [] +} + +variable "apply_immediately" { + default = "true" +} + +variable "automatic_failover" { + default = "false" +} + +variable "availability_zones" { + type = "list" +} + +variable "zone_id" {}