Terraform

Terraform Validate Command – Validate Configuration Locally

terraform validate

Terraform is an Infrastructure as Code tool that helps us manage the infrastructure lifecycle via code. Terraform uses HCL (Hashicorp Configuration Language) to configure the target infrastructure requirements.

Once the infrastructure is configured, Terraform downloads the required plugins from the registry which are then used to call respective cloud platform APIs to provision the target state. While doing so, Terraform also records the mapping between the configuration and the resources created in a state file.

The state file is either stored locally or on a remote backend. However, while working with teams remote backend is always preferred. The state file provides crucial information about the infrastructure components being managed via Terraform. Terraform uses this information to perform subsequent operations.

Every time a plan or apply command is run, Terraform queries the state file for validation purposes and then determines the operations to be performed based on the change in config. However, if we want to validate the syntax of the configuration included in Terraform file locally – in other words, without any remote interaction – then we can use validate command to do the same.

This post will dive deep into understanding the Terraform validate command.

Difference between plan and validate

If you have managed infrastructure using Terraform, then you must have used the plan and apply commands to execute the changes defined in the configuration files. As the name suggests, apply applies to the configuration. Meaning that once the apply command is executed, the changes begin to take effect.

We use the plan command to validate the changes that will be applied using the apply command. Terraform plan command helps us identify exactly which resources will be created, replaced, changed, or destroyed without actually executing them. Additionally, the output of the plan command can be saved and used during apply command.

Apart from validation, with the help of modes and various options, the output of the plan command is used to manage infrastructure in a targetted manner. The plan, thus generated, is input to the apply command for the same.

All the actions performed by the plan command make use of various API calls to the remote state files and cloud platform APIs since it needs to get the latest information on the state and real-world deployments. The purpose of the plan command is to validate the changes in the configuration and highlight the same by referencing remote state and cloud resources.

The validate command, on the other hand, is used to validate the configuration internally i.e., locally on the host system. Its focus is on validating the Terraform configuration files for syntax and internal consistencies.

Thus, validate command does not depend on any state file or information regarding deployed command. It is recommended to use this command to validate the consistencies between reusable modules in a given Terraform configuration directory.

Usage

To understand the validate command usage, let us consider the Terraform configuration below, which creates a standalone EC2 instance. This configuration makes use of a few input variables for AMI, instance type, and tag value.

// Standalone EC2 instance
resource "aws_instance" "my_vm" {
 ami           = var.ami //Ubuntu AMI
 instance_type = var.instance_type
 
 tags = {
   Name = var.name_tag,
 }
}
 
variable "ami" {
 type        = string
 description = "Ubuntu AMI ID in N. Virginia Region"
 default     = "ami-065deacbcaac64cf2"
}
 
variable "instance_type" {
 type        = string
 description = "Instance type"
 default     = "t2.micro"
}
 
variable "name_tag" {
 type        = string
 description = "Name of the EC2 instance"
 default     = "My EC2 Instance"
}

When we run terraform validate in the Terraform root directory, it simply outputs if the configuration is valid or not. For a valid configuration, the output is shown below.

terraform valid configuration

However, if the configuration is invalid, it provides us with the details as shown in the below screenshot. I purposely changed the reference to the variable “name_tag” to “nametag” to cause the below error message. The details include:

  1. File name
  2. Line of code that causes the error
  3. Summary of the error message
  4. Details
terraform invalid configuration

The details are very helpful since they are self-explanatory.

The Terraform validate command comes with a couple of options. They are as follows:

  1. -json – outputs the error details in a JSON format. The output produced in JSON format is used as an input to another program which may trigger appropriate automation workflows or any associated program.
  2. -no-color – produces the output without any color.

Let us use the -no-color flag and observe the output in success and error cases. If you compare the output below to the ones above, it does not contain any word which is highlighted using colors. For example, “Success!” is not Green, and “Error:” is not Red.

terraform validate -no-color

-json is an important flag as it is used to chain this output into another application or supply this information to any other integrated system. When we use this flag to run the validate command for a valid configuration, it produces the below output.

terraform validate -json

The JSON thus produced, has a few attributes that describe the state of current validity of the Terraform configuration. The purpose of these attributes is detailed below.

  1. format_version – This is an attribute with a constant value of “1.0”. The value “1.0” indicates that the validity check is done against the compatibility promises made for Terraform v1.x.
  2. valid – A boolean value that indicates whether a given configuration is valid (true) or not (false). It is set as false when there is at least one validation error.
  3. error_count – Represents the number of errors identified in the given configuration during validation. Since there are no validation errors in the given configuration the value is set to 0.
  4. warning_count – This represents the number of warnings issued during the validate command run. Warnings do not invalidate the configuration, the “valid” flag is not set to false only for warnings. However, it represents the fact that the developers may have to resolve these warnings in the future.
  5. diagnostics – Diagnostics attribute is an array of nested JSON objects. Each object in this array includes the details of all the errors produced during a Terraform validate command run. To understand the details, let us break our Terraform configuration again, and observe the JSON output as below.
terraform validate -json attributes

When the Terraform configuration is invalid, the JSON output thus produced is represented in the above screenshot. As we can see, the valid attribute is set to false, error_count is 1, and there are no warnings. The details of the error are included in the diagnostics array of nested JSON objects. Each object has attributes that provide more details. These attributes are described below.

  1. severity – Indicates if this is an error or a warning.
  2. summary – A short summary of the error. This is useful to indicate the kind of error that was encountered. In this case, it indicates that an error occurred when referencing the undeclared input variable. This is expected since we changed the variable reference from name_tag to nametag in our config.
  3. detail – This attribute provides deeper textual details about the error. It also includes the referencing variable names and gives us more clarity about what is broken in the configuration. It also suggests if we meant to use a certain value. This is useful to address typos. However, if the mistyped referencing variable name is not close to any given input variable name, it would not suggest this fix. For example, if instead of changing name_tag to nametag, I change it to “tag_name_mistake”, then the difference in the output of the detail attribute can be seen here.
tag name mistake output
  1. range – This attribute is assigned a JSON object that helps us pinpoint the error in the configuration. It includes a filename that points to a file that causes this error. The start and end attributes define the line, column, and even the byte information of the origin of this validation error. By the nature of it, we can already see this information can be a crucial asset when we have further automated processing to be done.
  2. snippet – The snippet attribute contains more details about the code snippet in consideration. As compared to the range details, this is more human-readable and keeps certain values ready for producing a generic human-readable output.

As mentioned before, using -json flag option provides a possibility to pass this information in a machine-readable format to other systems. As an example, we need not look anywhere else but simply compare the output of terraform validate and terraform validate -json.

terraform validate output

Each word in the above output is created, formatted, and assembled based on the details present in the diagnostic attribute of the JSON output.

Conclusion

Terraform validate command is very useful in many cases.

  1. When we want to be sure about the internal consistencies of the developed configuration before using external information like state and deployed resources.
  2. When we want to use the output of validate command to pass this information to other applications.

One of the short-comings in the validate command is the fact that it cannot be used to perform custom validations defined on the input variables. It is possible to define our validation condition and corresponding error message when the conditions are not met by the supplied values.

Input variable validation offers guardrails for consistent configuration, but these conditions are not interpreted by the terraform validate command. These validation rules are validated during plan and apply.

We encourage you to also explore how Spacelift makes it easy to work with Terraform. If you need any help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this. It supports Git workflows, policy as code, programmatic configuration, context sharing, drift detection, and many more great features right out of the box. You can check it for free, by creating a trial account.

Manage Terraform Better with Spacelift

Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization, and many more.

Start free trial