Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
crash.log

# Exclude all .tfvars files, which are likely to contain sentitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
#
*.tfvars
Expand Down
62 changes: 62 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.PHONY: static-tests unit-tests integration-tests e2e-tests init

# OS can be "Linux" or "macOS"
OS ?= Linux
# ARCH can be "x86_64" or "arm64"
ARCH ?= x86_64

TERRAFORM_VERSION := 1.0.10
TFLINT_VERSION := 0.33.1


SHELL := /usr/bin/env bash

static-tests: setup-env
rm .terraform.lock.hcl plan.out plan.out.json 2> /dev/null || true
# should not require any aws credentials to test against, should be safe to run as github checks on pull requests
terraform init || ( echo 'FAILED: terraform init failed'; exit 1 )
terraform validate || ( echo 'FAILED: terraform validate failed'; exit 1 )
terraform fmt -check -recursive ./ || ( echo 'FAILED: all tf files should be formatted using "terraform fmt -recursive ./"'; exit 1 )
tflint --init && tflint --var='region=us-west-1' --var='profile=default' ./ || ( echo 'FAILED: tflint found issues'; exit 1 )

unit-tests: setup-env
# Should test code paths in an individual module. terratest, or `terraform test`, this is where you want to test different regions, use retries to smooth transient errors
# Should not run automatically on PR's from un-trusted contributors
export PATH=$(shell pwd)/build/bin:$${PATH} &&\
cd test && \
go test -timeout 30m -json | tee >(go-test-report) | jq -jr .Output 2> /dev/null | sed 's/null//g';\
retval_bash="$${PIPESTATUS[0]}" retval_zsh="$${pipestatus[1]}" ;\
exit $$retval_bash $$retval_zsh

integration-tests:
# Should test code paths in a module of modules and run when on eof the sub-modules is updated. terratest, or `terraform test` use retries to smooth transient errors
# Should not run automatically on PR's from un-trusted contributors, and should only be run on modules where one sub-module is changed
echo "todo"
exit 1

e2e-tests:
# Should test code paths in `deploy/` module. Unsure whether it should use tf cloud. terratest, or `terraform test`.
# For deploys that take long you could skip destroy between runs, so e2e is just updating what changed from last iteration, use retries to smooth transient errors.
# Should not run automatically on PR's from any contributors. Update(no destroy) tests run on `/do-e2e-tests` PR comment from maintainers. Full e2e run on release.
echo "todo"
exit 1

setup-env:
# using a bin path specific to this project so that different projects can use different versions of the tooling
mkdir -p build/bin/ &&\
export PATH=$(shell pwd)/build/bin:$${PATH} &&\
export TF_ARCH=$(shell echo $(ARCH) | sed 's/x86_64/amd64/') &&\
export TF_OS=$(shell echo $(OS) | tr '[:upper:]' '[:lower:]' | sed 's/macos/darwin/') &&\
export CT_OS=$(shell echo $(OS) | sed 's/macOS/Darwin/') &&\
if [ "$$(terraform -v | head -n 1 | sed 's/Terraform v//')" != "$(TERRAFORM_VERSION)" ]; then \
wget -O tf.zip https://releases.hashicorp.com/terraform/$(TERRAFORM_VERSION)/terraform_$(TERRAFORM_VERSION)_$${TF_OS}_$${TF_ARCH}.zip &&\
unzip -o tf.zip terraform &&\
rm tf.zip &&\
mv -fv terraform build/bin/ ;\
fi ;\
if [ "$$(tflint --version | head -n 1 | sed 's/TFLint version //')" != "$(TFLINT_VERSION)" ]; then \
wget -O tflint.zip https://github.com/terraform-linters/tflint/releases/download/v$(TFLINT_VERSION)/tflint_$${TF_OS}_$${TF_ARCH}.zip &&\
unzip -o tflint.zip tflint &&\
rm tflint.zip &&\
mv -fv tflint build/bin/ ;\
fi
2 changes: 1 addition & 1 deletion examples/main.tf → examples/basic/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ provider "awscc" {
}

module "labels" {
source = "../"
source = "../.."

name = "measurements"
namespace = "link"
Expand Down
File renamed without changes.
File renamed without changes.
59 changes: 59 additions & 0 deletions examples/formatted_tags/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
provider "aws" {
region = var.region
}

provider "awscc" {
region = var.region
}

locals {
# In the AWS provider format
aws_tags = {
"service" : "authorize",
"managed_by" : "terraform"
}

# In the AWSCC provider format
awcc_tags = [
{ "key" : "service", "value" : "measurements" },
{ "key" = "managed_by", "value" : "terraform" }
]
}

# Using aws provider format as input
module "aws_labels" {
source = "../.."

tags = local.aws_tags
}

# Using awscc provider format as input
module "awscc_labels" {
source = "../.."

tags = local.awcc_tags
}

module "test_aws_to_aws" {
source = "../../internal/modules/aws"

tags = module.aws_labels.tags_aws
}

module "test_aws_to_awscc" {
source = "../../internal/modules/awscc"

tags = module.aws_labels.tags
}

module "test_awscc_to_aws" {
source = "../../internal/modules/aws"

tags = module.awscc_labels.tags_aws
}

module "test_awscc_to_awscc" {
source = "../../internal/modules/awscc"

tags = module.awscc_labels.tags
}
5 changes: 5 additions & 0 deletions examples/formatted_tags/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "region" {
type = string
default = "eu-west-1"
description = "What AWS region to deploy resources in."
}
2 changes: 2 additions & 0 deletions internal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Warning
Do not use anything within the `internal` folder. It is only used for testing and verification of the module.
29 changes: 29 additions & 0 deletions internal/modules/aws/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Do not use. This This module only exists to verify the tag formatting.
*/

variable "tags" {
description = "tags, which could be used for additional tags"
type = map(string)
}

resource "aws_iam_policy" "policy" {
description = "A temporary policy. Should be deleted by the test."
name_prefix = "test_policy"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ec2:Describe*",
]
Effect = "Deny"
Resource = "*"
},
]
})

tags = var.tags
}

27 changes: 27 additions & 0 deletions internal/modules/awscc/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Do not use. This This module only exists to verify the tag formatting.
*/

variable "tags" {
description = "tags, which could be used for additional tags"
}

resource "awscc_iam_role" "role" {
description = "A temporary role. Should be deleted by the test."

assume_role_policy_document = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
},
]
})

tags = var.tags
}

33 changes: 23 additions & 10 deletions locals.tf
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
locals {
generated_tags = [
generated_tags_awscc = [
{
"key": "Name",
"value": join("", null_resource.default.*.triggers.id)
"key" : "Name",
"value" : join("", null_resource.default.*.triggers.id)
},
{
"key": "Namespace",
"value": join("", null_resource.default.*.triggers.namespace),
"key" : "Namespace",
"value" : join("", null_resource.default.*.triggers.namespace),
},
{
"key": "Account",
"value": join("", null_resource.default.*.triggers.account)
"key" : "Account",
"value" : join("", null_resource.default.*.triggers.account)
},
{
"key": "Env",
"value": join("", null_resource.default.*.triggers.env)
"key" : "Env",
"value" : join("", null_resource.default.*.triggers.env)
}
]
generated_tags_aws = { for tag in local.generated_tags_awscc : tag["key"] => tag["value"] }

tags = concat(local.generated_tags, var.tags)
tags = try(
# Tags are already in awscc format
concat(local.generated_tags_awscc, var.tags),
# Tags are in aws format. Convert to awscc format
concat(local.generated_tags_awscc, [for k, v in var.tags : { key : k, value : v }])
)

tags_aws = try(
# Assuming tags are already in aws format
merge(local.generated_tags_aws, var.tags),
# Tags are in awscc format. Converting to aws format
merge(local.generated_tags_aws, { for tag in var.tags : tag["key"] => tag["value"] })
)
}
4 changes: 4 additions & 0 deletions output.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ output "tags" {
value = local.tags
}

output "tags_aws" {
value = local.tags_aws
}

output "id" {
value = join("", null_resource.default.*.triggers.id)
}
Expand Down
8 changes: 2 additions & 6 deletions variable.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ variable "attributes" {
}

variable "tags" {
type = list(object({
key = string
value = string
}))

default = []
description = "tags, which could be used for additional tags"
type = any
default = []
}