Terraform Template Gimmicks
While managing multiple environments with Terraform, you might come across this scenario:
- you have to manage multiple environments
- all the environments use the same configuration file, but with different values
- so, the above mentioned configuration file has to be a template
- some environments tend to be snowflakes, as they have non-default values
You want to accomplish two things:
- limit the number of variables you maintain for each environment
- not replicate a snowflake variable to a standard / non-snowflake environment
The solution
- is described in this Hashicorp blog post
- and presented with a demo code in this repository of mine
The TL;DR version
The structure of the Terraform code
$ tree
.
├── common-template-file.tftpl
├── environmentA
│ ├── render-template.tf
│ └── variables.tf
├── environmentB
│ ├── render-template.tf
│ └── variables.tf
├── environmentC
│ ├── render-template.tf
│ └── variables.tf
├── environmentD
│ ├── render-template.tf
│ └── variables.tf
├── environmentE
│ ├── render-template.tf
│ └── variables.tf
└── README.md
So
- there's a common template for all environments
- each environment has its own directory
- each environment has a bunch of .tf files holding the Terraform code
- in
variables.tf
each environment has its own custom set of variables
The template and the variables
This is the common template file:
global:
hostnames: [${hostname}]
importantStuff:
enableThis: ${enable_this}
thisWorksIfVariableIsDeclared:
thisDependsOnTheValueOfVariable: %{ if enable_this == false }0%{ else }1%{ endif }
thisWorksEvenIfVariableIsMissing:
VarOne: ${try(optional_vars.var_one, 2)}
VarTwo: ${try(optional_vars.var_two, "bla")}
VarThree: ${try(optional_vars.var_three, true)}
The are two important sections in the template:
the first one:
thisDependsOnTheValueOfVariable: %{ if enable_this == false }0%{ else }1%{ endif }
enable_this
is a variable that must exist in allvariables.tf
files- environmentE doesn't have it and you'll see Terraform failing because of that
- depending on its value, another variable is set.
the second one:
thisWorksEvenIfVariableIsMissing:
VarOne: ${try(optional_vars.var_one, 2)}
VarTwo: ${try(optional_vars.var_two, "bla")}
VarThree: ${try(optional_vars.var_three, true)}
optional_vars
is a section (that can have any other name) that must exist in allvariables.tf
files- environmentD doesn't have it and you'll see Terraform failing because of that
- but any variable nested under
optional_vars
is optional and can be missing
So, this will work in variables.tf
:
template_variables = {
git_tag = "some_hash"
hostname = "A.foo.bar"
enable_this = false
optional_vars = {}
}
and this will work as well:
template_variables = {
git_tag = "C"
hostname = "C.foo.bar"
enable_this = true
optional_vars = {
var_one = "C has both var_one"
var_three = "... and var_three"
}
}
but this won't:
template_variables = {
git_tag = "some_hash"
hostname = "D.foo.bar"
enable_this = false
}