From 8d99de1b1b82f62d98d2512c8225c74779fedd7a Mon Sep 17 00:00:00 2001 From: Nuru Date: Thu, 10 Dec 2020 20:40:23 -0800 Subject: [PATCH] Terraform 0.14 upgrade (#28) --- .github/CODEOWNERS | 12 +- .github/auto-release.yml | 45 ++++++ .github/mergify.yml | 52 +++++++ .github/workflows/auto-context.yml | 55 +++++++ .github/workflows/auto-readme.yml | 41 ++++++ .github/workflows/auto-release.yml | 19 +++ .github/workflows/chatops.yml | 8 +- .github/workflows/validate-codeowners.yml | 18 +++ README.md | 36 +++-- README.yaml | 4 +- context.tf | 169 ++++++++++++++++++++++ docs/terraform.md | 21 +-- examples/complete/context.tf | 169 ++++++++++++++++++++++ examples/complete/main.tf | 14 +- examples/complete/outputs.tf | 10 -- examples/complete/variables.tf | 33 ----- main.tf | 97 +------------ outputs.tf | 10 -- test/src/examples_complete_test.go | 5 - variables.tf | 48 ------ versions.tf | 12 +- 21 files changed, 645 insertions(+), 233 deletions(-) create mode 100644 .github/auto-release.yml create mode 100644 .github/mergify.yml create mode 100644 .github/workflows/auto-context.yml create mode 100644 .github/workflows/auto-readme.yml create mode 100644 .github/workflows/auto-release.yml create mode 100644 .github/workflows/validate-codeowners.yml create mode 100644 context.tf create mode 100644 examples/complete/context.tf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bed3c96..ceb4644 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,7 +1,7 @@ # Use this file to define individuals or teams that are responsible for code in a repository. # Read more: # -# Order is important: the last matching pattern takes the most precedence +# Order is important: the last matching pattern has the highest precedence # These owners will be the default owners for everything * @cloudposse/engineering @cloudposse/contributors @@ -12,3 +12,13 @@ # Cloud Posse must review any changes to GitHub actions .github/* @cloudposse/engineering + +# Cloud Posse must review any changes to standard context definition, +# but some changes can be rubber-stamped. +**/context.tf @cloudposse/engineering @cloudposse/approvers +README.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers +docs/*.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers + +# Cloud Posse Admins must review all changes to CODEOWNERS or the mergify configuration +.github/mergify.yml @cloudposse/admins +.github/CODEOWNERS @cloudposse/admins diff --git a/.github/auto-release.yml b/.github/auto-release.yml new file mode 100644 index 0000000..18a1ca6 --- /dev/null +++ b/.github/auto-release.yml @@ -0,0 +1,45 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: '$RESOLVED_VERSION' +version-template: '$MAJOR.$MINOR.$PATCH' +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + - 'enhancement' + patch: + labels: + - 'auto-update' + - 'patch' + - 'fix' + - 'bugfix' + - 'bug' + - 'hotfix' + default: 'minor' + +categories: +- title: '🚀 Enhancements' + labels: + - 'enhancement' + - 'patch' +- title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - 'hotfix' +- title: '🤖 Automatic Updates' + labels: + - 'auto-update' + +change-template: | +
+ $TITLE @$AUTHOR (#$NUMBER) + + $BODY +
+ +template: | + $CHANGES diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 0000000..485982f --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,52 @@ +pull_request_rules: +- name: "approve automated PRs that have passed checks" + conditions: + - "check-success~=test/bats" + - "check-success~=test/readme" + - "check-success~=test/terratest" + - "base=master" + - "author=cloudpossebot" + - "head~=auto-update/.*" + actions: + review: + type: "APPROVE" + bot_account: "cloudposse-mergebot" + message: "We've automatically approved this PR because the checks from the automated Pull Request have passed." + +- name: "merge automated PRs when approved and tests pass" + conditions: + - "check-success~=test/bats" + - "check-success~=test/readme" + - "check-success~=test/terratest" + - "base=master" + - "head~=auto-update/.*" + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + - "#commented-reviews-by=0" + - "base=master" + - "author=cloudpossebot" + actions: + merge: + method: "squash" + +- name: "delete the head branch after merge" + conditions: + - "merged" + actions: + delete_head_branch: {} + +- name: "ask to resolve conflict" + conditions: + - "conflict" + actions: + comment: + message: "This pull request is now in conflict. Could you fix it @{{author}}? 🙏" + +- name: "remove outdated reviews" + conditions: + - "base=master" + actions: + dismiss_reviews: + changes_requested: true + approved: true + message: "This Pull Request has been updated, so we're dismissing all reviews." diff --git a/.github/workflows/auto-context.yml b/.github/workflows/auto-context.yml new file mode 100644 index 0000000..739a3c9 --- /dev/null +++ b/.github/workflows/auto-context.yml @@ -0,0 +1,55 @@ +name: "auto-context" +on: + schedule: + # Update context.tf nightly + - cron: '0 3 * * *' + +jobs: + update: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Update context.tf + shell: bash + id: update + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + if [[ -f context.tf ]]; then + echo "Discovered existing context.tf! Fetching most recent version to see if there is an update." + curl -o context.tf -fsSL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf + if git diff --no-patch --exit-code context.tf; then + echo "No changes detected! Exiting the job..." + else + echo "context.tf file has changed. Update examples and rebuild README.md." + make init + make github/init/context.tf + make readme/build + echo "::set-output name=create_pull_request=true" + fi + else + echo "This module has not yet been updated to support the context.tf pattern! Please update in order to support automatic updates." + fi + + - name: Create Pull Request + if: {{ steps.update.outputs.create_pull_request == 'true' }} + uses: cloudposse/actions/github/create-pull-request@0.22.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + commit-message: Update context.tf from origin source + title: Update context.tf + body: |- + ## what + This is an auto-generated PR that updates the `context.tf` file to the latest version from `cloudposse/terraform-null-label` + + ## why + To support all the features of the `context` interface. + + branch: auto-update/context.tf + base: master + delete-branch: true + labels: | + auto-update + context diff --git a/.github/workflows/auto-readme.yml b/.github/workflows/auto-readme.yml new file mode 100644 index 0000000..6229e60 --- /dev/null +++ b/.github/workflows/auto-readme.yml @@ -0,0 +1,41 @@ +name: "auto-readme" +on: + schedule: + # Update README.md nightly + - cron: '0 4 * * *' + +jobs: + update: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Update readme + shell: bash + id: update + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + make init + make readme/build + + - name: Create Pull Request + uses: cloudposse/actions/github/create-pull-request@0.20.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + commit-message: Update README.md and docs + title: Update README.md and docs + body: |- + ## what + This is an auto-generated PR that updates the README.md and docs + + ## why + To have most recent changes of README.md and doc from origin templates + + branch: auto-update/readme + base: master + delete-branch: true + labels: | + auto-update + readme diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..ccc27be --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,19 @@ +name: auto-release + +on: + push: + branches: + - master + +jobs: + semver: + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + with: + publish: true + prerelease: false + config-name: auto-release.yml + env: + GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} diff --git a/.github/workflows/chatops.yml b/.github/workflows/chatops.yml index 31523a8..4ddc067 100644 --- a/.github/workflows/chatops.yml +++ b/.github/workflows/chatops.yml @@ -9,13 +9,13 @@ jobs: steps: - uses: actions/checkout@v2 - name: "Handle common commands" - uses: cloudposse/actions/github/slash-command-dispatch@0.16.0 + uses: cloudposse/actions/github/slash-command-dispatch@0.22.0 with: token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} reaction-token: ${{ secrets.GITHUB_TOKEN }} repository: cloudposse/actions commands: rebuild-readme, terraform-fmt - permission: none + permission: triage issue-type: pull-request test: @@ -24,13 +24,13 @@ jobs: - name: "Checkout commit" uses: actions/checkout@v2 - name: "Run tests" - uses: cloudposse/actions/github/slash-command-dispatch@0.16.0 + uses: cloudposse/actions/github/slash-command-dispatch@0.22.0 with: token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} reaction-token: ${{ secrets.GITHUB_TOKEN }} repository: cloudposse/actions commands: test - permission: none + permission: triage issue-type: pull-request reactions: false diff --git a/.github/workflows/validate-codeowners.yml b/.github/workflows/validate-codeowners.yml new file mode 100644 index 0000000..8044289 --- /dev/null +++ b/.github/workflows/validate-codeowners.yml @@ -0,0 +1,18 @@ +name: Validate Codeowners +on: + pull_request: + +jobs: + validate-codeowners: + runs-on: ubuntu-latest + steps: + - name: "Checkout source code at current commit" + uses: actions/checkout@v2 + - uses: mszostok/codeowners-validator@v0.5.0 + with: + # For now, remove "files" check to allow CODEOWNERS to specify non-existent + # files so we can use the same CODEOWNERS file for Terraform and non-Terraform repos + # checks: "files,syntax,owners,duppatterns" + checks: "syntax,owners,duppatterns" + # GitHub access token is required only if the `owners` check is enabled + github_access_token: "${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}" diff --git a/README.md b/README.md index 9225061..bee099a 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,22 @@ 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-dynamodb-autoscaler/releases). +**IMPORTANT:** We do not pin modules to versions in our examples because of the +difficulty of keeping the versions in the documentation in sync with the latest released versions. +We highly recommend that in your code you pin the version to the exact version you are +using so that your infrastructure remains stable, and update versions in a +systematic way so that they do not catch you by surprise. + +Also, because of a bug in the Terraform registry ([hashicorp/terraform#21417](https://github.com/hashicorp/terraform/issues/21417)), +the registry shows many of our inputs as required when in fact they are optional. +The table below correctly indicates which inputs are required. ```hcl module "dynamodb_autoscaler" { - source = "git::https://github.com/cloudposse/terraform-aws-dynamodb-autoscaler.git?ref=master" + source = "cloudposse/dynamodb-autoscaler/aws" + # Cloud Posse recommends pinning every module to a specific version + # version = "x.x.x" namespace = "eg" stage = "dev" name = "cluster" @@ -110,7 +119,7 @@ Available targets: | Name | Version | |------|---------| -| terraform | >= 0.12.0 | +| terraform | >= 0.12.26 | | aws | >= 2.0 | | null | >= 2.0 | @@ -124,6 +133,7 @@ Available targets: | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | | attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | | autoscale\_max\_read\_capacity | DynamoDB autoscaling max read capacity | `number` | `20` | no | | autoscale\_max\_write\_capacity | DynamoDB autoscaling max write capacity | `number` | `20` | no | @@ -131,15 +141,19 @@ Available targets: | autoscale\_min\_write\_capacity | DynamoDB autoscaling min write capacity | `number` | `5` | no | | autoscale\_read\_target | The target value for DynamoDB read autoscaling | `number` | `50` | no | | autoscale\_write\_target | The target value for DynamoDB write autoscaling | `number` | `50` | no | -| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes` | `string` | `"-"` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. |
object({
enabled = bool
namespace = string
environment = string
stage = string
name = string
delimiter = string
attributes = list(string)
tags = map(string)
additional_tag_map = map(string)
regex_replace_chars = string
label_order = list(string)
id_length_limit = number
})
|
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_order": [],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | dynamodb\_indexes | List of DynamoDB indexes | `list(string)` | `[]` | no | | dynamodb\_table\_arn | DynamoDB table ARN | `string` | n/a | yes | | dynamodb\_table\_name | DynamoDB table name | `string` | n/a | yes | -| enabled | Set to false to prevent the module from creating any resources | `bool` | `true` | no | -| environment | Environment, e.g. 'prod', 'staging', 'dev', 'pre-prod', 'UAT' | `string` | `""` | no | -| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `""` | no | -| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `""` | no | -| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `""` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters.
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | ## Outputs @@ -150,8 +164,6 @@ Available targets: | appautoscaling\_read\_target\_index\_id | Appautoscaling read target index ID | | appautoscaling\_write\_target\_id | Appautoscaling write target ID | | appautoscaling\_write\_target\_index\_id | Appautoscaling write target index ID | -| autoscaler\_iam\_role\_arn | Autoscaler IAM Role ARN | -| autoscaler\_iam\_role\_id | Autoscaler IAM Role ID | diff --git a/README.yaml b/README.yaml index ecad28a..b7e13a3 100644 --- a/README.yaml +++ b/README.yaml @@ -51,7 +51,9 @@ description: |- usage: |- ```hcl module "dynamodb_autoscaler" { - source = "git::https://github.com/cloudposse/terraform-aws-dynamodb-autoscaler.git?ref=master" + source = "cloudposse/dynamodb-autoscaler/aws" + # Cloud Posse recommends pinning every module to a specific version + # version = "x.x.x" namespace = "eg" stage = "dev" name = "cluster" diff --git a/context.tf b/context.tf new file mode 100644 index 0000000..e5734b7 --- /dev/null +++ b/context.tf @@ -0,0 +1,169 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + + +module "this" { + source = "cloudposse/label/null" + version = "0.22.0" // requires Terraform >= 0.12.26 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/docs/terraform.md b/docs/terraform.md index 7ca2046..f8da72a 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -3,7 +3,7 @@ | Name | Version | |------|---------| -| terraform | >= 0.12.0 | +| terraform | >= 0.12.26 | | aws | >= 2.0 | | null | >= 2.0 | @@ -17,6 +17,7 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| additional\_tag\_map | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no | | attributes | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no | | autoscale\_max\_read\_capacity | DynamoDB autoscaling max read capacity | `number` | `20` | no | | autoscale\_max\_write\_capacity | DynamoDB autoscaling max write capacity | `number` | `20` | no | @@ -24,15 +25,19 @@ | autoscale\_min\_write\_capacity | DynamoDB autoscaling min write capacity | `number` | `5` | no | | autoscale\_read\_target | The target value for DynamoDB read autoscaling | `number` | `50` | no | | autoscale\_write\_target | The target value for DynamoDB write autoscaling | `number` | `50` | no | -| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes` | `string` | `"-"` | no | +| context | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. |
object({
enabled = bool
namespace = string
environment = string
stage = string
name = string
delimiter = string
attributes = list(string)
tags = map(string)
additional_tag_map = map(string)
regex_replace_chars = string
label_order = list(string)
id_length_limit = number
})
|
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_order": [],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {}
}
| no | +| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | dynamodb\_indexes | List of DynamoDB indexes | `list(string)` | `[]` | no | | dynamodb\_table\_arn | DynamoDB table ARN | `string` | n/a | yes | | dynamodb\_table\_name | DynamoDB table name | `string` | n/a | yes | -| enabled | Set to false to prevent the module from creating any resources | `bool` | `true` | no | -| environment | Environment, e.g. 'prod', 'staging', 'dev', 'pre-prod', 'UAT' | `string` | `""` | no | -| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `""` | no | -| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `""` | no | -| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `""` | no | +| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| id\_length\_limit | Limit `id` to this many characters.
Set to `0` for unlimited length.
Set to `null` for default, which is `0`.
Does not affect `id_full`. | `number` | `null` | no | +| label\_order | The naming order of the id output and Name tag.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | +| name | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no | +| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no | +| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no | ## Outputs @@ -43,7 +48,5 @@ | appautoscaling\_read\_target\_index\_id | Appautoscaling read target index ID | | appautoscaling\_write\_target\_id | Appautoscaling write target ID | | appautoscaling\_write\_target\_index\_id | Appautoscaling write target index ID | -| autoscaler\_iam\_role\_arn | Autoscaler IAM Role ARN | -| autoscaler\_iam\_role\_id | Autoscaler IAM Role ID | diff --git a/examples/complete/context.tf b/examples/complete/context.tf new file mode 100644 index 0000000..e5734b7 --- /dev/null +++ b/examples/complete/context.tf @@ -0,0 +1,169 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + + +module "this" { + source = "cloudposse/label/null" + version = "0.22.0" // requires Terraform >= 0.12.26 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = object({ + enabled = bool + namespace = string + environment = string + stage = string + name = string + delimiter = string + attributes = list(string) + tags = map(string) + additional_tag_map = map(string) + regex_replace_chars = string + label_order = list(string) + id_length_limit = number + }) + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters. + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT +} + +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 5e753ec..a611a43 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -3,7 +3,8 @@ provider "aws" { } module "dynamodb_table" { - source = "git::https://github.com/cloudposse/terraform-aws-dynamodb.git?ref=tags/0.17.1" + source = "cloudposse/dynamodb/aws" + version = "0.17.1" namespace = var.namespace environment = var.environment stage = var.stage @@ -66,13 +67,8 @@ module "dynamodb_table" { } module "dynamodb_autoscaler" { - source = "../../" - namespace = var.namespace - environment = var.environment - stage = var.stage - name = var.name - attributes = var.attributes - tags = var.tags + source = "../../" + dynamodb_table_name = module.dynamodb_table.table_name dynamodb_table_arn = module.dynamodb_table.table_arn autoscale_read_target = var.autoscale_read_target @@ -81,4 +77,6 @@ module "dynamodb_autoscaler" { autoscale_write_target = var.autoscale_write_target autoscale_min_write_capacity = var.autoscale_min_write_capacity autoscale_max_write_capacity = var.autoscale_max_write_capacity + + context = module.this.context } diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index bd36c7f..8d13fe2 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -28,16 +28,6 @@ output "table_stream_label" { description = "DynamoDB table stream label" } -output "autoscaler_iam_role_id" { - value = module.dynamodb_autoscaler.autoscaler_iam_role_id - description = "Autoscaler IAM Role ID" -} - -output "autoscaler_iam_role_arn" { - value = module.dynamodb_autoscaler.autoscaler_iam_role_arn - description = "Autoscaler IAM Role ARN" -} - output "appautoscaling_read_target_id" { value = module.dynamodb_autoscaler.appautoscaling_read_target_id description = "Appautoscaling read target ID" diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 978f12a..650573d 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -3,39 +3,6 @@ variable "region" { description = "AWS region" } -variable "namespace" { - type = string - description = "Namespace (e.g. `eg` or `cp`)" -} - -variable "environment" { - type = string - default = "" - description = "Environment, e.g. 'prod', 'staging', 'dev', 'pre-prod', 'UAT'" -} - -variable "stage" { - type = string - description = "Stage (e.g. `prod`, `dev`, `staging`, `infra`)" -} - -variable "name" { - type = string - description = "Name (e.g. `app` or `cluster`)" -} - -variable "attributes" { - type = list(string) - default = [] - description = "Additional attributes (e.g. `1`)" -} - -variable "tags" { - type = map(string) - default = {} - description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" -} - variable "autoscale_write_target" { type = number description = "The target value for DynamoDB write autoscaling" diff --git a/main.tf b/main.tf index 4555c87..0ab2823 100644 --- a/main.tf +++ b/main.tf @@ -1,86 +1,5 @@ -module "default_label" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.22.0" - namespace = var.namespace - stage = var.stage - environment = var.environment - name = var.name - delimiter = var.delimiter - attributes = var.attributes - tags = var.tags - enabled = var.enabled -} - -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" { - count = var.enabled ? 1 : 0 - name = "${module.default_label.id}${var.delimiter}autoscaler" - assume_role_policy = data.aws_iam_policy_document.assume_role.json - tags = module.default_label.tags -} - -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" { - count = var.enabled ? 1 : 0 - name = "${module.default_label.id}${var.delimiter}autoscaler${var.delimiter}dynamodb" - role = join("", 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" { - count = var.enabled ? 1 : 0 - name = "${module.default_label.id}${var.delimiter}autoscaler${var.delimiter}cloudwatch" - role = join("", aws_iam_role.autoscaler.*.id) - policy = data.aws_iam_policy_document.autoscaler_cloudwatch.json -} - resource "aws_appautoscaling_target" "read_target" { - count = var.enabled ? 1 : 0 + count = module.this.enabled ? 1 : 0 max_capacity = var.autoscale_max_read_capacity min_capacity = var.autoscale_min_read_capacity resource_id = "table/${var.dynamodb_table_name}" @@ -89,7 +8,7 @@ resource "aws_appautoscaling_target" "read_target" { } resource "aws_appautoscaling_target" "read_target_index" { - count = var.enabled ? length(var.dynamodb_indexes) : 0 + count = module.this.enabled ? length(var.dynamodb_indexes) : 0 max_capacity = var.autoscale_max_read_capacity min_capacity = var.autoscale_min_read_capacity resource_id = "table/${var.dynamodb_table_name}/index/${element(var.dynamodb_indexes, count.index)}" @@ -98,7 +17,7 @@ resource "aws_appautoscaling_target" "read_target_index" { } resource "aws_appautoscaling_policy" "read_policy" { - count = var.enabled ? 1 : 0 + count = module.this.enabled ? 1 : 0 name = "DynamoDBReadCapacityUtilization:${join("", aws_appautoscaling_target.read_target.*.resource_id)}" policy_type = "TargetTrackingScaling" resource_id = join("", aws_appautoscaling_target.read_target.*.resource_id) @@ -116,7 +35,7 @@ resource "aws_appautoscaling_policy" "read_policy" { } resource "aws_appautoscaling_policy" "read_policy_index" { - count = var.enabled ? length(var.dynamodb_indexes) : 0 + count = module.this.enabled ? length(var.dynamodb_indexes) : 0 name = "DynamoDBReadCapacityUtilization:${element( aws_appautoscaling_target.read_target_index.*.resource_id, @@ -138,7 +57,7 @@ resource "aws_appautoscaling_policy" "read_policy_index" { } resource "aws_appautoscaling_target" "write_target" { - count = var.enabled ? 1 : 0 + count = module.this.enabled ? 1 : 0 max_capacity = var.autoscale_max_write_capacity min_capacity = var.autoscale_min_write_capacity resource_id = "table/${var.dynamodb_table_name}" @@ -147,7 +66,7 @@ resource "aws_appautoscaling_target" "write_target" { } resource "aws_appautoscaling_target" "write_target_index" { - count = var.enabled ? length(var.dynamodb_indexes) : 0 + count = module.this.enabled ? length(var.dynamodb_indexes) : 0 max_capacity = var.autoscale_max_write_capacity min_capacity = var.autoscale_min_write_capacity resource_id = "table/${var.dynamodb_table_name}/index/${element(var.dynamodb_indexes, count.index)}" @@ -156,7 +75,7 @@ resource "aws_appautoscaling_target" "write_target_index" { } resource "aws_appautoscaling_policy" "write_policy" { - count = var.enabled ? 1 : 0 + count = module.this.enabled ? 1 : 0 name = "DynamoDBWriteCapacityUtilization:${join("", aws_appautoscaling_target.write_target.*.resource_id)}" policy_type = "TargetTrackingScaling" resource_id = join("", aws_appautoscaling_target.write_target.*.resource_id) @@ -174,7 +93,7 @@ resource "aws_appautoscaling_policy" "write_policy" { } resource "aws_appautoscaling_policy" "write_policy_index" { - count = var.enabled ? length(var.dynamodb_indexes) : 0 + count = module.this.enabled ? length(var.dynamodb_indexes) : 0 name = "DynamoDBWriteCapacityUtilization:${element( aws_appautoscaling_target.write_target_index.*.resource_id, diff --git a/outputs.tf b/outputs.tf index 15903e9..048944c 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,13 +1,3 @@ -output "autoscaler_iam_role_id" { - value = join("", aws_iam_role.autoscaler.*.id) - description = "Autoscaler IAM Role ID" -} - -output "autoscaler_iam_role_arn" { - value = join("", aws_iam_role.autoscaler.*.arn) - description = "Autoscaler IAM Role ARN" -} - output "appautoscaling_read_target_id" { value = join("", aws_appautoscaling_target.read_target.*.id) description = "Appautoscaling read target ID" diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go index b2631b5..77f22ea 100644 --- a/test/src/examples_complete_test.go +++ b/test/src/examples_complete_test.go @@ -55,9 +55,4 @@ func TestExamplesComplete(t *testing.T) { appautoscalingWriteTargetId := terraform.Output(t, terraformOptions, "appautoscaling_write_target_id") // Verify we're getting back the outputs we expect assert.Equal(t, "table/eg-test-dynamodb-autoscaler-"+randId, appautoscalingWriteTargetId) - - // Run `terraform output` to get the value of an output variable - autoscalerIamRoleArn := terraform.Output(t, terraformOptions, "autoscaler_iam_role_arn") - // Verify we're getting back the outputs we expect - assert.Contains(t, autoscalerIamRoleArn, "eg-test-dynamodb-autoscaler-"+randId) } diff --git a/variables.tf b/variables.tf index cabde82..3139de4 100644 --- a/variables.tf +++ b/variables.tf @@ -1,51 +1,3 @@ -variable "namespace" { - type = string - default = "" - description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" -} - -variable "environment" { - type = string - default = "" - description = "Environment, e.g. 'prod', 'staging', 'dev', 'pre-prod', 'UAT'" -} - -variable "stage" { - type = string - default = "" - description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" -} - -variable "name" { - type = string - default = "" - description = "Solution name, e.g. 'app' or 'jenkins'" -} - -variable "enabled" { - type = bool - default = true - description = "Set to false to prevent the module from creating any resources" -} - -variable "delimiter" { - type = string - default = "-" - description = "Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`" -} - -variable "attributes" { - type = list(string) - default = [] - description = "Additional attributes (e.g. `1`)" -} - -variable "tags" { - type = map(string) - default = {} - description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" -} - variable "dynamodb_table_name" { type = string description = "DynamoDB table name" diff --git a/versions.tf b/versions.tf index 723d6b1..f34d0d0 100644 --- a/versions.tf +++ b/versions.tf @@ -1,8 +1,14 @@ terraform { - required_version = ">= 0.12.0" + required_version = ">= 0.12.26" required_providers { - aws = ">= 2.0" - null = ">= 2.0" + aws = { + source = "hashicorp/aws" + version = ">= 2.0" + } + null = { + source = "hashicorp/null" + version = ">= 2.0" + } } }