Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Modules, outputs and validation

After this lesson: I can call a module twice and read what each copy hands back.

60 min lesson11 commandsOpenTofu lab: infrastructure as code with plan, apply and state on one VM

Two shops, one recipe

An OpenTofu module is a folder of files that a project can call again and again, each time with its own values. It matters because a fix made once in the module reaches every place that calls it.

A company runs a corner shop and a hill shop with the same set-up. Copying the files works until a fix is needed, and then it is made twice. A module is the recipe written once.

By the end of this lesson

Note

I can call a module twice and read what each copy hands back.

Key words

WordWhat it meansExample
Modulea folder of files that you can use again
Module calla block that uses a module and gives it valuesmodule "hill"
Outputa value a module hands back
Validationa rule that refuses a bad input
Module addressthe path of a resource, starting with modulemodule.hill.terraform_data.sign

The cells students fill in are left blank in this preview.

A module is a folder you call

A module is a folder of OpenTofu files. The project that uses it is the root. The root writes a module call, names the folder in source, and gives each input a value.

Two calls make two separate copies of everything in the folder. The source here is a local path, so nothing is downloaded.

Make the folders and go in

Command
mkdir -p ~/iac-demo/mods/modules/shop && cd ~/iac-demo/mods

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the module

Command
printf '%s\n' 'variable "name" {' '  type = string' '  validation {' '    condition     = length(var.name) >= 3 && length(var.name) <= 10' '    error_message = "The name must have 3 to 10 characters."' '  }' '}' '' 'resource "terraform_data" "sign" {' '  input = format("%s: open", var.name)' '}' '' 'output "sign" {' '  value = terraform_data.sign.output' '}' > modules/shop/main.tf

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the root: two calls and one output

Command
printf '%s\n' 'module "corner" {' '  source = "./modules/shop"' '  name   = "Corner"' '}' '' 'module "hill" {' '  source = "./modules/shop"' '  name   = "Hill"' '}' '' 'output "signs" {' '  value = [module.corner.sign, module.hill.sign]' '}' > main.tf

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Prepare the folder

Command
tofu init -no-color | grep -E "Initializing modules|corner|hill|successfully"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Plan, and look at the addresses

Command
tofu plan -no-color | grep -E "will be created|^Plan"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A module hands back outputs

A resource inside a module has a longer address, such as module.hill.terraform_data.sign. The root cannot read it directly.

Only an output crosses the wall. The root reads it as module.hill.sign: the call name, then the output name.

Apply, so the state holds both copies

Command
tofu apply -auto-approve -no-color | grep "Apply complete"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

List the addresses in the state

Command
tofu state list

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Read the output the root made

Command
tofu output signs

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think the root can read any resource inside a module. It cannot. A module shares only what its outputs name, so a value you want outside needs an output block.

Read a resource that has no output

Command
printf '%s\n' 'output "bad" {' '  value = module.corner.terraform_data.sign' '}' > bad.tf; tofu validate -no-color 2>&1 | grep -E "Error|Unsupported"; rm bad.tf

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A validation rule refuses a bad input

A validation block holds a condition and an error_message. When the condition is false, OpenTofu stops before it plans anything and prints the message.

The module here accepts a name of 3 to 10 characters. Try a name that is too short.

Give the hill shop a short name

Command
sed -i 's/"Hill"/"Hi"/' main.tf; tofu validate -no-color 2>&1 | grep -E "Error|must have"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Put the name back and check it

Command
sed -i 's/"Hi"/"Hill"/' main.tf; tofu validate -no-color

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Two calls worked out in Python

Code: python
# Work out the addresses a module call makes.
resources = ["sign", "door"]
calls = {"corner": None, "hill": None}
for call in calls:
    for name in resources:
        print("module." + call + ".terraform_data." + name)
# Change "hill": None to "hill": ["a", "b"] and look again.

Now do it in the lab

The Runs built a module in a practice folder. The lab has a folder for this too, ~/tofu-lab/shop, and part 7 of its README says what to build. It is not the same module, so you must change what you saw, not copy it.

How it is marked

Your teacher marks it by running a check on your saved lab. The check applies your project, then calls your module again with names and a status you have never seen. A module with the answers typed in cannot follow those, and neither can one with no validation rule.

Going further: a call with count

Add count = 2 to the hill call, and change module.hill.sign in the output to module.hill[0].sign. Run tofu plan -no-color | grep -E "will be|^Plan".

Which addresses does the plan show now, and why did the output line need to change?

About this lab and its source: OpenTofu lab: infrastructure as code with plan, apply and state on one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.