Terraform is an infrastructure as code tool that helps us manage the infrastructure lifecycle via code. It 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 the Terraform file locally – in other words, without any remote interaction – then we can use the validate command to do this.
This post will explore the Terraform validate command.
The validate command in Terraform is used to verify the correctness of Terraform configuration files. It checks the syntax of the Terraform files, ensures the correct usage of attributes and values, and validates the configuration based on the core syntax of Terraform and also by checking all the providers in the code. By using this command, developers can catch and solve configuration errors before attempting to apply changes to the infrastructure.
Terraform validate
command is very useful in many cases, including:
- When we want to be sure about the internal consistencies of the developed configuration before using external information like state and deployed resources
- When we want to use the output of validate command to pass this information to other applications
One of the shortcomings 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
.
Terraform validate command options
The Terraform validate command has two options. They are:
-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.-no-color
– produces the output without any color.
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, which means 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 targeted manner. The plan, thus generated, is input to the apply command for this.
All the actions performed by the plan command use various API calls to the remote state files and cloud platform APIs because 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 these 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, the validate command does not depend on any state file or information regarding deployed commands. You should use this command to validate the consistencies between reusable modules in a given Terraform configuration directory.
Let’s consider different scenarios.
1. Validate single file
By default, when you are running terraform validate
, you will check the entire configuration in that directory.
If you want to focus on validating a single file the only way to do that is to have only one file in a directory. You will go to that directory and simply run:
terraform validate
2. Validate multiple configuration files
Terraform automatically validates all .tf and .tf.json files in the current directory. If you have multiple configuration files in the same directory and want to validate them all at once, run:
terraform validate /config_files_path
3. Validate command with module block
If there is a module in the configuration you want to validate, you don’t need to do anything special to verify if the module configuration is valid. Just navigate to the module directory and run:
terraform validate
To understand the validate command usage, let us consider the Terraform configuration below. This creates a standalone EC2 instance. and uses 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 whether the configuration is valid or not. For a valid configuration, the output is shown below.
However, if the configuration is invalid, it provides us with the details as shown in the screenshot below. I deliberately changed the reference to the variable “name_tag” to “nametag” to cause the error message below. The details include:
- File name
- Line of code that causes the error
- Summary of the error message
- Details
The details are very helpful since they are self-explanatory.
Run terraform validate
with -no-color flag
Let’s 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.
Run terraform validate
with -json flag
-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 output below.
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:
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.- 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.
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.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.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.
When the Terraform configuration is invalid, the JSON output thus produced is represented in the screenshot ablove. 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:
severity
– Indicates if this is an error or a warning.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 because we changed the variable reference from name_tag to nametag in our config.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.
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.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 enables us 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
.
Each word in the output above is created, formatted, and assembled based on the details present in the diagnostic attribute of the JSON output.
In this article, we learned how to use the Terraform validate command and saw how -no-color and -json flags change the output.
We encourage you also to 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.
Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.
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.