Stage 2 — Basics (local, no cloud)¶
Thirteen topics that prove every core Terraform mechanic without touching a cloud API.
Nothing here authenticates, costs money, or can be broken in a way that matters. The
local, random, null and archive providers write files to /tmp — but the
lifecycle, the state file, the dependency graph and the plan/apply loop are the real
thing, identical to what runs against GCP in Stage 3.
The code lives in 01-basics/,
seven numbered folders holding eight self-contained Terraform roots — 4-dependencies/
isn't a root itself, its explicit/ and implicit/ subdirectories are. This section is
the only prose: the folders hold .tf files, plus one checked-in graph.svg where the
graph is the point.
Prerequisites¶
That's it. No gcloud, no credentials, no billing account. Graphviz is optional and only
needed for terraform graph:
The sequence¶
Ordered by difficulty, not by folder number. Six topics have no folder yet — the code is in the page, ready to paste into a scratch root.
| # | Topic | Folder | Writes |
|---|---|---|---|
| 1 | Resources and state | 1-create-local-file/ |
/tmp/hello.txt |
| 2 | Variables | 2-variable-use/ |
/tmp/helloFruits.txt |
| 3 | Locals | — | /tmp/tf-practice/greeting-*.txt |
| 4 | References and dependencies | 3-resource-attribute-reference/, 4-dependencies/ |
/tmp/hello_resourceAttribute.txt, /tmp/hello_{im,ex}plicit_dependencies.txt |
| 5 | Outputs | 4-dependencies/explicit/ |
nothing |
| 6 | Data sources | 6-data-sources/ |
/tmp/hello.txt |
| 7 | count and for_each | — | /tmp/pet-*.txt |
| 8 | Conditionals | — | /tmp/backup.txt |
| 9 | Lifecycle | 5-lifecycle/ |
/tmp/hello.txt |
| 10 | Validation and sensitive values | — | /tmp/app-config.txt |
| 11 | Provider versions | 7-version-constraints/ |
./hello.txt |
| 12 | State surgery | — | nothing new |
| 13 | Provisioners and archive_file | — | /tmp/greeting-*.txt, /tmp/tf-practice-bundle.zip |
Folder numbers and topic numbers deliberately don't line up. The folders were numbered in the order they were written; the topics are numbered in the order that makes them easiest to learn.
Running any of them¶
cd 01-basics/1-create-local-file
terraform init
terraform plan
terraform apply
terraform state list # what Terraform now thinks it owns
terraform destroy
Each folder is an independent root with its own state. terraform destroy between topics
is optional here — nothing costs money and nothing needs cleanup approval — but several
folders write to the same /tmp/hello.txt, so destroying as you go avoids confusion about
which root owns the file.
Deliberate defects¶
Three folders contain bugs on purpose. Fixing them teaches more than reading a working example, so don't "clean them up" without reading the relevant page first.
| Folder | Defect | Page |
|---|---|---|
5-lifecycle/ |
ignore_changes = [tags] — local_file has no tags attribute, so this errors |
Lifecycle |
7-version-constraints/ |
Writes hello.txt to the current directory while the comment says /tmp |
Provider versions |
3-… vs 4-dependencies/implicit/ |
Byte-identical main.tf, which looks like duplication and isn't |
References and dependencies |
Not yet implemented¶
Six topics are documented here but have no folder under 01-basics/. The code on each
page is complete and runnable — paste it into an empty directory and terraform init.
Roughly in the order worth building them:
| Topic | Why it's worth building |
|---|---|
| State surgery | Highest value. State surgery is far cheaper to practise on a local_file than on a GCP resource, and it's the same muscle needed for GCP Lab 6 and Lab 11. |
| Conditionals | The count = 0 error and guard propagation are the cheapest possible rehearsal of the bug that cost a whole session in the sandbox (Session 2). Reading it is not the same as hitting it. |
| count and for_each | The destructive test — remove a middle element and diff terraform state list — has to be run to land. It's the entire argument for for_each and it takes two applies. |
| Locals | The timestamp() perpetual-diff experiment needs a real second plan to be convincing; a config that can never converge is a strange thing to take on trust. |
| Validation and sensitive values | grepping your own "secret" out of terraform.tfstate in plaintext is the moment sensitive = true stops sounding like encryption. Worth doing once, locally, where the secret is fake. |
| Provisioners and archive_file | Lowest priority — the triggers re-run behaviour is the only part that needs observing, and provisioners are a pattern to recognise rather than adopt. |
Conventions¶
- One directory per concept, numbered in the order they were written — except
4-dependencies/, where one concept needs two roots side by side to contrast against each other. main.tffor resources,variables.tffor inputs — the same layout as02-gcp-terraform/and every root in the sandbox, so moving between them costs nothing..terraform/,terraform.tfstateand lock files are gitignored. Only the HCL is committed.
Start with Resources and state.