There is a wealth of information available about Terraform and the various tools within the Terraform ecosystem. However, there seems to be a noticeable gap when it comes to resources on debugging techniques specific to Terraform.
Let's address this issue and expand the knowledge base to include detailed debugging methods.
Terraform Console
The built-in Terraform feature can make your life much simpler. It's often been avoided by engineers and is not so popular in blogs.
What can you do with the console? Basically, it can be used not only to show info about a resource in a state.
1. Drop state info
When you run terraform console
in a Terraform project directory, it tries to use the state information to get actual details. It's useful for getting information about created resources or data objects.
But it sometimes slows down the debugging process. For example, if you place your state in an S3 bucket, it fetches it first. Tools like terraform-repl
run terraform console
under the hood for every command, making the process really slow. Also, console
sets a lock on the state while you work with it.
To work with console
without an S3 state, you can comment out the Terraform backend
section, remove the .terraform
folder, and rerun terraform init
.
2. Test your expressions
Often we have to convert data between various formats to meet the requirements of module interfaces or for other cases. And we usually do it blindly, evaluating complicated expressions in our minds only. That leads to unexpected issues in some corner cases.
Just test it:
> coalesce(["", "b"]...)
b
Yes, it's a simple example from the tf docs, but you can use console
for much more complicated things.
Did you know that terraform console can be launched not only in a directory with a terraform project? To test expressions, you can start it in any directory.
3. Define your own locals
interactively
One of the common drawbacks of terraform console is that it doesn't allow you to set your own variables or locals. To compose a complicated expression, it's handy to use intermediate local variables.
To make it possible, you can use terraform console wrappers such as terraform-repl. It also adds a tab-completion feature.
> local.a=1
> local.a+1
2
By using the local
command, you can display all local variables.
There is another tool called tfrepl with similar functionality. However, it doesn't have tab-completion, and it can't show all of your defined locals
.
4. Debug your modules
Modules are the way to keep your tf code DRY. But it's a pain in the neck when you debug and refactor it. Use console tools to make it simpler.
If you have default values for your variables defined, just run terraform console
or terraform-repl
to debug expressions.
If you have no default values, it's safe to place terraform.tfvars
just inside the module folder. Terraform will ignore these vars when this module is used somewhere in a parent project.
5. Test your modules
The practice of testing Terraform code is not widely used in the infrastructure world. Actually, I've never seen tests in any single company :)
Personally, I don't see any significant benefit from tests in the way they are meant to be used. See this example from the official docs: the test checks if the bucket's name is created as expected.
Do we really need it? We just use the variable in the bucket name, so it's obvious that nothing will happen to it later!
But we can use tests to make sure that we will not break a module's 'interface' sometime in the future while refactoring. Just write a test and do anything with local expressions and variables.
Stupid simple test example:
# main.tftest.hcl
run "test" {
command = plan
assert {
condition = jsonencode(local.users) == jsonencode({
"john" = {
"grants" = null
"login" = true
"member_of" = [
"admin",
]
"password_enabled" = false
}
})
error_message = "Wrong format of local.users : ${jsonencode(local.users)}"
}
}
❯ terraform test
main.tftest.hcl... in progress
run "test"... pass
main.tftest.hcl... tearing down
main.tftest.hcl... pass
Success! 1 passed, 0 failed.
Again, if you already have default values in your variables.tf
, you are ready to use tests. If you don't, place terraform.tfvars
as stated above.
I don't recommend placing variables inside *.tftest.hcl
in simple cases because you will not be able to use those variables with console
later. Also, avoid complicated tests. Simple tests are easier to support. So, there is a chance that they will be supported in the future at least.
Testing expressions is the way to be confident that you will have the expected value in your resource property.
Conclusion
I shared a few tricks on debugging Terraform expressions. Do you have any to add? Share them in the comments.
Top comments (0)