Skip to main content

2 posts tagged with "terraform"

View All Tags

DRAFT POC Time limited Terraform resource implementation

· One min read
Aurelian Shuttleworth
Aurelian Shuttleworth
Site Reliability Engineer

Input design

Timestamps

Terraform has reliable support for RFC3339 2020-02-12T06:36:13Z in order to decrease complexity this will be the only supported timestamp format.

Input variable

In order to allow the user to easily specify the start, end and a resource id a simple Terraform object variable can be made to fit most use cases.

variable "time_resource" {
description = "A map containing time limited resources."
type = map(
object({
start = string
end = string
})
)
default = {}
}

Logic

Utilizing the time_rotating resource is key to making this work, unlike the timestamp() it can be determined during the terraform plan stage.

Validating for Terraform docs in Merge Requests

· 4 min read
Aurelian Shuttleworth
Aurelian Shuttleworth
Site Reliability Engineer

Terraform Docs is a fantastic helper when documenting Terraform code, but enforcing its use is not straight forward as it seems. In this post, I attempt to integrate it into a typical Gitlab CiCd pipeline as a validation step.

Problem

Developers must ensure the documentation for their Terraform changes is updated, so developers maintain quality docs.

Doing this separately to change requests results in sub-par documentation as the documents are no longer the responsibility of the user creating the change.

Enforcing this is harder than doing so with the terraform fmt and terraform validate commands. Enforcing docs are updated is difficult because terraforming docs are not part of Terraform but a separate tool that must be installed and is missing the ability to work with git diff natively.

Solutions

Terraform Docs Docker image

Terraform docs helpfully provides a maintained Docker image compatible as a part of any CI/CD Pipeline.

A validation step could be as simple as adding a pipeline step like the one below.

validate.docs:
image: quay.io/terraform-docs/terraform-docs:0.16.0
script:
- terraform-docs markdown --output-check --recursive .

There are some limitations with a simple application like the above example, especially if your Terraform code is that awkward Terrarmod phase of development where multiple terraform modules live in one repository. The recursive flag will not cut it.

You could use a simple looping function like the one below to ensure all docs are updated.

doc_paths=$(find . -type f -name '.terraform-docs.yml' -exec dirname {} + | sort -u)
for doc_path in ${doc_paths}; do
terraform-docs markdown --output-check --recursive -c "${doc_path}/.terraform-docs.yml" "${doc_path}"
done

The above works, but you now need to deal with the problem that the pipeline will fail if any doc is not updated, even if it is unrelated to the current terraform changes.

Git hooks

Git provides some handy functionality when it comes to Git Hooks. There are both server-side and client-side hooks we will be focusing on client-side.

note

A helpful stack overflow post helped me figure out how to add my hooks to a repository.

How can I commit Git hooks?

There are multiple hooks, such as pre-commit, prepare-commit-msg, commit-msg and pre-push; this is not all of them. You can learn about them here, but we will focus on the pre-push and post-commit hooks.

To create a git hook, create a script in the .git/hooks/<hook name> folder of your project and make it executable chmod +x .git/hooks/<hoook name>.

info

commit-msg works as it executes any time a user attempts to run git commit, but this could result in friction among users, so it is advisable only to use warnings and not to block behaviour.

info

pre-push is the perfect place to put blocking behaviour, such as ensuring changes never push to the main branch.

Due to the friction, if we interrupt a user every time they attempt to create a commit, we will only be using pre-push hooks.

Before we work on the code, it is essential to ensure the user is only interrupted by out-of-date docs that are part of the changes the user creates. Therefore, we will use git diff with the --name-only flag to get a list of directories that need to be checked.

default_branch="master"
git_root_path=$(git rev-parse --show-toplevel)
diff_dir_paths=()

getDiffPaths() {
diff_paths="$(git diff --name-only ${default_branch})"
for path in $diff_paths ; do
is_duplicate=false
dir_path=$(dirname "${path}")
diff_dir_path_string="${git_root_path}/${dir_path}"

for diff_dir_path in "${diff_dir_paths[@]}" ; do
if [ "${diff_dir_path_string}" = "${diff_dir_path}" ]; then
is_duplicate=true
fi
done

if [ ${is_duplicate} != true ]; then
diff_dir_paths+=("${diff_dir_path_string}")
fi
done
}

Using the code in the above example, we can use the array diff_dir_paths to identify what directories contain active changes.

terraformDocsCheck() {
if which terraform-docs 1>/dev/null ; then
for path in "${diff_dir_paths[@]}" ; do
config_path="${path}/.terraform-docs.yml"
if [ -f "${config_path}" ]; then
terraform-docs markdown --output-check -c "${config_path}" "${path}" 1>/dev/null
fi
done
else
echo "Terraform Docs not installed please install using brew install terraform-docs"
fi
}