DEV Community

Cover image for Mastering Terraform Debugging: Tips and Techniques 🔧
Roman Geraskin
Roman Geraskin

Posted on • Originally published at rgeraskin.hashnode.dev

Mastering Terraform Debugging: Tips and Techniques 🔧

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)}"
  }
}
Enter fullscreen mode Exit fullscreen mode
❯ terraform test
main.tftest.hcl... in progress
  run "test"... pass
main.tftest.hcl... tearing down
main.tftest.hcl... pass

Success! 1 passed, 0 failed.
Enter fullscreen mode Exit fullscreen mode

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)