Orlando Thöny
Orlando's Blog

Orlando's Blog

How to debug in Terraform

How to debug in Terraform

Orlando Thöny's photo
Orlando Thöny
·Mar 9, 2021·

4 min read

Terraform (currently) does not provide any functionality that could be compared to a var_dump() function like the PHP programming language has it for example. Or a debugger of any kind. However, there are a few options to get more insights about what a Terraform module is doing.

terraform console

Terraform provides a terraform console command (docs). It can be used to test/try out expressions, read values from a module, or scripting.

Usage

Run terraform console in the directory of the module that you want to debug. Pass the -var-file option if you are using a non-standard variable file location. For example terraform console -var-file=./config/dev.tfvars.

You can print the values of resources, module outputs, locals & data.

Note that it is not possible to print the values of locals, resources & data which are declared inside a child module. To be able to view them, you need to declare an output for the desired object in the child module, which makes these values available to the parent module.

For addressing the objects, use Resource Addresses.

Usage example

Let’s assume we have a root module, which calls the cloud_storage child module. That module creates two Google Storage Buckets, and defines them as an output.

Let's see how we can find out what the content of that output is. Usually, to be able to see the output of a child module, we would have to "bubble it up", meaning also declaring an output in the root module, which in turn uses the child module output as value.

Our root module’s main.tf:

// ...

module "cloud_storage" {
  source = "../modules/cloud_storage"

  environment    = var.environment
  project        = var.project
  default_labels = local.default_labels
}

cloud_storage module main.tf:

locals {
  bucket_configs = {
    {
      foo : {
        name : "foo-files", retention_days : 3, location : "europe-west4", storage_class : "STANDARD"
      },
      bar : {
        name : "bar-files", retention_days : 1, location : "europe-west6", storage_class : "COLDLINE"
    }
  }
}

resource "google_storage_bucket" "buckets" {
  for_each      = local.bucket_configs
  provider      = google-beta
  name          = each.value.name
  location      = each.value.location
  force_destroy = true
  uniform_bucket_level_access = false
  public_access_prevention    = "enforced"
  storage_class               = each.value.storage_class
  labels                      = var.default_labels

  versioning {
    enabled = true
  }

  dynamic "lifecycle_rule" {
    for_each = each.value.retention_days[*]
    content {
      condition {
        age = each.value.retention_days
      }

      action {
        type = "Delete"
      }
    }
  }
}

cloud_storage module outputs.tf:

// This is what we want to investigate
output "buckets" {
  value = google_storage_bucket.buckets[*]
}
Printing buckets

Run the console inside the root module’s directory:

terraform console
// We are now basically "inside" the root module, and can access all the variables/resources it has direct access to.

Print the value of the buckets output that is defined by the cloud_storage module.

> module.cloud_storage.buckets

This will output something like this:

[
  {
    "foo" = {
      "cors" = tolist([])
      "default_event_based_hold" = false
      "encryption" = tolist([])
      "force_destroy" = true
      "id" = "foo-files"
      "labels" = tomap({
        "environment" = "dev"
        "managed-by" = "tf-module--main"
      })
      "lifecycle_rule" = tolist([
        {
          "action" = toset([
            {
              "storage_class" = ""
              "type" = "Delete"
            },
          ])
          "condition" = toset([
            {
              "age" = 3
              "created_before" = ""
              "custom_time_before" = ""
              "days_since_custom_time" = 0
              "days_since_noncurrent_time" = 0
              "matches_storage_class" = tolist([])
              "noncurrent_time_before" = ""
              "num_newer_versions" = 0
              "with_state" = "ANY"
            },
          ])
        },
      ])
      "location" = "EUROPE-WEST4"
      "logging" = tolist([])
      "name" = "foo-files"
      "project" = "my-gcp-project"
      "public_access_prevention" = "enforced"
      "requester_pays" = false
      "retention_policy" = tolist([])
      "self_link" = "https://www.googleapis.com/storage/v1/b/foo-files"
      "storage_class" = "STANDARD"
      "timeouts" = null /* object */
      "uniform_bucket_level_access" = false
      "url" = "gs://foo-files"
      "versioning" = tolist([
        {
          "enabled" = true
        },
      ])
      "website" = tolist([])
    }
    "bar" = {
      "cors" = tolist([])
      "default_event_based_hold" = false
      "encryption" = tolist([])
      "force_destroy" = true
      "id" = "bar-files"
      "labels" = tomap({
        "environment" = "dev"
        "managed-by" = "tf-module--main"
      })
      "lifecycle_rule" = tolist([
        {
          "action" = toset([
            {
              "storage_class" = ""
              "type" = "Delete"
            },
          ])
          "condition" = toset([
            {
              "age" = 1
              "created_before" = ""
              "custom_time_before" = ""
              "days_since_custom_time" = 0
              "days_since_noncurrent_time" = 0
              "matches_storage_class" = tolist([])
              "noncurrent_time_before" = ""
              "num_newer_versions" = 0
              "with_state" = "ANY"
            },
          ])
        },
      ])
      "location" = "EUROPE-WEST6"
      "logging" = tolist([])
      "name" = "bar-files"
      "project" = "my-gcp-project"
      "public_access_prevention" = "enforced"
      "requester_pays" = false
      "retention_policy" = tolist([])
      "self_link" = "https://www.googleapis.com/storage/v1/b/bar-files"
      "storage_class" = "COLDLINE"
      "timeouts" = null /* object */
      "uniform_bucket_level_access" = false
      "url" = "gs://bar-files"
      "versioning" = tolist([
        {
          "enabled" = true
        },
      ])
      "website" = tolist([])
    }
  },
]
 
Share this