A plan lists changes before they happen
An OpenTofu plan is the list of changes the tool would make, with a symbol in front of each. Reading it before you apply is the main safety check of infrastructure as code. A small edit can destroy a resource and build it again.
The skill is quick: find the symbol, find the name, read the total on the last line.
By the end of this lesson
Note
I can read a plan after a change and say what is created, changed or destroyed.
Key words
| Word | What it means | Example |
|---|---|---|
| Update in place | a resource changes and stays the same resource | ~ |
| Destroy | a resource will be removed | - |
| Replace | destroy a resource, then create it again | -/+ |
| Known after apply | a value that is only decided during the apply | |
| Trigger | a value whose change forces a replacement |
The cells students fill in are left blank in this preview.
Every plan line starts with a symbol
A plan marks every resource it will touch. + means create. - means destroy. ~ means update in place.
A fourth symbol, -/+, means replace: OpenTofu destroys the old resource, then creates a new one. The last line adds it all up. A replacement counts once as an add and once as a destroy.
The plan symbols and what they mean
| Symbol | Words in the plan | Counted as |
|---|---|---|
| + | will be created | 1 to add |
| ~ | will be updated in-place | 1 to change |
| - | will be destroyed | 1 to destroy |
| -/+ | must be replaced | 1 to add and 1 to destroy |
The cells students fill in are left blank in this preview.
Make a folder for the signs
mkdir -p ~/iac-demo/signsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Go into it
cd ~/iac-demo/signsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write a project with three resources
printf '%s\n' 'variable "shop" {' ' type = string' ' default = "Corner Shop"' '}' '' 'variable "sign_version" {' ' type = number' ' default = 1' '}' '' 'resource "terraform_data" "door" {' ' input = format("%s: open", var.shop)' '}' '' 'resource "terraform_data" "sign" {' ' input = "Open today"' ' triggers_replace = [var.sign_version]' '}' '' 'resource "terraform_data" "window" {' ' input = "Sale"' '}' > main.tfShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Prepare the folder
tofu init -no-color | grep successfullyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Apply, so the state holds all three
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.
An edit may change or replace a resource
Only the resources an edit reaches appear in the plan. The door reads the variable shop, so changing the shop touches the door and nothing else.
The sign has triggers_replace, a list of values. When any of them changes, OpenTofu will not edit the sign: it replaces it. The Runs below pass different values with -var. They only plan, so nothing is applied.
Change the shop name: one update in place
tofu plan -no-color -var shop="Hill Shop" | grep -E "will be|^Plan|known after apply"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Change the sign version: one replacement
tofu plan -no-color -var sign_version=2 | grep -E "will be|must be|^Plan"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 a replacement is a gentle change. It is not. The old resource is destroyed and a new one is made, so anything stored in the old one is gone. Before you apply, look for -/+ and the words must be replaced.
Both changes at once
tofu plan -no-color -var shop="Hill Shop" -var sign_version=2 | grep -E "will be|must be|^Plan"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: adding up the last line
| Resource | Symbol | To add | To change | To destroy |
|---|---|---|---|---|
| door | ~ | 0 | 1 | 0 |
| sign | -/+ | 1 | 0 | 1 |
| window | none | 0 | 0 | 0 |
| Total | 1 | 1 | 1 |
The cells students fill in are left blank in this preview.
Delete the window block from the file
sed -i '/"window"/,/^}/d' main.tfShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Show the symbol for each change
tofu plan -no-color -var shop="Hill Shop" -var sign_version=2 | grep resourceShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A plan worked out in Python
# Work out a plan between a state and a wish.
state = {
"door": {"input": "open", "trigger": 1},
"sign": {"input": "Open today", "trigger": 1},
"window": {"input": "Sale", "trigger": 1},
}
wish = {
"door": {"input": "open", "trigger": 1},
"sign": {"input": "Open today", "trigger": 2},
"gate": {"input": "Locked", "trigger": 1},
}
add = 0
destroy = 0
for name in wish:
if name not in state:
print("+", name)
add = add + 1
elif wish[name]["trigger"] != state[name]["trigger"]:
print("-/+", name)
add = add + 1
destroy = destroy + 1
for name in state:
if name not in wish:
print("-", name)
destroy = destroy + 1
print("Plan:", add, "to add,", destroy, "to destroy.")
# Change window's trigger in the wish and look again.