diff --git a/LICENSE b/LICENSE index 6b9d898..a6e3b3e 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017 Cloud Posse, LLC + Copyright 2017-2019 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 7e3b796..7fbcc49 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,50 @@ - + [![README Header][readme_header_img]][readme_header_link] [![Cloud Posse][logo]](https://cpco.io/homepage) # terraform-aws-elasticache-memcached - [![Build Status](https://travis-ci.org/cloudposse/terraform-aws-elasticache-memcached.svg?branch=master)](https://travis-ci.org/cloudposse/terraform-aws-elasticache-memcached) [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-aws-elasticache-memcached.svg)](https://github.com/cloudposse/terraform-aws-elasticache-memcached/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + [![Codefresh Build Status](https://g.codefresh.io/api/badges/pipeline/cloudposse/terraform-modules%2Fterraform-aws-elasticache-memcached?type=cf-1)](https%3A%2F%2Fg.codefresh.io%2Fpublic%2Faccounts%2Fcloudposse%2Fpipelines%2F5e0a73156baea5f1b7de7ce0) [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-aws-elasticache-memcached.svg)](https://github.com/cloudposse/terraform-aws-elasticache-memcached/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) Terraform module to provision an [`ElastiCache`](https://aws.amazon.com/elasticache/) Memcached Cluster @@ -42,11 +81,69 @@ We literally have [*hundreds of terraform modules*][terraform_modules] that are +## Usage + + +**IMPORTANT:** The `master` branch is used in `source` just as an example. In your code, do not pin to `master` because there may be breaking changes between releases. +Instead pin to the release tag (e.g. `?ref=tags/x.y.z`) of one of our [latest releases](https://github.com/cloudposse/terraform-aws-elasticache-memcached/releases). + + +For a complete example, see [examples/complete](examples/complete). + +For automated tests of the complete example using [bats](https://github.com/bats-core/bats-core) and [Terratest](https://github.com/gruntwork-io/terratest) (which tests and deploys the example on AWS), see [test](test). + +```hcl + provider "aws" { + region = var.region + } + + module "vpc" { + source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=tags/0.8.1" + namespace = var.namespace + stage = var.stage + name = var.name + cidr_block = "172.16.0.0/16" + } + + module "subnets" { + source = "git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=tags/0.18.1" + availability_zones = var.availability_zones + namespace = var.namespace + stage = var.stage + name = var.name + vpc_id = module.vpc.vpc_id + igw_id = module.vpc.igw_id + cidr_block = module.vpc.vpc_cidr_block + nat_gateway_enabled = false + nat_instance_enabled = false + } + + module "memcached" { + source = "git::https://github.com/cloudposse/terraform-aws-elasticache-memcached.git?ref=master" + namespace = var.namespace + stage = var.stage + name = var.name + availability_zones = var.availability_zones + vpc_id = module.vpc.vpc_id + allowed_security_groups = [module.vpc.vpc_default_security_group_id] + subnets = module.subnets.private_subnet_ids + cluster_size = var.cluster_size + instance_type = var.instance_type + engine_version = var.engine_version + apply_immediately = true + zone_id = var.zone_id + } +``` +## Examples + +Review the [complete example](examples/simple) to see how to use this module. + + ## Makefile Targets ``` @@ -58,39 +155,49 @@ Available targets: lint Lint terraform code ``` - ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| alarm_actions | Alarm actions | list | `` | no | -| alarm_cpu_threshold_percent | CPU threshold alarm level | string | `75` | no | -| alarm_memory_threshold_bytes | Alarm memory threshold bytes | string | `10000000` | no | -| apply_immediately | Specifies whether any database modifications are applied immediately, or during the next maintenance window | string | `true` | no | -| availability_zones | List of Availability Zones where subnets will be created | list | - | yes | -| cluster_size | Cluster size | string | `1` | no | -| engine_version | Engine version | string | `1.4.33` | no | -| instance_type | Elastic cache instance type | string | `t2.micro` | no | +| alarm_actions | Alarm actions | list(string) | `` | no | +| alarm_cpu_threshold_percent | CPU threshold alarm level | number | `75` | no | +| alarm_memory_threshold_bytes | Alarm memory threshold bytes | number | `10000000` | no | +| allowed_cidr_blocks | List of CIDR blocks that are allowed ingress to the cluster's Security Group created in the module | list(string) | `` | no | +| allowed_security_groups | List of Security Group IDs that are allowed ingress to the cluster's Security Group created in the module | list(string) | `` | no | +| apply_immediately | Specifies whether any database modifications are applied immediately, or during the next maintenance window | bool | `true` | no | +| attributes | Additional attributes (_e.g._ "1") | list(string) | `` | no | +| availability_zones | List of Availability Zones for the cluster | list(string) | - | yes | +| cluster_size | Cluster size | number | `1` | no | +| delimiter | Delimiter between `name`, `namespace`, `stage` and `attributes` | string | `-` | no | +| elasticache_parameter_group_family | ElastiCache parameter group family | string | `memcached1.5` | no | +| elasticache_subnet_group_name | Subnet group name for the ElastiCache instance | string | `` | no | +| enabled | Set to false to prevent the module from creating any resources | bool | `true` | no | +| engine_version | Memcached engine version. For more info, see https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/supported-engine-versions.html | string | `1.5.16` | no | +| existing_security_groups | List of existing Security Group IDs to place the cluster into. Set `use_existing_security_groups` to `true` to enable using `existing_security_groups` as Security Groups for the cluster | list(string) | `` | no | +| instance_type | Elastic cache instance type | string | `cache.t2.micro` | no | | maintenance_window | Maintenance window | string | `wed:03:00-wed:04:00` | no | -| max_item_size | Max item size | string | `10485760` | no | -| name | The Name of the application or solution (e.g. `bastion` or `portal`) | string | - | yes | -| namespace | Namespace (e.g. `cp` or `cloudposse`) | string | - | yes | +| max_item_size | Max item size | number | `10485760` | no | +| name | Name of the application | string | - | yes | +| namespace | Namespace (e.g. `eg` or `cp`) | string | `` | no | | notification_topic_arn | Notification topic arn | string | `` | no | -| security_groups | AWS security group ids | list | - | yes | -| stage | Stage (e.g. `prod`, `dev`, `staging`) | string | - | yes | -| subnets | AWS subnet ids | list | `` | no | +| port | Memcached port | number | `11211` | no | +| stage | Stage (e.g. `prod`, `dev`, `staging`) | string | `` | no | +| subnets | AWS subnet ids | list(string) | `` | no | +| tags | Additional tags (_e.g._ map("BusinessUnit","ABC") | map(string) | `` | no | +| use_existing_security_groups | Flag to enable/disable creation of Security Group in the module. Set to `true` to disable Security Group creation and provide a list of existing security Group IDs in `existing_security_groups` to place the cluster into | bool | `false` | no | | vpc_id | VPC ID | string | `` | no | -| zone_id | Route53 DNS Zone id | string | `` | no | +| zone_id | Route53 DNS Zone ID | string | `` | no | ## Outputs | Name | Description | |------|-------------| -| config_host | Config host | -| hosts | Hosts | -| id | Disambiguated ID | -| port | Port | -| security_group_id | Security group id | +| cluster_address | Cluster address | +| cluster_configuration_endpoint | Cluster configuration endpoint | +| cluster_id | Cluster ID | +| cluster_urls | Cluster URLs | +| hostname | Cluster hostname | +| security_group_id | Security Group ID | @@ -113,34 +220,33 @@ Check out these related projects. ## Help -**Got a question?** +**Got a question?** We got answers. File a GitHub [issue](https://github.com/cloudposse/terraform-aws-elasticache-memcached/issues), send us an [email][email] or join our [Slack Community][slack]. [![README Commercial Support][readme_commercial_support_img]][readme_commercial_support_link] -## Commercial Support - -Work directly with our team of DevOps experts via email, slack, and video conferencing. - -We provide [*commercial support*][commercial_support] for all of our [Open Source][github] projects. As a *Dedicated Support* customer, you have access to our team of subject matter experts at a fraction of the cost of a full-time engineer. +## DevOps Accelerator for Startups -[![E-Mail](https://img.shields.io/badge/email-hello@cloudposse.com-blue.svg)][email] -- **Questions.** We'll use a Shared Slack channel between your team and ours. -- **Troubleshooting.** We'll help you triage why things aren't working. -- **Code Reviews.** We'll review your Pull Requests and provide constructive feedback. -- **Bug Fixes.** We'll rapidly work to fix any bugs in our projects. -- **Build New Terraform Modules.** We'll [develop original modules][module_development] to provision infrastructure. -- **Cloud Architecture.** We'll assist with your cloud strategy and design. -- **Implementation.** We'll provide hands-on support to implement our reference architectures. +We are a [**DevOps Accelerator**][commercial_support]. We'll help you build your cloud infrastructure from the ground up so you can own it. Then we'll show you how to operate it and stick around for as long as you need us. +[![Learn More](https://img.shields.io/badge/learn%20more-success.svg?style=for-the-badge)][commercial_support] +Work directly with our team of DevOps experts via email, slack, and video conferencing. -## Terraform Module Development - -Are you interested in custom Terraform module development? Submit your inquiry using [our form][module_development] today and we'll get back to you ASAP. +We deliver 10x the value for a fraction of the cost of a full-time engineer. Our track record is not even funny. If you want things done right and you need it done FAST, then we're your best bet. +- **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code. +- **Release Engineering.** You'll have end-to-end CI/CD with unlimited staging environments. +- **Site Reliability Engineering.** You'll have total visibility into your apps and microservices. +- **Security Baseline.** You'll have built-in governance with accountability and audit logs for all changes. +- **GitOps.** You'll be able to operate your infrastructure via Pull Requests. +- **Training.** You'll receive hands-on training so your team can operate what we build. +- **Questions.** You'll have a direct line of communication between our teams via a Shared Slack channel. +- **Troubleshooting.** You'll get help to triage when things aren't working. +- **Code Reviews.** You'll receive constructive feedback on Pull Requests. +- **Bug Fixes.** We'll rapidly work with you to fix any bugs in our projects. ## Slack Community @@ -148,7 +254,13 @@ Join our [Open Source Community][slack] on Slack. It's **FREE** for everyone! Ou ## Newsletter -Signup for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. +Sign up for [our newsletter][newsletter] that covers everything on our technology radar. Receive updates on what we're up to on GitHub as well as awesome new projects we discover. + +## Office Hours + +[Join us every Wednesday via Zoom][office_hours] for our weekly "Lunch & Learn" sessions. It's **FREE** for everyone! + +[![zoom](https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png")][office_hours] ## Contributing @@ -173,7 +285,7 @@ In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. ## Copyright -Copyright © 2017-2018 [Cloud Posse, LLC](https://cpco.io/copyright) +Copyright © 2017-2019 [Cloud Posse, LLC](https://cpco.io/copyright) @@ -228,41 +340,41 @@ Check out [our other projects][github], [follow us on twitter][twitter], [apply ### Contributors -| [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | -|---|---| +| [![Igor Rodionov][goruha_avatar]][goruha_homepage]
[Igor Rodionov][goruha_homepage] | [![Andriy Knysh][aknysh_avatar]][aknysh_homepage]
[Andriy Knysh][aknysh_homepage] | [![Erik Osterman][osterman_avatar]][osterman_homepage]
[Erik Osterman][osterman_homepage] | +|---|---|---| [goruha_homepage]: https://github.com/goruha - [goruha_avatar]: https://github.com/goruha.png?size=150 + [goruha_avatar]: https://img.cloudposse.com/150x150/https://github.com/goruha.png [aknysh_homepage]: https://github.com/aknysh - [aknysh_avatar]: https://github.com/aknysh.png?size=150 - - + [aknysh_avatar]: https://img.cloudposse.com/150x150/https://github.com/aknysh.png + [osterman_homepage]: https://github.com/osterman + [osterman_avatar]: https://img.cloudposse.com/150x150/https://github.com/osterman.png [![README Footer][readme_footer_img]][readme_footer_link] [![Beacon][beacon]][website] [logo]: https://cloudposse.com/logo-300x69.svg - [docs]: https://cpco.io/docs - [website]: https://cpco.io/homepage - [github]: https://cpco.io/github - [jobs]: https://cpco.io/jobs - [hire]: https://cpco.io/hire - [slack]: https://cpco.io/slack - [linkedin]: https://cpco.io/linkedin - [twitter]: https://cpco.io/twitter - [testimonial]: https://cpco.io/leave-testimonial - [newsletter]: https://cpco.io/newsletter - [email]: https://cpco.io/email - [commercial_support]: https://cpco.io/commercial-support - [we_love_open_source]: https://cpco.io/we-love-open-source - [module_development]: https://cpco.io/module-development - [terraform_modules]: https://cpco.io/terraform-modules - [readme_header_img]: https://cloudposse.com/readme/header/img?repo=cloudposse/terraform-aws-elasticache-memcached - [readme_header_link]: https://cloudposse.com/readme/header/link?repo=cloudposse/terraform-aws-elasticache-memcached - [readme_footer_img]: https://cloudposse.com/readme/footer/img?repo=cloudposse/terraform-aws-elasticache-memcached - [readme_footer_link]: https://cloudposse.com/readme/footer/link?repo=cloudposse/terraform-aws-elasticache-memcached - [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img?repo=cloudposse/terraform-aws-elasticache-memcached - [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?repo=cloudposse/terraform-aws-elasticache-memcached + [docs]: https://cpco.io/docs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=docs + [website]: https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=website + [github]: https://cpco.io/github?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=github + [jobs]: https://cpco.io/jobs?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=jobs + [hire]: https://cpco.io/hire?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=hire + [slack]: https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=slack + [linkedin]: https://cpco.io/linkedin?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=linkedin + [twitter]: https://cpco.io/twitter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=twitter + [testimonial]: https://cpco.io/leave-testimonial?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=testimonial + [office_hours]: https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=office_hours + [newsletter]: https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=newsletter + [email]: https://cpco.io/email?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=email + [commercial_support]: https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=commercial_support + [we_love_open_source]: https://cpco.io/we-love-open-source?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=we_love_open_source + [terraform_modules]: https://cpco.io/terraform-modules?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=terraform_modules + [readme_header_img]: https://cloudposse.com/readme/header/img + [readme_header_link]: https://cloudposse.com/readme/header/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=readme_header_link + [readme_footer_img]: https://cloudposse.com/readme/footer/img + [readme_footer_link]: https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=readme_footer_link + [readme_commercial_support_img]: https://cloudposse.com/readme/commercial-support/img + [readme_commercial_support_link]: https://cloudposse.com/readme/commercial-support/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-elasticache-memcached&utm_content=readme_commercial_support_link [share_twitter]: https://twitter.com/intent/tweet/?text=terraform-aws-elasticache-memcached&url=https://github.com/cloudposse/terraform-aws-elasticache-memcached [share_linkedin]: https://www.linkedin.com/shareArticle?mini=true&title=terraform-aws-elasticache-memcached&url=https://github.com/cloudposse/terraform-aws-elasticache-memcached [share_reddit]: https://reddit.com/submit/?url=https://github.com/cloudposse/terraform-aws-elasticache-memcached diff --git a/README.yaml b/README.yaml index f6422a2..3c996c8 100644 --- a/README.yaml +++ b/README.yaml @@ -31,9 +31,9 @@ github_repo: cloudposse/terraform-aws-elasticache-memcached # Badges to display badges: - - name: "Build Status" - image: "https://travis-ci.org/cloudposse/terraform-aws-elasticache-memcached.svg?branch=master" - url: "https://travis-ci.org/cloudposse/terraform-aws-elasticache-memcached" + - name: "Codefresh Build Status" + image: "https://g.codefresh.io/api/badges/pipeline/cloudposse/terraform-modules%2Fterraform-aws-elasticache-memcached?type=cf-1" + url: "https%3A%2F%2Fg.codefresh.io%2Fpublic%2Faccounts%2Fcloudposse%2Fpipelines%2F5e0a73156baea5f1b7de7ce0" - name: "Latest Release" image: "https://img.shields.io/github/release/cloudposse/terraform-aws-elasticache-memcached.svg" url: "https://github.com/cloudposse/terraform-aws-elasticache-memcached/releases/latest" @@ -53,6 +53,59 @@ related: description: |- Terraform module to provision an [`ElastiCache`](https://aws.amazon.com/elasticache/) Memcached Cluster +# How to use this project +usage: |- + + For a complete example, see [examples/complete](examples/complete). + + For automated tests of the complete example using [bats](https://github.com/bats-core/bats-core) and [Terratest](https://github.com/gruntwork-io/terratest) (which tests and deploys the example on AWS), see [test](test). + + ```hcl + provider "aws" { + region = var.region + } + + module "vpc" { + source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=tags/0.8.1" + namespace = var.namespace + stage = var.stage + name = var.name + cidr_block = "172.16.0.0/16" + } + + module "subnets" { + source = "git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=tags/0.18.1" + availability_zones = var.availability_zones + namespace = var.namespace + stage = var.stage + name = var.name + vpc_id = module.vpc.vpc_id + igw_id = module.vpc.igw_id + cidr_block = module.vpc.vpc_cidr_block + nat_gateway_enabled = false + nat_instance_enabled = false + } + + module "memcached" { + source = "git::https://github.com/cloudposse/terraform-aws-elasticache-memcached.git?ref=master" + namespace = var.namespace + stage = var.stage + name = var.name + availability_zones = var.availability_zones + vpc_id = module.vpc.vpc_id + allowed_security_groups = [module.vpc.vpc_default_security_group_id] + subnets = module.subnets.private_subnet_ids + cluster_size = var.cluster_size + instance_type = var.instance_type + engine_version = var.engine_version + apply_immediately = true + zone_id = var.zone_id + } + ``` + +examples: |- + Review the [complete example](examples/simple) to see how to use this module. + include: - "docs/targets.md" - "docs/terraform.md" @@ -62,4 +115,6 @@ contributors: - name: "Igor Rodionov" github: "goruha" - name: "Andriy Knysh" - github: "aknysh" \ No newline at end of file + github: "aknysh" + - name: "Erik Osterman" + github: "osterman" diff --git a/codefresh/test.yml b/codefresh/test.yml new file mode 100644 index 0000000..69fab42 --- /dev/null +++ b/codefresh/test.yml @@ -0,0 +1,77 @@ +version: '1.0' + +stages: + - Prepare + - Test + +steps: + wait: + title: Wait + stage: Prepare + image: codefresh/cli:latest + commands: + - codefresh get builds --pipeline=${{CF_REPO_NAME}} --status running --limit 1000 -o json | jq --arg id ${{CF_BUILD_ID}} -ser 'flatten|.[-1].id==$id' + retry: + maxAttempts: 10 + delay: 20 + exponentialFactor: 1.1 + + main_clone: + title: "Clone repository" + type: git-clone + stage: Prepare + description: "Initialize" + repo: ${{CF_REPO_OWNER}}/${{CF_REPO_NAME}} + git: CF-default + revision: ${{CF_REVISION}} + + clean_init: + title: Prepare build-harness and test-harness + image: ${{TEST_IMAGE}} + stage: Prepare + commands: + - cf_export PATH="/usr/local/terraform/0.12/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + - make init + - git -C build-harness checkout master + - make -C test/ clean init TEST_HARNESS_BRANCH=master + - make -C test/src clean init + - find . -type d -name '.terraform' | xargs rm -rf + - find . -type f -name 'terraform.tfstate*' -exec rm -f {} \; + + test: + type: "parallel" + title: "Run tests" + description: "Run all tests in parallel" + stage: Test + steps: + test_readme_lint: + title: "Test README.md updated" + stage: "Test" + image: ${{TEST_IMAGE}} + description: Test "readme/lint" + commands: + - make readme/lint + + test_module: + title: Test module with bats + image: ${{TEST_IMAGE}} + stage: Test + commands: + - make -C test/ module + + test_examples_complete: + title: Test "examples/complete" with bats + image: ${{TEST_IMAGE}} + stage: Test + commands: + - make -C test/ examples/complete + + test_examples_complete_terratest: + title: Test "examples/complete" with terratest + image: ${{TEST_IMAGE}} + stage: Test + commands: + - unset AWS_PROFILE + - unset AWS_DEFAULT_PROFILE + - unset AWS_MFA_PROFILE + - make -C test/src diff --git a/docs/terraform.md b/docs/terraform.md index cfc33b2..6648278 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -1,34 +1,44 @@ - ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| alarm_actions | Alarm actions | list | `` | no | -| alarm_cpu_threshold_percent | CPU threshold alarm level | string | `75` | no | -| alarm_memory_threshold_bytes | Alarm memory threshold bytes | string | `10000000` | no | -| apply_immediately | Specifies whether any database modifications are applied immediately, or during the next maintenance window | string | `true` | no | -| availability_zones | List of Availability Zones where subnets will be created | list | - | yes | -| cluster_size | Cluster size | string | `1` | no | -| engine_version | Engine version | string | `1.4.33` | no | -| instance_type | Elastic cache instance type | string | `t2.micro` | no | +| alarm_actions | Alarm actions | list(string) | `` | no | +| alarm_cpu_threshold_percent | CPU threshold alarm level | number | `75` | no | +| alarm_memory_threshold_bytes | Alarm memory threshold bytes | number | `10000000` | no | +| allowed_cidr_blocks | List of CIDR blocks that are allowed ingress to the cluster's Security Group created in the module | list(string) | `` | no | +| allowed_security_groups | List of Security Group IDs that are allowed ingress to the cluster's Security Group created in the module | list(string) | `` | no | +| apply_immediately | Specifies whether any database modifications are applied immediately, or during the next maintenance window | bool | `true` | no | +| attributes | Additional attributes (_e.g._ "1") | list(string) | `` | no | +| availability_zones | List of Availability Zones for the cluster | list(string) | - | yes | +| cluster_size | Cluster size | number | `1` | no | +| delimiter | Delimiter between `name`, `namespace`, `stage` and `attributes` | string | `-` | no | +| elasticache_parameter_group_family | ElastiCache parameter group family | string | `memcached1.5` | no | +| elasticache_subnet_group_name | Subnet group name for the ElastiCache instance | string | `` | no | +| enabled | Set to false to prevent the module from creating any resources | bool | `true` | no | +| engine_version | Memcached engine version. For more info, see https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/supported-engine-versions.html | string | `1.5.16` | no | +| existing_security_groups | List of existing Security Group IDs to place the cluster into. Set `use_existing_security_groups` to `true` to enable using `existing_security_groups` as Security Groups for the cluster | list(string) | `` | no | +| instance_type | Elastic cache instance type | string | `cache.t2.micro` | no | | maintenance_window | Maintenance window | string | `wed:03:00-wed:04:00` | no | -| max_item_size | Max item size | string | `10485760` | no | -| name | The Name of the application or solution (e.g. `bastion` or `portal`) | string | - | yes | -| namespace | Namespace (e.g. `cp` or `cloudposse`) | string | - | yes | +| max_item_size | Max item size | number | `10485760` | no | +| name | Name of the application | string | - | yes | +| namespace | Namespace (e.g. `eg` or `cp`) | string | `` | no | | notification_topic_arn | Notification topic arn | string | `` | no | -| security_groups | AWS security group ids | list | - | yes | -| stage | Stage (e.g. `prod`, `dev`, `staging`) | string | - | yes | -| subnets | AWS subnet ids | list | `` | no | +| port | Memcached port | number | `11211` | no | +| stage | Stage (e.g. `prod`, `dev`, `staging`) | string | `` | no | +| subnets | AWS subnet ids | list(string) | `` | no | +| tags | Additional tags (_e.g._ map("BusinessUnit","ABC") | map(string) | `` | no | +| use_existing_security_groups | Flag to enable/disable creation of Security Group in the module. Set to `true` to disable Security Group creation and provide a list of existing security Group IDs in `existing_security_groups` to place the cluster into | bool | `false` | no | | vpc_id | VPC ID | string | `` | no | -| zone_id | Route53 DNS Zone id | string | `` | no | +| zone_id | Route53 DNS Zone ID | string | `` | no | ## Outputs | Name | Description | |------|-------------| -| config_host | Config host | -| hosts | Hosts | -| id | Disambiguated ID | -| port | Port | -| security_group_id | Security group id | +| cluster_address | Cluster address | +| cluster_configuration_endpoint | Cluster configuration endpoint | +| cluster_id | Cluster ID | +| cluster_urls | Cluster URLs | +| hostname | Cluster hostname | +| security_group_id | Security Group ID | diff --git a/examples/complete/fixtures.us-east-2.tfvars b/examples/complete/fixtures.us-east-2.tfvars new file mode 100644 index 0000000..0915f1d --- /dev/null +++ b/examples/complete/fixtures.us-east-2.tfvars @@ -0,0 +1,18 @@ +region = "us-east-2" + +availability_zones = ["us-east-2a", "us-east-2b"] + +namespace = "eg" + +stage = "test" + +name = "memcached-test" + +instance_type = "cache.t2.micro" + +cluster_size = 1 + +# https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/supported-engine-versions.html +engine_version = "1.5.16" + +elasticache_parameter_group_family = "memcached1.5" diff --git a/examples/complete/main.tf b/examples/complete/main.tf new file mode 100644 index 0000000..bf2a2cd --- /dev/null +++ b/examples/complete/main.tf @@ -0,0 +1,40 @@ +provider "aws" { + region = var.region +} + +module "vpc" { + source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=tags/0.8.1" + namespace = var.namespace + stage = var.stage + name = var.name + cidr_block = "172.16.0.0/16" +} + +module "subnets" { + source = "git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=tags/0.18.1" + availability_zones = var.availability_zones + namespace = var.namespace + stage = var.stage + name = var.name + vpc_id = module.vpc.vpc_id + igw_id = module.vpc.igw_id + cidr_block = module.vpc.vpc_cidr_block + nat_gateway_enabled = false + nat_instance_enabled = false +} + +module "memcached" { + source = "../../" + namespace = var.namespace + stage = var.stage + name = var.name + availability_zones = var.availability_zones + vpc_id = module.vpc.vpc_id + allowed_security_groups = [module.vpc.vpc_default_security_group_id] + subnets = module.subnets.private_subnet_ids + cluster_size = var.cluster_size + instance_type = var.instance_type + engine_version = var.engine_version + apply_immediately = true + zone_id = var.zone_id +} diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf new file mode 100644 index 0000000..6407d05 --- /dev/null +++ b/examples/complete/outputs.tf @@ -0,0 +1,44 @@ +output "public_subnet_cidrs" { + value = module.subnets.public_subnet_cidrs + description = "Public subnet CIDRs" +} + +output "private_subnet_cidrs" { + value = module.subnets.private_subnet_cidrs + description = "Private subnet CIDRs" +} + +output "vpc_cidr" { + value = module.vpc.vpc_cidr_block + description = "VPC CIDR" +} + +output "cluster_id" { + value = module.memcached.cluster_id + description = "Cluster ID" +} + +output "security_group_id" { + value = module.memcached.security_group_id + description = "Security Group ID" +} + +output "cluster_address" { + value = module.memcached.cluster_address + description = "Cluster address" +} + +output "cluster_configuration_endpoint" { + value = module.memcached.cluster_configuration_endpoint + description = "Cluster configuration endpoint" +} + +output "hostname" { + value = module.memcached.hostname + description = "Cluster hostname" +} + +output "cluster_urls" { + value = module.memcached.cluster_urls + description = "Cluster URLs" +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf new file mode 100644 index 0000000..ef91316 --- /dev/null +++ b/examples/complete/variables.tf @@ -0,0 +1,170 @@ +variable "enabled" { + type = bool + description = "Set to false to prevent the module from creating any resources" + default = true +} + +variable "region" { + type = string + description = "AWS region" +} + +variable "availability_zones" { + type = list(string) + description = "Availability zone IDs" +} + +variable "namespace" { + type = string + description = "Namespace (e.g. `eg` or `cp`)" + default = "" +} + +variable "stage" { + type = string + description = "Stage (e.g. `prod`, `dev`, `staging`)" + default = "" +} + +variable "name" { + type = string + description = "Name of the application" +} + +variable "delimiter" { + type = string + default = "-" + description = "Delimiter between `name`, `namespace`, `stage` and `attributes`" +} + +variable "attributes" { + type = list(string) + description = "Additional attributes (_e.g._ \"1\")" + default = [] +} + +variable "tags" { + type = map(string) + description = "Additional tags (_e.g._ map(\"BusinessUnit\",\"ABC\")" + default = {} +} + +variable "vpc_id" { + type = string + default = "" + description = "VPC ID" +} + +variable "max_item_size" { + type = number + default = 10485760 + description = "Max item size" +} + +variable "subnets" { + type = list(string) + default = [] + description = "AWS subnet ids" +} + +variable "maintenance_window" { + type = string + default = "wed:03:00-wed:04:00" + description = "Maintenance window" +} + +variable "cluster_size" { + type = number + default = 1 + description = "Cluster size" +} + +variable "instance_type" { + type = string + default = "cache.t2.micro" + description = "Elastic cache instance type" +} + +variable "engine_version" { + type = string + default = "1.5.16" + description = "Memcached engine version. For more info, see https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/supported-engine-versions.html" +} + +variable "notification_topic_arn" { + type = string + default = "" + description = "Notification topic arn" +} + +variable "alarm_cpu_threshold_percent" { + type = number + default = 75 + description = "CPU threshold alarm level" +} + +variable "alarm_memory_threshold_bytes" { + type = number + default = 10000000 # 10MB + description = "Alarm memory threshold bytes" +} + +variable "alarm_actions" { + type = list(string) + default = [] + description = "Alarm actions" +} + +variable "apply_immediately" { + type = bool + default = true + description = "Specifies whether any database modifications are applied immediately, or during the next maintenance window" +} + +variable "zone_id" { + type = string + default = "" + description = "Route53 DNS Zone ID" +} + +variable "port" { + type = number + default = 11211 + description = "Memcached port" +} + +variable "use_existing_security_groups" { + type = bool + description = "Flag to enable/disable creation of Security Group in the module. Set to `true` to disable Security Group creation and provide a list of existing security Group IDs in `existing_security_groups` to place the cluster into" + default = false +} + +variable "existing_security_groups" { + type = list(string) + default = [] + description = "List of existing Security Group IDs to place the cluster into. Set `use_existing_security_groups` to `true` to enable using `existing_security_groups` as Security Groups for the cluster" +} + +variable "allowed_security_groups" { + type = list(string) + default = [] + description = "List of Security Group IDs that are allowed ingress to the cluster's Security Group created in the module" +} + +variable "allowed_cidr_blocks" { + type = list(string) + default = [] + description = "List of CIDR blocks that are allowed ingress to the cluster's Security Group created in the module" +} + +variable "elasticache_subnet_group_name" { + type = string + description = "Subnet group name for the ElastiCache instance" + default = "" +} + +variable "elasticache_parameter_group_family" { + type = string + description = "ElastiCache parameter group family" + default = "memcached1.5" +} diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf new file mode 100644 index 0000000..4c7776f --- /dev/null +++ b/examples/complete/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_version = "~> 0.12.0" + + required_providers { + aws = "~> 2.0" + null = "~> 2.0" + } +} diff --git a/main.tf b/main.tf index 4319094..4b566fd 100644 --- a/main.tf +++ b/main.tf @@ -1,16 +1,23 @@ -# Define composite variables for resources module "label" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.2.1" - namespace = "${var.namespace}" - name = "${var.name}" - stage = "${var.stage}" + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.16.0" + enabled = var.enabled + namespace = var.namespace + name = var.name + stage = var.stage + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags } -resource "null_resource" "host" { - count = "${var.cluster_size}" +resource "null_resource" "cluster_urls" { + count = var.enabled ? var.cluster_size : 0 triggers = { - name = "${replace(aws_elasticache_cluster.default.cluster_address, ".cfg.", format(".%04d.", count.index + 1))}:11211" + name = "${replace( + join("", aws_elasticache_cluster.default.*.cluster_address), + ".cfg.", + format(".%04d.", count.index + 1) + )}:${var.port}" } lifecycle { @@ -21,121 +28,139 @@ resource "null_resource" "host" { # # Security Group Resources # + resource "aws_security_group" "default" { - vpc_id = "${var.vpc_id}" - name = "${module.label.id}" - - ingress { - from_port = "11211" # Memcache - to_port = "11211" - protocol = "tcp" - security_groups = ["${var.security_groups}"] - } + count = var.enabled && var.use_existing_security_groups == false ? 1 : 0 + vpc_id = var.vpc_id + name = module.label.id + tags = module.label.tags +} - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } +resource "aws_security_group_rule" "egress" { + count = var.enabled && var.use_existing_security_groups == false ? 1 : 0 + description = "Allow all egress traffic" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = join("", aws_security_group.default.*.id) + type = "egress" +} - tags = "${module.label.tags}" +resource "aws_security_group_rule" "ingress_security_groups" { + count = var.enabled && var.use_existing_security_groups == false ? length(var.allowed_security_groups) : 0 + description = "Allow inbound traffic from existing Security Groups" + from_port = var.port + to_port = var.port + protocol = "tcp" + source_security_group_id = var.allowed_security_groups[count.index] + security_group_id = join("", aws_security_group.default.*.id) + type = "ingress" } +resource "aws_security_group_rule" "ingress_cidr_blocks" { + count = var.enabled && var.use_existing_security_groups == false && length(var.allowed_cidr_blocks) > 0 ? 1 : 0 + description = "Allow inbound traffic from CIDR blocks" + from_port = var.port + to_port = var.port + protocol = "tcp" + cidr_blocks = var.allowed_cidr_blocks + security_group_id = join("", aws_security_group.default.*.id) + type = "ingress" +} + +# +# ElastiCache Resources +# resource "aws_elasticache_subnet_group" "default" { - name = "${module.label.id}" - subnet_ids = ["${var.subnets}"] + count = var.enabled ? 1 : 0 + name = module.label.id + subnet_ids = var.subnets } resource "aws_elasticache_parameter_group" "default" { - name = "${module.label.id}" - family = "memcached1.4" + count = var.enabled ? 1 : 0 + name = module.label.id + family = var.elasticache_parameter_group_family parameter { name = "max_item_size" - value = "${var.max_item_size}" + value = var.max_item_size } } -# -# ElastiCache Resources -# +locals { + elasticache_subnet_group_name = var.elasticache_subnet_group_name != "" ? var.elasticache_subnet_group_name : join("", aws_elasticache_subnet_group.default.*.name) +} + resource "aws_elasticache_cluster" "default" { - cluster_id = "${module.label.id}" + count = var.enabled ? 1 : 0 + cluster_id = module.label.id engine = "memcached" - engine_version = "${var.engine_version}" - node_type = "${var.instance_type}" - num_cache_nodes = "${var.cluster_size}" - parameter_group_name = "${aws_elasticache_parameter_group.default.name}" - 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}" - port = "11211" - az_mode = "${var.cluster_size == 1 ? "single-az" : "cross-az" }" - preferred_availability_zones = ["${slice(var.availability_zones, 0, var.cluster_size)}"] - tags = "${module.label.tags}" + engine_version = var.engine_version + node_type = var.instance_type + num_cache_nodes = var.cluster_size + parameter_group_name = join("", aws_elasticache_parameter_group.default.*.name) + subnet_group_name = local.elasticache_subnet_group_name + security_group_ids = var.use_existing_security_groups ? var.existing_security_groups : [join("", aws_security_group.default.*.id)] + maintenance_window = var.maintenance_window + notification_topic_arn = var.notification_topic_arn + port = var.port + az_mode = var.cluster_size == 1 ? "single-az" : "cross-az" + preferred_availability_zones = slice(var.availability_zones, 0, var.cluster_size) + tags = module.label.tags } # # CloudWatch Resources # resource "aws_cloudwatch_metric_alarm" "cache_cpu" { + count = var.enabled ? 1 : 0 alarm_name = "${module.label.id}-cpu-utilization" alarm_description = "Memcached cluster CPU utilization" comparison_operator = "GreaterThanThreshold" - evaluation_periods = "1" + evaluation_periods = 1 metric_name = "CPUUtilization" namespace = "AWS/ElastiCache" - period = "300" + period = 300 statistic = "Average" - threshold = "${var.alarm_cpu_threshold_percent}" + threshold = var.alarm_cpu_threshold_percent - dimensions { - CacheClusterId = "${module.label.id}" + dimensions = { + CacheClusterId = module.label.id } - alarm_actions = ["${var.alarm_actions}"] - depends_on = ["aws_elasticache_cluster.default"] + alarm_actions = var.alarm_actions + depends_on = [aws_elasticache_cluster.default] } resource "aws_cloudwatch_metric_alarm" "cache_memory" { + count = var.enabled ? 1 : 0 alarm_name = "${module.label.id}-freeable-memory" alarm_description = "Memcached cluster freeable memory" comparison_operator = "LessThanThreshold" - evaluation_periods = "1" + evaluation_periods = 1 metric_name = "FreeableMemory" namespace = "AWS/ElastiCache" - period = "60" + period = 60 statistic = "Average" - threshold = "${var.alarm_memory_threshold_bytes}" + threshold = var.alarm_memory_threshold_bytes - dimensions { - CacheClusterId = "${module.label.id}" + dimensions = { + CacheClusterId = module.label.id } - alarm_actions = ["${var.alarm_actions}"] - depends_on = ["aws_elasticache_cluster.default"] + alarm_actions = var.alarm_actions + depends_on = [aws_elasticache_cluster.default] } module "dns" { - source = "git::https://github.com/cloudposse/terraform-aws-route53-cluster-hostname.git?ref=tags/0.1.1" - namespace = "${var.namespace}" - name = "${var.name}" - stage = "${var.stage}" - ttl = 60 - zone_id = "${var.zone_id}" - records = ["${aws_elasticache_cluster.default.cluster_address}"] -} - -module "dns_config" { - source = "git::https://github.com/cloudposse/terraform-aws-route53-cluster-hostname.git?ref=tags/0.1.1" - namespace = "${var.namespace}" - name = "config.${var.name}" - stage = "${var.stage}" - ttl = 60 - zone_id = "${var.zone_id}" - records = ["${aws_elasticache_cluster.default.configuration_endpoint}"] + source = "git::https://github.com/cloudposse/terraform-aws-route53-cluster-hostname.git?ref=tags/0.3.0" + enabled = var.enabled && var.zone_id != "" ? true : false + name = var.name + ttl = 60 + zone_id = var.zone_id + records = [join("", aws_elasticache_cluster.default.*.cluster_address)] } diff --git a/output.tf b/output.tf deleted file mode 100644 index e2e8dc0..0000000 --- a/output.tf +++ /dev/null @@ -1,24 +0,0 @@ -output "id" { - value = "${aws_elasticache_cluster.default.id}" - description = "Disambiguated ID" -} - -output "security_group_id" { - value = "${aws_security_group.default.id}" - description = "Security group id" -} - -output "port" { - value = "11211" - description = "Port" -} - -output "config_host" { - value = "${module.dns_config.hostname}" - description = "Config host" -} - -output "hosts" { - value = "${join(",", null_resource.host.*.triggers.name)}" - description = "Hosts" -} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..6f25611 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,29 @@ +output "cluster_id" { + value = join("", aws_elasticache_cluster.default.*.id) + description = "Cluster ID" +} + +output "security_group_id" { + value = join("", aws_security_group.default.*.id) + description = "Security Group ID" +} + +output "cluster_address" { + value = join("", aws_elasticache_cluster.default.*.cluster_address) + description = "Cluster address" +} + +output "cluster_configuration_endpoint" { + value = join("", aws_elasticache_cluster.default.*.configuration_endpoint) + description = "Cluster configuration endpoint" +} + +output "hostname" { + value = module.dns.hostname + description = "Cluster hostname" +} + +output "cluster_urls" { + value = null_resource.cluster_urls.*.triggers.name + description = "Cluster URLs" +} diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..442804a --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +.test-harness diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..17b2fe7 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,43 @@ +TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git +TEST_HARNESS_BRANCH ?= master +TEST_HARNESS_PATH = $(realpath .test-harness) +BATS_ARGS ?= --tap +BATS_LOG ?= test.log + +# Define a macro to run the tests +define RUN_TESTS +@echo "Running tests in $(1)" +@cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) +endef + +default: all + +-include Makefile.* + +## Provision the test-harnesss +.test-harness: + [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ + +## Initialize the tests +init: .test-harness + +## Install all dependencies (OS specific) +deps:: + @exit 0 + +## Clean up the test harness +clean: + [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) + +## Run all tests +all: module examples/complete + +## Run basic sanity checks against the module itself +module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions +module: deps + $(call RUN_TESTS, ../) + +## Run tests against example +examples/complete: export TESTS ?= installed lint get-modules get-plugins validate +examples/complete: deps + $(call RUN_TESTS, ../$@) diff --git a/test/Makefile.alpine b/test/Makefile.alpine new file mode 100644 index 0000000..7925b18 --- /dev/null +++ b/test/Makefile.alpine @@ -0,0 +1,5 @@ +ifneq (,$(wildcard /sbin/apk)) +## Install all dependencies for alpine +deps:: init + @apk add --update terraform-docs@cloudposse json2hcl@cloudposse +endif diff --git a/test/src/.gitignore b/test/src/.gitignore new file mode 100644 index 0000000..31b0219 --- /dev/null +++ b/test/src/.gitignore @@ -0,0 +1,2 @@ +.gopath +vendor/ diff --git a/test/src/Gopkg.lock b/test/src/Gopkg.lock new file mode 100644 index 0000000..87bb6bd --- /dev/null +++ b/test/src/Gopkg.lock @@ -0,0 +1,92 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "UT" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + digest = "1:75d6042fc66aebc974cc49b0c6c7cc3b9adb5f8130fbfa0dbec0820d990afa25" + name = "github.com/gruntwork-io/terratest" + packages = [ + "modules/collections", + "modules/customerrors", + "modules/files", + "modules/logger", + "modules/retry", + "modules/shell", + "modules/ssh", + "modules/terraform", + ] + pruneopts = "UT" + revision = "892abb2c35878d0808101bbfe6559e931dc2d354" + version = "v0.16.0" + +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + digest = "1:5da8ce674952566deae4dbc23d07c85caafc6cfa815b0b3e03e41979cedb8750" + name = "github.com/stretchr/testify" + packages = [ + "assert", + "require", + ] + pruneopts = "UT" + revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" + version = "v1.3.0" + +[[projects]] + branch = "master" + digest = "1:831470c2758c8b733941144f2803a0ccad0632c5a767415b777ebd296b5f463e" + name = "golang.org/x/crypto" + packages = [ + "curve25519", + "ed25519", + "ed25519/internal/edwards25519", + "internal/chacha20", + "internal/subtle", + "poly1305", + "ssh", + "ssh/agent", + ] + pruneopts = "UT" + revision = "22d7a77e9e5f409e934ed268692e56707cd169e5" + +[[projects]] + branch = "master" + digest = "1:76ee51c3f468493aff39dbacc401e8831fbb765104cbf613b89bef01cf4bad70" + name = "golang.org/x/net" + packages = ["context"] + pruneopts = "UT" + revision = "f3200d17e092c607f615320ecaad13d87ad9a2b3" + +[[projects]] + branch = "master" + digest = "1:181f3fd33e620b958b5ab77da177cf775cdcccd7db82963607875fbd09ae995e" + name = "golang.org/x/sys" + packages = [ + "cpu", + "unix", + ] + pruneopts = "UT" + revision = "9cd6430ef91e39e1a0ec0470cf1321a33ef1b887" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/gruntwork-io/terratest/modules/terraform", + "github.com/stretchr/testify/assert", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/test/src/Gopkg.toml b/test/src/Gopkg.toml new file mode 100644 index 0000000..995bac5 --- /dev/null +++ b/test/src/Gopkg.toml @@ -0,0 +1,7 @@ +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.2" + +[prune] + go-tests = true + unused-packages = true diff --git a/test/src/Makefile b/test/src/Makefile new file mode 100644 index 0000000..72a838a --- /dev/null +++ b/test/src/Makefile @@ -0,0 +1,50 @@ +PACKAGE = terraform-aws-elasticache-memcached +GOEXE ?= /usr/bin/go +GOPATH = $(CURDIR)/.gopath +GOBIN = $(GOPATH)/bin +BASE = $(GOPATH)/src/$(PACKAGE) +PATH := $(PATH):$(GOBIN) + +export TF_DATA_DIR ?= $(CURDIR)/.terraform +export TF_CLI_ARGS_init ?= -get-plugins=true +export GOPATH + +.PHONY: all +## Default target +all: test + +ifneq (,$(wildcard /sbin/apk)) +## Install go, if not installed +$(GOEXE): + apk add --update go +endif + +ifeq ($(shell uname -s),Linux) +## Install all `dep`, if not installed +$(GOBIN)/dep: + @mkdir -p $(GOBIN) + @curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh +endif + +## Prepare the GOPATH +$(BASE): $(GOEXE) + @mkdir -p $(dir $@) + @ln -sf $(CURDIR) $@ + +## Download vendor dependencies to vendor/ +$(BASE)/vendor: $(BASE) $(GOBIN)/dep + cd $(BASE) && dep ensure + +.PHONY : init +## Initialize tests +init: $(BASE)/vendor + +.PHONY : test +## Run tests +test: init + cd $(BASE) && go test -v -timeout 30m -run TestExamplesComplete + +.PHONY : clean +## Clean up files +clean: + rm -rf .gopath/ vendor/ $(TF_DATA_DIR) diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go new file mode 100644 index 0000000..1eb8c9f --- /dev/null +++ b/test/src/examples_complete_test.go @@ -0,0 +1,47 @@ +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/stretchr/testify/assert" +) + +// Test the Terraform module in examples/complete using Terratest. +func TestExamplesComplete(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/complete", + Upgrade: true, + // Variables to pass to our Terraform code using -var-file options + VarFiles: []string{"fixtures.us-east-2.tfvars"}, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + // Run `terraform output` to get the value of an output variable + vpcCidr := terraform.Output(t, terraformOptions, "vpc_cidr") + // Verify we're getting back the outputs we expect + assert.Equal(t, "172.16.0.0/16", vpcCidr) + + // Run `terraform output` to get the value of an output variable + privateSubnetCidrs := terraform.OutputList(t, terraformOptions, "private_subnet_cidrs") + // Verify we're getting back the outputs we expect + assert.Equal(t, []string{"172.16.0.0/19", "172.16.32.0/19"}, privateSubnetCidrs) + + // Run `terraform output` to get the value of an output variable + publicSubnetCidrs := terraform.OutputList(t, terraformOptions, "public_subnet_cidrs") + // Verify we're getting back the outputs we expect + assert.Equal(t, []string{"172.16.96.0/19", "172.16.128.0/19"}, publicSubnetCidrs) + + // Run `terraform output` to get the value of an output variable + clusterId := terraform.Output(t, terraformOptions, "cluster_id") + // Verify we're getting back the outputs we expect + assert.Equal(t, "eg-test-memcached-test", clusterId) +} diff --git a/variables.tf b/variables.tf index 62bc277..340989d 100644 --- a/variables.tf +++ b/variables.tf @@ -1,89 +1,165 @@ -variable "name" { - description = "The Name of the application or solution (e.g. `bastion` or `portal`)" +variable "enabled" { + type = bool + description = "Set to false to prevent the module from creating any resources" + default = true } variable "namespace" { - description = "Namespace (e.g. `cp` or `cloudposse`)" + type = string + description = "Namespace (e.g. `eg` or `cp`)" + default = "" } variable "stage" { + type = string description = "Stage (e.g. `prod`, `dev`, `staging`)" + default = "" +} + +variable "name" { + type = string + description = "Name of the application" } -variable "security_groups" { - type = "list" - description = "AWS security group ids" +variable "delimiter" { + type = string + default = "-" + description = "Delimiter between `name`, `namespace`, `stage` and `attributes`" +} + +variable "attributes" { + type = list(string) + description = "Additional attributes (_e.g._ \"1\")" + default = [] +} + +variable "tags" { + type = map(string) + description = "Additional tags (_e.g._ map(\"BusinessUnit\",\"ABC\")" + default = {} } variable "vpc_id" { + type = string default = "" description = "VPC ID" } variable "max_item_size" { - default = "10485760" + type = number + default = 10485760 description = "Max item size" } variable "subnets" { - type = "list" + type = list(string) default = [] description = "AWS subnet ids" } variable "maintenance_window" { + type = string default = "wed:03:00-wed:04:00" description = "Maintenance window" } variable "cluster_size" { - default = "1" + type = number + default = 1 description = "Cluster size" } variable "instance_type" { - default = "t2.micro" + type = string + default = "cache.t2.micro" description = "Elastic cache instance type" } variable "engine_version" { - default = "1.4.33" - description = "Engine version" + type = string + default = "1.5.16" + description = "Memcached engine version. For more info, see https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/supported-engine-versions.html" } variable "notification_topic_arn" { + type = string default = "" description = "Notification topic arn" } variable "alarm_cpu_threshold_percent" { - default = "75" + type = number + default = 75 description = "CPU threshold alarm level" } variable "alarm_memory_threshold_bytes" { - # 10MB - default = "10000000" + type = number + default = 10000000 # 10MB description = "Alarm memory threshold bytes" } variable "alarm_actions" { - type = "list" + type = list(string) default = [] description = "Alarm actions" } variable "apply_immediately" { - default = "true" + type = bool + default = true description = "Specifies whether any database modifications are applied immediately, or during the next maintenance window" } variable "availability_zones" { - type = "list" - description = "List of Availability Zones where subnets will be created" + type = list(string) + description = "List of Availability Zones for the cluster" } variable "zone_id" { + type = string default = "" - description = "Route53 DNS Zone id" + description = "Route53 DNS Zone ID" +} + +variable "port" { + type = number + default = 11211 + description = "Memcached port" +} + +variable "use_existing_security_groups" { + type = bool + description = "Flag to enable/disable creation of Security Group in the module. Set to `true` to disable Security Group creation and provide a list of existing security Group IDs in `existing_security_groups` to place the cluster into" + default = false +} + +variable "existing_security_groups" { + type = list(string) + default = [] + description = "List of existing Security Group IDs to place the cluster into. Set `use_existing_security_groups` to `true` to enable using `existing_security_groups` as Security Groups for the cluster" +} + +variable "allowed_security_groups" { + type = list(string) + default = [] + description = "List of Security Group IDs that are allowed ingress to the cluster's Security Group created in the module" +} + +variable "allowed_cidr_blocks" { + type = list(string) + default = [] + description = "List of CIDR blocks that are allowed ingress to the cluster's Security Group created in the module" +} + +variable "elasticache_subnet_group_name" { + type = string + description = "Subnet group name for the ElastiCache instance" + default = "" +} + +variable "elasticache_parameter_group_family" { + type = string + description = "ElastiCache parameter group family" + default = "memcached1.5" } diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..4c7776f --- /dev/null +++ b/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_version = "~> 0.12.0" + + required_providers { + aws = "~> 2.0" + null = "~> 2.0" + } +}