diff --git a/.gitignore b/.gitignore index 41859c8..467c8e5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ # Module directory .terraform/ +.idea +terraform-aws-dynamodb-autoscaler.iml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..241026e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +addons: + apt: + packages: + - git + - make + - curl + +install: + - make init + +script: + - make terraform/install + - make terraform/get-plugins + - make terraform/get-modules + - make terraform/lint + - make terraform/validate diff --git a/LICENSE b/LICENSE index 261eeb9..772b28e 100644 --- a/LICENSE +++ b/LICENSE @@ -178,7 +178,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 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018 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/Makefile b/Makefile new file mode 100644 index 0000000..d002c7d --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +SHELL := /bin/bash + +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +lint: + $(SELF) terraform/install terraform/get-modules terraform/get-plugins terraform/lint terraform/validate diff --git a/README.md b/README.md index 5c0b40d..fb62d8f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,128 @@ -# terraform-aws-dynamodb-autoscaler -Terraform module to provision DynamoDB autoscaler +# terraform-aws-dynamodb-autoscaler [![Build Status](https://travis-ci.org/cloudposse/terraform-aws-dynamodb-autoscaler.svg?branch=master)](https://travis-ci.org/cloudposse/terraform-aws-dynamodb-autoscaler) + +Terraform module to provision DynamoDB autoscaler. + +Autoscaler scales up/down the provisioned OPS for a DynamoDB table based on the load. + + +## Usage + +```hcl +module "dynamodb_autoscaler" { + source = "git::https://github.com/cloudposse/terraform-aws-dynamodb-autoscaler.git?ref=master" + namespace = "cp" + stage = "dev" + name = "cluster" + dynamodb_table_name = "cp-dev-cluster-terraform-state-lock" + dynamodb_table_arn = "arn:aws:dynamodb:us-east-1:123456789012:table/cp-dev-cluster-terraform-state-lock" + autoscale_write_target = 10 + autoscale_read_target = 10 + autoscale_min_read_capacity = 5 + autoscale_max_read_capacity = 20 + autoscale_min_write_capacity = 5 + autoscale_max_write_capacity = 20 +} +``` + + +## Variables + +| Name | Default | Description | Required | +|:---------------------------------|:-------------|:--------------------------------------------------------------------------------|:--------:| +| `namespace` | `` | Namespace (_e.g._ `cp` or `cloudposse`) | Yes | +| `stage` | `` | Stage (_e.g._ `prod`, `dev`, `staging`) | Yes | +| `name` | `` | Name (_e.g._ `app` or `cluster`) | Yes | +| `dynamodb_table_name` | `` | DynamoDB table name | Yes | +| `dynamodb_table_arn` | `` | DynamoDB table ARN | Yes | +| `attributes` | `[]` | Additional attributes (_e.g._ `policy` or `role`) | No | +| `tags` | `{}` | Additional tags (_e.g._ `map("BusinessUnit","XYZ")` | No | +| `delimiter` | `-` | Delimiter to be used between `namespace`, `stage`, `name`, and `attributes` | No | +| `autoscale_write_target` | `10` | The target value for DynamoDB write autoscaling | No | +| `autoscale_read_target` | `10` | The target value for DynamoDB read autoscaling | No | +| `autoscale_min_read_capacity` | `5` | DynamoDB autoscaling min read capacity | No | +| `autoscale_max_read_capacity` | `20` | DynamoDB autoscaling max read capacity | No | +| `autoscale_min_write_capacity` | `5` | DynamoDB autoscaling min write capacity | No | +| `autoscale_max_write_capacity` | `20` | DynamoDB autoscaling max write capacity | No | + + + +## Help + +**Got a question?** + +File a GitHub [issue](https://github.com/cloudposse/terraform-aws-dynamodb-autoscaler/issues), send us an [email](mailto:hello@cloudposse.com) or reach out to us on [Gitter](https://gitter.im/cloudposse/). + + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/cloudposse/terraform-aws-dynamodb-autoscaler/issues) to report any bugs or file feature requests. + +### Developing + +If you are interested in being a contributor and want to get involved in developing `terraform-aws-dynamodb-autoscaler`, we would love to hear from you! Shoot us an [email](mailto:hello@cloudposse.com). + +In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Commit** changes to your own branch + 4. **Push** your work back up to your fork + 5. Submit a **Pull request** so that we can review your changes + +**NOTE:** Be sure to merge the latest from "upstream" before making a pull request! + + +## License + +[APACHE 2.0](LICENSE) © 2017-2018 [Cloud Posse, LLC](https://cloudposse.com) + +See [LICENSE](LICENSE) for full details. + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + + +## About + +`terraform-aws-dynamodb-autoscaler` is maintained and funded by [Cloud Posse, LLC][website]. + +![Cloud Posse](https://cloudposse.com/logo-300x69.png) + + +Like it? Please let us know at + +We love [Open Source Software](https://github.com/cloudposse/)! + +See [our other projects][community] +or [hire us][hire] to help build your next cloud-platform. + + [website]: http://cloudposse.com/ + [community]: https://github.com/cloudposse/ + [hire]: http://cloudposse.com/contact/ + +### Contributors + + +| [![Erik Osterman][erik_img]][erik_web]
[Erik Osterman][erik_web] | [![Andriy Knysh][andriy_img]][andriy_web]
[Andriy Knysh][andriy_web] | +|-------------------------------------------------------|------------------------------------------------------------------| + + [erik_img]: http://s.gravatar.com/avatar/88c480d4f73b813904e00a5695a454cb?s=144 + [erik_web]: https://github.com/osterman/ + [andriy_img]: https://avatars0.githubusercontent.com/u/7356997?v=4&u=ed9ce1c9151d552d985bdf5546772e14ef7ab617&s=144 + [andriy_web]: https://github.com/aknysh/ diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..bb406c6 --- /dev/null +++ b/main.tf @@ -0,0 +1,122 @@ +module "default_label" { + source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.3.3" + namespace = "${var.namespace}" + stage = "${var.stage}" + name = "${var.name}" + delimiter = "${var.delimiter}" + attributes = "${var.attributes}" + tags = "${var.tags}" +} + +data "aws_iam_policy_document" "assume_role" { + statement { + sid = "" + + actions = [ + "sts:AssumeRole", + ] + + principals { + type = "Service" + identifiers = ["application-autoscaling.amazonaws.com"] + } + + effect = "Allow" + } +} + +resource "aws_iam_role" "autoscaler" { + name = "${module.default_label.id}${var.delimiter}autoscaler" + assume_role_policy = "${data.aws_iam_policy_document.assume_role.json}" +} + +data "aws_iam_policy_document" "autoscaler" { + statement { + sid = "" + + actions = [ + "dynamodb:DescribeTable", + "dynamodb:UpdateTable", + ] + + resources = ["${var.dynamodb_table_arn}"] + + effect = "Allow" + } +} + +resource "aws_iam_role_policy" "autoscaler" { + name = "${module.default_label.id}${var.delimiter}autoscaler${var.delimiter}dynamodb" + role = "${aws_iam_role.autoscaler.id}" + policy = "${data.aws_iam_policy_document.autoscaler.json}" +} + +data "aws_iam_policy_document" "autoscaler_cloudwatch" { + statement { + sid = "" + + actions = [ + "cloudwatch:PutMetricAlarm", + "cloudwatch:DescribeAlarms", + "cloudwatch:DeleteAlarms", + ] + + resources = ["*"] + + effect = "Allow" + } +} + +resource "aws_iam_role_policy" "autoscaler_cloudwatch" { + name = "${module.default_label.id}${var.delimiter}autoscaler${var.delimiter}cloudwatch" + role = "${aws_iam_role.autoscaler.id}" + policy = "${data.aws_iam_policy_document.autoscaler_cloudwatch.json}" +} + +resource "aws_appautoscaling_target" "read_target" { + max_capacity = "${var.autoscale_max_read_capacity}" + min_capacity = "${var.autoscale_min_read_capacity}" + resource_id = "table/${var.dynamodb_table_name}" + scalable_dimension = "dynamodb:table:ReadCapacityUnits" + service_namespace = "dynamodb" +} + +resource "aws_appautoscaling_policy" "read_policy" { + name = "DynamoDBReadCapacityUtilization:${aws_appautoscaling_target.read_target.resource_id}" + policy_type = "TargetTrackingScaling" + resource_id = "${aws_appautoscaling_target.read_target.resource_id}" + scalable_dimension = "${aws_appautoscaling_target.read_target.scalable_dimension}" + service_namespace = "${aws_appautoscaling_target.read_target.service_namespace}" + + target_tracking_scaling_policy_configuration { + predefined_metric_specification { + predefined_metric_type = "DynamoDBReadCapacityUtilization" + } + + target_value = "${var.autoscale_read_target}" + } +} + +resource "aws_appautoscaling_target" "write_target" { + max_capacity = "${var.autoscale_max_write_capacity}" + min_capacity = "${var.autoscale_min_write_capacity}" + resource_id = "table/${var.dynamodb_table_name}" + scalable_dimension = "dynamodb:table:WriteCapacityUnits" + service_namespace = "dynamodb" +} + +resource "aws_appautoscaling_policy" "write_policy" { + name = "DynamoDBWriteCapacityUtilization:${aws_appautoscaling_target.write_target.resource_id}" + policy_type = "TargetTrackingScaling" + resource_id = "${aws_appautoscaling_target.write_target.resource_id}" + scalable_dimension = "${aws_appautoscaling_target.write_target.scalable_dimension}" + service_namespace = "${aws_appautoscaling_target.write_target.service_namespace}" + + target_tracking_scaling_policy_configuration { + predefined_metric_specification { + predefined_metric_type = "DynamoDBWriteCapacityUtilization" + } + + target_value = "${var.autoscale_write_target}" + } +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/outputs.tf @@ -0,0 +1 @@ + diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..e709023 --- /dev/null +++ b/variables.tf @@ -0,0 +1,72 @@ +variable "namespace" { + type = "string" + description = "Namespace (e.g. `cp` or `cloudposse`)" +} + +variable "stage" { + type = "string" + description = "Stage (e.g. `prod`, `dev`, `staging`, `infra`)" +} + +variable "name" { + type = "string" + description = "Name (e.g. `app` or `cluster`)" +} + +variable "delimiter" { + type = "string" + default = "-" + description = "Delimiter to be used between `namespace`, `stage`, `name`, and `attributes`" +} + +variable "attributes" { + type = "list" + default = [] + description = "Additional attributes (e.g. `policy` or `role`)" +} + +variable "tags" { + type = "map" + default = {} + description = "Additional tags (e.g. map('BusinessUnit`,`XYZ`)" +} + +variable "dynamodb_table_name" { + type = "string" + description = "DynamoDB table name" +} + +variable "dynamodb_table_arn" { + type = "string" + description = "DynamoDB table ARN" +} + +variable "autoscale_write_target" { + default = 10 + description = "The target value for DynamoDB write autoscaling" +} + +variable "autoscale_read_target" { + default = 10 + description = "The target value for DynamoDB read autoscaling" +} + +variable "autoscale_min_read_capacity" { + default = 5 + description = "DynamoDB autoscaling min read capacity" +} + +variable "autoscale_max_read_capacity" { + default = 20 + description = "DynamoDB autoscaling max read capacity" +} + +variable "autoscale_min_write_capacity" { + default = 5 + description = "DynamoDB autoscaling min write capacity" +} + +variable "autoscale_max_write_capacity" { + default = 20 + description = "DynamoDB autoscaling max write capacity" +}