diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 241026e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -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 c37833f..eb114f2 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 Cloud Posse, LLC + Copyright 2018-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 6b46098..6780da1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Cloud Posse][logo]](https://cpco.io/homepage) -# terraform-terraform-label [![Build Status](https://travis-ci.org/cloudposse/terraform-terraform-label.svg?branch=master)](https://travis-ci.org/cloudposse/terraform-terraform-label) [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-terraform-label.svg)](https://github.com/cloudposse/terraform-terraform-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) +# terraform-terraform-label [![Codefresh Build Status](https://g.codefresh.io/api/badges/pipeline/cloudposse/cloudposse%2Fterraform-null-label%2Ftest?type=cf-1)](https://g.codefresh.io/public/accounts/cloudposse/pipelines/cloudposse/terraform-null-label/test) [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-terraform-label.svg)](https://github.com/cloudposse/terraform-terraform-label/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) Terraform module designed to generate consistent label names and tags for resources. Use `terraform-terraform-label` to implement a strict naming convention. @@ -15,7 +15,7 @@ A label follows the following convention: `{namespace}-{stage}-{name}-{attribute It's recommended to use one `terraform-terraform-label` module for every unique resource of a given resource type. For example, if you have 10 instances, there should be 10 different labels. -However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. +However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic IPs), then they can all share the same label assuming they are logically related. All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. @@ -55,6 +55,11 @@ 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-terraform-label/releases). + + ### Simple Example Include this repository as a module in your existing terraform code: @@ -67,7 +72,11 @@ module "eg_prod_bastion_label" { name = "bastion" attributes = ["public"] delimiter = "-" - tags = "${map("BusinessUnit", "XYZ", "Snapshot", "true")}" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } } ``` @@ -78,7 +87,7 @@ Now reference the label when creating an instance (for example): ```hcl resource "aws_instance" "eg_prod_bastion_public" { instance_type = "t1.micro" - tags = "${module.eg_prod_bastion_label.tags}" + tags = module.eg_prod_bastion_label.tags } ``` @@ -86,9 +95,9 @@ Or define a security group: ```hcl resource "aws_security_group" "eg_prod_bastion_public" { - vpc_id = "${var.vpc_id}" - name = "${module.eg_prod_bastion_label.id}" - tags = "${module.eg_prod_bastion_label.tags}" + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags egress { from_port = 0 to_port = 0 @@ -111,12 +120,15 @@ module "eg_prod_bastion_abc_label" { name = "bastion" attributes = ["abc"] delimiter = "-" - tags = "${map("BusinessUnit", "ABC")}" + + tags = { + "BusinessUnit" = "ABC" + } } resource "aws_security_group" "eg_prod_bastion_abc" { - name = "${module.eg_prod_bastion_abc_label.id}" - tags = "${module.eg_prod_bastion_abc_label.tags}" + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags ingress { from_port = 22 to_port = 22 @@ -127,23 +139,26 @@ resource "aws_security_group" "eg_prod_bastion_abc" { resource "aws_instance" "eg_prod_bastion_abc" { instance_type = "t1.micro" - tags = "${module.eg_prod_bastion_abc_label.tags}" - vpc_security_group_ids = ["${aws_security_group.eg_prod_bastion_abc.id}"] + tags = module.eg_prod_bastion_abc_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] } module "eg_prod_bastion_xyz_label" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + source = "git::https://github.com/cloudposse/terraform-terraform-label.git?ref=master" namespace = "eg" stage = "prod" name = "bastion" attributes = ["xyz"] delimiter = "-" - tags = "${map("BusinessUnit", "XYZ")}" + + tags = { + "BusinessUnit" = "XYZ" + } } resource "aws_security_group" "eg_prod_bastion_xyz" { - name = "module.eg_prod_bastion_xyz_label.id" - tags = "${module.eg_prod_bastion_xyz_label.tags}" + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags ingress { from_port = 22 to_port = 22 @@ -154,8 +169,8 @@ resource "aws_security_group" "eg_prod_bastion_xyz" { resource "aws_instance" "eg_prod_bastion_xyz" { instance_type = "t1.micro" - tags = "${module.eg_prod_bastion_xyz_label.tags}" - vpc_security_group_ids = ["${aws_security_group.eg_prod_bastion_xyz.id}"] + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] } ``` @@ -174,25 +189,25 @@ Available targets: lint Lint terraform code ``` - ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| attributes | Additional attributes, e.g. `1` | list | `` | no | -| convert_case | Convert fields to lower case | string | `true` | no | -| delimiter | Delimiter to be used between `namespace`, `name`, `stage` and `attributes` | string | `-` | no | -| enabled | Set to false to prevent the module from creating any resources | string | `true` | no | -| name | Solution name, e.g. `app` | string | - | yes | -| namespace | Namespace, which could be your organization name, e.g. `cp` or `cloudposse` | string | - | yes | -| stage | Stage, e.g. `prod`, `staging`, `dev`, or `test` | string | - | yes | -| tags | Additional tags (e.g. `map(`BusinessUnit`,`XYZ`) | map | `` | no | +| attributes | Additional attributes (e.g. `1`) | list(string) | `` | no | +| convert_case | Convert fields to lower case | bool | `true` | no | +| delimiter | Delimiter to be used between `namespace`, `stage`, `name` and `attributes` | string | `-` | no | +| enabled | Set to false to prevent the module from creating any resources | bool | `true` | 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' | string | `` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | map(string) | `` | no | ## Outputs | Name | Description | |------|-------------| | attributes | Normalized attributes | +| delimiter | Delimiter between `namespace`, `stage`, `name` and `attributes` | | id | Disambiguated ID | | name | Normalized name | | namespace | Normalized namespace | @@ -279,7 +294,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) diff --git a/README.yaml b/README.yaml index c03594a..d66f261 100644 --- a/README.yaml +++ b/README.yaml @@ -18,9 +18,9 @@ github_repo: cloudposse/terraform-terraform-label # Badges to display badges: - - name: "Build Status" - image: "https://travis-ci.org/cloudposse/terraform-terraform-label.svg?branch=master" - url: "https://travis-ci.org/cloudposse/terraform-terraform-label" + - name: "Codefresh Build Status" + image: "https://g.codefresh.io/api/badges/pipeline/cloudposse/cloudposse%2Fterraform-null-label%2Ftest?type=cf-1" + url: "https://g.codefresh.io/public/accounts/cloudposse/pipelines/cloudposse/terraform-null-label/test" - name: "Latest Release" image: "https://img.shields.io/github/release/cloudposse/terraform-terraform-label.svg" url: "https://github.com/cloudposse/terraform-terraform-label/releases/latest" @@ -44,7 +44,7 @@ description: |- It's recommended to use one `terraform-terraform-label` module for every unique resource of a given resource type. For example, if you have 10 instances, there should be 10 different labels. - However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic ips), then they can all share the same label assuming they are logically related. + However, if you have multiple different kinds of resources (e.g. instances, security groups, file systems, and elastic IPs), then they can all share the same label assuming they are logically related. All [Cloud Posse modules](https://github.com/cloudposse?utf8=%E2%9C%93&q=terraform-&type=&language=) use this module to ensure resources can be instantiated multiple times within an account and without conflict. @@ -64,7 +64,11 @@ usage: |- name = "bastion" attributes = ["public"] delimiter = "-" - tags = "${map("BusinessUnit", "XYZ", "Snapshot", "true")}" + + tags = { + "BusinessUnit" = "XYZ", + "Snapshot" = "true" + } } ``` @@ -75,7 +79,7 @@ usage: |- ```hcl resource "aws_instance" "eg_prod_bastion_public" { instance_type = "t1.micro" - tags = "${module.eg_prod_bastion_label.tags}" + tags = module.eg_prod_bastion_label.tags } ``` @@ -83,9 +87,9 @@ usage: |- ```hcl resource "aws_security_group" "eg_prod_bastion_public" { - vpc_id = "${var.vpc_id}" - name = "${module.eg_prod_bastion_label.id}" - tags = "${module.eg_prod_bastion_label.tags}" + vpc_id = var.vpc_id + name = module.eg_prod_bastion_label.id + tags = module.eg_prod_bastion_label.tags egress { from_port = 0 to_port = 0 @@ -108,12 +112,15 @@ usage: |- name = "bastion" attributes = ["abc"] delimiter = "-" - tags = "${map("BusinessUnit", "ABC")}" + + tags = { + "BusinessUnit" = "ABC" + } } resource "aws_security_group" "eg_prod_bastion_abc" { - name = "${module.eg_prod_bastion_abc_label.id}" - tags = "${module.eg_prod_bastion_abc_label.tags}" + name = module.eg_prod_bastion_abc_label.id + tags = module.eg_prod_bastion_abc_label.tags ingress { from_port = 22 to_port = 22 @@ -124,23 +131,26 @@ usage: |- resource "aws_instance" "eg_prod_bastion_abc" { instance_type = "t1.micro" - tags = "${module.eg_prod_bastion_abc_label.tags}" - vpc_security_group_ids = ["${aws_security_group.eg_prod_bastion_abc.id}"] + tags = module.eg_prod_bastion_abc_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_abc.id] } module "eg_prod_bastion_xyz_label" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=master" + source = "git::https://github.com/cloudposse/terraform-terraform-label.git?ref=master" namespace = "eg" stage = "prod" name = "bastion" attributes = ["xyz"] delimiter = "-" - tags = "${map("BusinessUnit", "XYZ")}" + + tags = { + "BusinessUnit" = "XYZ" + } } resource "aws_security_group" "eg_prod_bastion_xyz" { - name = "module.eg_prod_bastion_xyz_label.id" - tags = "${module.eg_prod_bastion_xyz_label.tags}" + name = module.eg_prod_bastion_xyz_label.id + tags = module.eg_prod_bastion_xyz_label.tags ingress { from_port = 22 to_port = 22 @@ -151,8 +161,8 @@ usage: |- resource "aws_instance" "eg_prod_bastion_xyz" { instance_type = "t1.micro" - tags = "${module.eg_prod_bastion_xyz_label.tags}" - vpc_security_group_ids = ["${aws_security_group.eg_prod_bastion_xyz.id}"] + tags = module.eg_prod_bastion_xyz_label.tags + vpc_security_group_ids = [aws_security_group.eg_prod_bastion_xyz.id] } ``` diff --git a/codefresh/test.yml b/codefresh/test.yml new file mode 100644 index 0000000..09a2154 --- /dev/null +++ b/codefresh/test.yml @@ -0,0 +1,63 @@ +version: '1.0' + +stages: +- Prepare +- Test + +steps: + 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: + - make -C test/src diff --git a/docs/terraform.md b/docs/terraform.md index c537bea..a45248c 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -1,22 +1,22 @@ - ## Inputs | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| -| attributes | Additional attributes, e.g. `1` | list | `` | no | -| convert_case | Convert fields to lower case | string | `true` | no | -| delimiter | Delimiter to be used between `namespace`, `name`, `stage` and `attributes` | string | `-` | no | -| enabled | Set to false to prevent the module from creating any resources | string | `true` | no | -| name | Solution name, e.g. `app` | string | - | yes | -| namespace | Namespace, which could be your organization name, e.g. `cp` or `cloudposse` | string | - | yes | -| stage | Stage, e.g. `prod`, `staging`, `dev`, or `test` | string | - | yes | -| tags | Additional tags (e.g. `map(`BusinessUnit`,`XYZ`) | map | `` | no | +| attributes | Additional attributes (e.g. `1`) | list(string) | `` | no | +| convert_case | Convert fields to lower case | bool | `true` | no | +| delimiter | Delimiter to be used between `namespace`, `stage`, `name` and `attributes` | string | `-` | no | +| enabled | Set to false to prevent the module from creating any resources | bool | `true` | 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' | string | `` | no | +| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | map(string) | `` | no | ## Outputs | Name | Description | |------|-------------| | attributes | Normalized attributes | +| delimiter | Delimiter between `namespace`, `stage`, `name` and `attributes` | | id | Disambiguated ID | | name | Normalized name | | namespace | Normalized namespace | diff --git a/examples/complete/label1.tf b/examples/complete/label1.tf new file mode 100644 index 0000000..2b15734 --- /dev/null +++ b/examples/complete/label1.tf @@ -0,0 +1,47 @@ +module "label1" { + source = "../../" + namespace = "Namespace" + stage = "Stage" + name = "Name" + attributes = ["1", "2", "3"] + delimiter = "-" + + tags = { + "Key" = "Value" + } +} + +output "label1_id" { + value = module.label1.id +} + +output "label1_name" { + value = module.label1.name +} + +output "label1_namespace" { + value = module.label1.namespace +} + +output "label1_stage" { + value = module.label1.stage +} + +output "label1_attributes" { + value = module.label1.attributes +} + +output "label1_tags" { + value = module.label1.tags +} + +output "label1" { + value = { + id = module.label1.id + name = module.label1.name + namespace = module.label1.namespace + stage = module.label1.stage + attributes = module.label1.attributes + delimiter = module.label1.delimiter + } +} diff --git a/examples/complete/main.tf b/examples/complete/main.tf deleted file mode 100644 index 0d96945..0000000 --- a/examples/complete/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -module "label" { - source = "../../" - namespace = "Namespace" - stage = "Stage" - name = "Name" - attributes = ["1", "2", "3", ""] - tags = "${map("Key", "Value")}" -} diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf deleted file mode 100644 index af291b6..0000000 --- a/examples/complete/outputs.tf +++ /dev/null @@ -1,23 +0,0 @@ -output "id" { - value = "${module.label.id}" -} - -output "name" { - value = "${module.label.name}" -} - -output "namespace" { - value = "${module.label.namespace}" -} - -output "stage" { - value = "${module.label.stage}" -} - -output "attributes" { - value = "${module.label.attributes}" -} - -output "tags" { - value = "${module.label.tags}" -} diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf new file mode 100644 index 0000000..7000b05 --- /dev/null +++ b/examples/complete/versions.tf @@ -0,0 +1,3 @@ +terraform { + required_version = "~> 0.12.0" +} diff --git a/main.tf b/main.tf index 18cb2f0..da25f41 100644 --- a/main.tf +++ b/main.tf @@ -1,34 +1,23 @@ locals { - original_tags = "${join(var.delimiter, compact(concat(list(var.namespace, var.stage, var.name), var.attributes)))}" + original_tags = join(var.delimiter, compact(concat(list(var.namespace, var.stage, var.name), var.attributes))) + transformed_tags = var.convert_case ? lower(local.original_tags) : local.original_tags } locals { - convert_case = "${var.convert_case == "true" ? true : false }" -} - -locals { - transformed_tags = "${local.convert_case == true ? lower(local.original_tags) : local.original_tags}" -} - -locals { - enabled = "${var.enabled == "true" ? true : false }" - - id = "${local.enabled == true ? local.transformed_tags : ""}" + id = var.enabled ? local.transformed_tags : "" - name = "${local.enabled == true ? (local.convert_case == true ? lower(format("%v", var.name)) : format("%v", var.name)) : ""}" - namespace = "${local.enabled == true ? (local.convert_case == true ? lower(format("%v", var.namespace)) : format("%v", var.namespace)) : ""}" - stage = "${local.enabled == true ? (local.convert_case == true ? lower(format("%v", var.stage)) : format("%v", var.stage)) : ""}" - attributes = "${local.enabled == true ? (local.convert_case == true ? lower(format("%v", join(var.delimiter, compact(var.attributes)))) : format("%v", join(var.delimiter, compact(var.attributes)))): ""}" + name = var.enabled ? (var.convert_case ? lower(format("%v", var.name)) : format("%v", var.name)) : "" + namespace = var.enabled ? (var.convert_case ? lower(format("%v", var.namespace)) : format("%v", var.namespace)) : "" + stage = var.enabled ? (var.convert_case ? lower(format("%v", var.stage)) : format("%v", var.stage)) : "" + delimiter = var.enabled ? (var.convert_case ? lower(format("%v", var.delimiter)) : format("%v", var.delimiter)) : "" + attributes = var.enabled ? (var.convert_case ? lower(format("%v", join(var.delimiter, compact(var.attributes)))) : format("%v", join(var.delimiter, compact(var.attributes)))) : "" - # Merge input tags with our tags. - # Note: `Name` has a special meaning in AWS and we need to disamgiuate it by using the computed `id` - tags = "${ - merge( - map( - "Name", "${local.id}", - "Namespace", "${local.namespace}", - "Stage", "${local.stage}" - ), var.tags - ) - }" + tags = merge( + { + "Name" = local.id + "Namespace" = local.namespace + "Stage" = local.stage + }, + var.tags + ) } diff --git a/outputs.tf b/outputs.tf index 38485ee..5347d4e 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,29 +1,34 @@ output "id" { - value = "${local.id}" + value = local.id description = "Disambiguated ID" } output "name" { - value = "${local.name}" + value = local.name description = "Normalized name" } output "namespace" { - value = "${local.namespace}" + value = local.namespace description = "Normalized namespace" } output "stage" { - value = "${local.stage}" + value = local.stage description = "Normalized stage" } +output "delimiter" { + value = local.delimiter + description = "Delimiter between `namespace`, `stage`, `name` and `attributes`" +} + output "attributes" { - value = "${local.attributes}" + value = local.attributes description = "Normalized attributes" } output "tags" { - value = "${local.tags}" + value = local.tags description = "Normalized Tag map" } diff --git a/terraform.tf b/terraform.tf new file mode 100644 index 0000000..7000b05 --- /dev/null +++ b/terraform.tf @@ -0,0 +1,3 @@ +terraform { + required_version = "~> 0.12.0" +} 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..ea15d62 --- /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 init plan apply +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.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..1143911 --- /dev/null +++ b/test/src/Makefile @@ -0,0 +1,50 @@ +PACKAGE = terraform-terraform-label +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..227eeba --- /dev/null +++ b/test/src/examples_complete_test.go @@ -0,0 +1,31 @@ +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, + } + + // 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 + label1 := terraform.OutputMap(t, terraformOptions, "label1") + + // Verify we're getting back the outputs we expect + assert.Equal(t, "namespace-stage-name-1-2-3", label1["id"]) +} diff --git a/variables.tf b/variables.tf index 5c432ac..22ee915 100644 --- a/variables.tf +++ b/variables.tf @@ -1,39 +1,47 @@ variable "namespace" { - description = "Namespace, which could be your organization name, e.g. `cp` or `cloudposse`" + type = string + default = "" + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" } variable "stage" { - description = "Stage, e.g. `prod`, `staging`, `dev`, or `test`" + type = string + default = "" + description = "Stage, e.g. 'prod', 'staging', 'dev'" } variable "name" { - description = "Solution name, e.g. `app`" -} - -variable "enabled" { - description = "Set to false to prevent the module from creating any resources" - default = "true" + type = string + default = "" + description = "Solution name, e.g. `app` or `jenkins`" } variable "delimiter" { - type = "string" + type = string default = "-" - description = "Delimiter to be used between `namespace`, `name`, `stage` and `attributes`" + description = "Delimiter to be used between `namespace`, `stage`, `name` and `attributes`" } variable "attributes" { - type = "list" + type = list(string) default = [] - description = "Additional attributes, e.g. `1`" + description = "Additional attributes (e.g. `1`)" } variable "tags" { - type = "map" + type = map(string) default = {} - description = "Additional tags (e.g. `map(`BusinessUnit`,`XYZ`)" + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "enabled" { + type = bool + default = true + description = "Set to false to prevent the module from creating any resources" } variable "convert_case" { + type = bool + default = true description = "Convert fields to lower case" - default = "true" }