5.3. Various
Preparation
Create a new directory for this exercise:
mkdir $LAB_ROOT/advanced/various
cd $LAB_ROOT/advanced/various
Optional: Create empty files:
touch {main,variables,outputs}.tf
Step 5.3.1: Variable structure
Terraform variables support nested complex types like nested maps and sets. The type keyword of the variable
block allows the definition of type constraints to enforce the correctness of the input (or default) value.
See https://developer.hashicorp.com/terraform/language/expressions/type-constraints
for the specification.
Create a new file named variables.tf and add the following content:
variable "clouds" {
default = {
aws = {
company = "Amazon"
founder = "Jeff Bezos"
cloud_rank = 1
}
azure = {
company = "Microsoft"
founder = "Bill Gates"
cloud_rank = 2
}
gcp = {
company = "Google"
founder = "Larry Page and Sergey Brin"
cloud_rank = 3
}
}
type = map(object({
company = string
founder = string
cloud_rank = number
}))
}
The code snippet above defines a map for the top three cloud platforms with three attributes:
- company
- founder
- cloud_rank
Try it out
Create a list of the founder attributes of all clouds using a SINGLE output using the following snippet:
output "founders" {
value = ["todo"]
}
Step 5.3.2: Variable optional and default fields
Defining variables as objects with attributes is very useful, but sometimes we don’t want to specify all
attributes but use some defaults. This can be achieved by the optional keyword.
Add the following snippet to outputs.tf:
variable "kubernetes" {
type = object({
version = optional(string)
node_count = optional(number, 3)
vm_type = optional(string, "t3.small")
})
default = {
version = "1.25.5"
}
}
output "kubernetes" {
value = var.kubernetes
}
When you run terraform apply you should see a fully defined kubernetes variable:
kubernetes = {
"node_count" = 3
"version" = "1.25.5"
"vm_type" = "t3.small"
}
config/*.tfvars files, to only specify the
explicit and override values - keeping the config small and tidy!Step 5.3.3: Variable validation
Sometimes you want to validate if a variable meets certain conditions. For this purpose, the validation block can
be added to a variable.
Modify outputs.tf as followed:
variable "kubernetes" {
type = object({
version = optional(string)
node_count = optional(number, 0)
vm_type = optional(string, "t3.small")
})
default = {
version = "1.25.5"
}
validation {
condition = var.kubernetes.node_count > 0
error_message = "Minimum Kubernetes nodes is 1"
}
}
Note: Set the node_count default to 0 to trigger a validation error!
Now run terraform apply and verify the validation error is printed.
Step 5.3.4: Dynamic blocks
Some Terraform resources (and data sources) have repetitive blocks, for example archive_file. See documentation
at https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file
Example:
data "archive_file" "dotfiles" {
type = "zip"
output_path = "dotfiles.zip"
source {
content = "# nothing"
filename = ".vimrc"
}
source {
content = "# comment"
filename = ".ssh/config"
}
}To add such blocks repetitively, we can use the dynamic keyword as documented here:
https://www.terraform.io/docs/language/expressions/dynamic-blocks.html
Create a new file named main.tf and add the following content:
data "archive_file" "clouds" {
type = "zip"
output_path = "clouds.zip"
dynamic "source" {
for_each = var.clouds
content {
filename = "${source.key}.txt"
content = jsonencode(source.value)
}
}
}
This will create a zip file containing a text file for each entry in the clouds map variable defined previously.
Now run:
terraform init
terraform apply
unzip clouds.zip
cat *txt