Debugging & CLI Configs

Sign Up to Build

About this Architecture

Here is some information about this architecture.

How to Build This Solution

Here are the steps you can follow to build this solution on your own.

In the lesson, you will learn how to debug Terraform and configure Terraform CLI.

When troubleshooting any problems in a Terraform configuration, logging and debugging are helpful toolsets. When a failure occurs, specifics about the type of failure, what caused it, and the time of the error are useful pieces of information that aid in root cause analysis and problem-solving. To assist you in resolving issues with your projects, Terraform offers a robust debugging feature.

How to Set Up Logging

Setting up logging for your projects is possible with Terraform's TF_LOG environment variable. The level of detail you want in your logs can be specified by setting the variable's value to the appropriate level.

Log levels

Although the TF_LOG environment variable accepts 6 values, the following 5 are the levels that specify the verbosity of the logs:

  1. TRACE: This is the most verbose level of Terraform logs. When you set the value of TF_LOG to TRACE (TF_LOG = "TRACE"), the log shows all the internal activities, outputs, and every step Terraform takes. The traces logging level allows you to gain visibility into all the activities that occur in your Terraform environment.

  2. DEBUG: This value describes all Terraform internal and provider activities like trace, but in a more concise way.

  3. ERROR: TF_LOG=”ERROR” omits the details and displays just the error(s) that prevented Terraform from executing successfully.

  4. WARN: This value logs warnings about incorrect configuration, mistakes, or negligence of recommended best practices, but such mistakes are not critical to execution.

  5. INFO: The Info level logs only a broad, high-level message about the Terraform execution.

The sixth value that the TF_LOG environment variable accepts is JSON. When you set TF_LOG to this value (TF_LOG="JSON"), Terraform generates activity logs at the TRACE level and outputs them in JSON format.

How to Narrow the Scope of TF_LOG

The standard TF_LOG environment variable produces both Terraform internal activities and provider activities logs. You might prefer to view the logs separately or just the ones that pertain to the provider's activities. Terraform allows you to achieve this through 2 variants of the TF_LOG environment variable:

  • TF_LOG_CORE

  • TF_LOG_PROVIDER

You can use any of the above variants in place of the default TF_LOG to generate logs that are specific to a scope. TF_LOG_CORE produces logs that are specific to Terraform internal activities. Likewise, TF_LOG_PROVIDER generates logs that are narrowed down to the provider's activities only.

Both TF_LOG_CORE and TF_LOG_PROVIDER accept the same values as the standard TF_LOG variable.

Setting a Log Path

TF_LOG_PATH environment variable allows you to persist the logs from TF_LOG. When you specify the path to a particular file as the value of the variable, Terraform will output your logs into that file.

$ export TF_LOG_PATH = “home/user/terraform-logs.txt/”

CLI Configuration File

Terraform offers a feature that enables you to customize the behavior of the CLI for your project. By using a CLI configuration file, you can adjust some default Terraform CLI settings and behaviors for each Terraform user.

On Windows, a terraform.rc file defines a Terraform CLI configuration; on Mac and Linux systems, a.terraformrc file does the same.

  • The terraform.rc file needs to be located in your %APPDATA% directory on Windows. While the location of the %APPDATA% directory may vary depending on system configuration and Windows version, you can view the directory's location by running the following PowerShell command:

$env:APPDATA
  • On macOS and other operating systems, you must store the .terraformrc file in your home directory.

Instead of manually storing the CLI configuration file in the appropriate directory, you can specify the location as the value of the TF_CLI_CONFIG_FILE environment variable.

Possible Settings in a CLI Configuration File

The following are the configurations you can set to alter the default CLI behaviors:

CREDENTIALS

When utilizing Terraform-specific network services, such as modules registry, in your main configurations, you must enter your Terraform Cloud or Terraform Enterprise credentials for the service to function. You can provide these details by adding a credentials block in your CLI configuration file:

credentials "<host-name>" {
    token = "xxxxxx.atlasv1.zzzzzzzzzzzzz"
}

The <host-name> label of the credentials block specifies which Terraform host you're connecting to. It can take one of two values: “app.terraform.io” for Terraform Cloud or “atlas.hashicorp.com” for Terraform Enterprise. The token argument specifies your API token for that host. If you use services from multiple hosts in your configuration file, you can create multiple credentials blocks with the host names and tokens as appropriate.

As an alternative to writing it directly to the CLI configuration file, you can also supply the credentials in the ways listed below:

  • Environment Variable Credentials: As a security measure, you may choose to not store your API token in the CLI configuration. Instead, you can provide the credentials through the TF_TOKEN_ environment variable as written below:

$ export TF_TOKEN_app_terraform_io

  • Credentials Helpers: A credential helper is an executable program that is installed in a particular location and whose name follows a specific naming convention. You can create a credentials_helper block to tell Terraform to store credentials differently, using the credential helper program.

credentials_helper "example" {
    args = []
}

Terraform gives credentials supplied via environment variables the highest preference, followed by the one in the credentials block of the CLI configuration file. Terraform will only default to the credential helper if none of the former are specified.

PROVIDER INSTALLATION

By default, Terraform downloads and installs provider plugins from the remote provider registry. This behavior is not always desirable because, for instance, it will prevent Terraform from installing the plugins if the system that runs Terraform is unable to access the Terraform registry because of local firewall restrictions. The following alternatives let you change this default:

  • Explicit installation: By using the provider_installation block, you can specifically direct Terraform to install any required provider plugins from the registry or a local system's directory:

provider_installation {
filesystem_mirror {
    path    = "/usr/share/terraform/providers"
    include = ["example.com/*/*"]
 }
 direct {
    exclude = ["example.com/*/*"]
  }
}

  • Implied Local Mirror: This option enables you to install provider plugins using both the filesystem_mirror and direct methods in sequence.

provider_installation {
    filesystem_mirror {
     path = "/usr/share/terraform/providers"
     include = ["example.com/*/*"]
    }
    direct {
     exclude = ["example.com/*/*"]
    }
}

PROVIDER PLUGIN CACHE

By default, Terraform automatically downloads and installs all necessary plugins directly from the registry for each Terraform project you are working on. If you're working on multiple Terraform projects from the same machine and have a slow or metered internet connection, this behavior might not be ideal. By utilizing the plugin_cache_dir block as in the example below, Terraform will check the local plugin file to install any necessary plugins and will only fall back to the default of fetching from the registry if the plugin cannot be found in the cache.

plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"

DEVELOPMENT OVERRIDES

Using dev_overrides, you can discourage Terraform from checking for version when running a configuration when you’re running a configuration for test reasons.

dev_overrides {
  "hashicorp/null" = "/home/developer/tmp/terraform-null"
}

Lab Time!

In this lab, you will set up debugging in a Terraform project.

Get Your AWS Credentials

If you're using the Skillmix Labs feature, open the lab settings (the beaker icon) on the right side of the code editor. Then, click the Start Lab button to start hte lab environment.

Wait for the credentials to load. Then run this in the terminal.

Be sure to enter in your own access key and secret key and name your profile 'smx-lab'.

$ aws configure --profile smx-lab
AWS Access Key ID [None]: 
AWS Secret Access Key [None]: 
Default region name [None]: us-west-2
Default output format [None]: 

Note: If you're using your own AWS account you'll need to ensure that you've created and configured a named AWS CLI profile named smx-lab.

Create New Terraform Project

First, create a new project directory, “terraform-debugging”, and create a new main.tf file inside of it. You can run the following commands on your command line:

#create project directory
$ mkdir terraform-debugging

#change to the newly created directory
$ cd terraform-debugging

#create config file
$ touch main.tf

Populate Configuration file

Next, we need to add our configuration. Open the main.tf file in your code editor and input the following code that creates an EC2 instance:

terraform {
  required_providers{
    aws = {
        source = "hashicorp/aws"
        version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}

#create EC2 instance
resource "aws_instance" "web_server" {
  ami = "ami-0c2ab3b8efb09f272"
  instance_type = "t2.micro"

  tags = {
    "Name" = "skillmix-lab-instance"
  }
}

Save the main.tf file and move on to the next step.

Set up Terraform Logging

We will set up logging in our project using the TRACE level because we want a detailed log. Open your command line and run the following commands:

#set logging to trace
$ export TF_LOG = "TRACE"

#specify the file to persist our logs
$ export TF_LOG_PATH = "my-skillmix.txt"

After setting the two environment variables, it's time to run the normal Terraform workflows:

#initialize terraform
$ terraform init

#generate a plan
$ terraform plan

#apply configuration
$ terraform apply

After applying the configuration, Terraform must have generated some logs. Inspect the newly created my-skillmix.txt file to view the logs.

Use CLI Logging to Verify Variables

When running Terraform in a collaborative environment, you may not want anyone using the configuration file to create specific services or types of services. You can define a condition and use Terraform logging to print an error message to the CLI if the condition is not met.

Modify main.tf file

Insert the following code in at the end of your main.tf file:

variable "instance_type"{
    type = string
    default = "t2.large"
    validation {
      condition = can(regex("^[Tt][2.3].(nano/micro).", var.instance_type))
      error_message = "The instance type you entered is not allowed. Please choose one of: t2.nano or t2.micro"
    }
  }

Also, inside the instance resource block, change the type argument to var.instance_type.

Your main.tf file should now look like this:

terraform {
  required_providers{
    aws = {
        source = "hashicorp/aws"
        version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}

#create EC2 instance
resource "aws_instance" "web_server" {
  ami = "ami-0c2ab3b8efb09f272"
  instance_type = var.instance_type

  tags = {
    "Name" = "skillmix-lab-instance"
  }
}

variable "instance_type"{
    type = string
    default = "t2.large"
    validation {
      condition = can(regex("^[Tt][2].(nano/micro).", var.instance_type))
      error_message = "The instance type you entered is not allowed. Please choose one of: t2.nano or t2.micro"
    }
  }

The variable block declares a variable for our instance type, with a condition that checks whether the instance type is set to t2.micro or t2.nano. If not, Terraform logs the error message we specified. Since we set the default value of instance_type to “t2.large”, this configuration should run into an error and display our error message on the CLI.

Next, apply the configuration:

# apply the config
$ terraform apply

The CLI log of the error will look like this:

│ Error: Invalid value for variable
│
│   on main.tf line 24:
│   24:   variable "instance_type"{
│     ├────────────────
│     │ var.instance_type is "t2.large"
│
│ The instance type you entered is not allowed. Please choose one of: t2.nano or
│ t2.micro

Congratulations, you now understand how to enable debugging in your Terraform project and also generate CLI logs based on certain conditions.