Adding custom pre and postconditions
In a previous recipe, Manipulating variables, we learned that it is possible to add condition validation inside the variable definition.
In Terraform version 1.2 and newer, it’s possible to add custom validation directly in resources, modules, or data sources with preconditions and postconditions.
These customs validations allow Terraform to set some custom rules during the execution of terraform plan
. The precondition will be checked just before the rendering of the plan and the postcondition will be checked just after the rendering.
Let’s get started!
Getting ready
To complete this recipe, we will start with this basic Terraform configuration:
resource "azurerm_virtual_network" "vnet" {
name = "vnet"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = [var.address_space]
}
The above Terraform configuration creates an Azure virtual network.
The first check that we want to perform is to be sure that the address_space
variable’s value is IP mask /16
.
The second check is to verify that the region (location
) of the virtual network is "westeurope"
.
The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/prepostcond.
How to do it…
The following step shows you how to perform the first check, which is the verification of the IP address range:
- Update the Terraform configuration of the Azure virtual network with the code below:
resource "azurerm_virtual_network" "vnet" { ….. address_space = [var.address_space] lifecycle { precondition { condition = cidrnetmask(var.address_space) == "255.255.0.0" error_message = "The IP Range must be /16" } } }
- Then, add the second check to verify the location by adding this configuration in the Azure virtual network:
resource "azurerm_virtual_network" "vnet" { name = "vnet" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name address_space = [var.address_space] lifecycle { precondition { condition = cidrnetmask(var.address_space) == "255.255.0.0" error_message = "The IP Range must be /16" } postcondition { condition = self.location == "westeurope" error_message = "Location must be westeurope" } } }
- Finally, run the Terraform workflow and check that no Terraform error is displayed in the console output.
How it works…
In Step 1, we added the first custom check, which corresponds to the precondition that will be run just before the plan. The precondition
block is new inside the lifecycle
block metadata. Let’s see this precondition in detail:
precondition {
condition = cidrnetmask(var.address_space) == "255.255.0.0"
error_message = "The IP Range must be /16"
}
The precondition
block contains two properties:
- The
condition
, that is, the code for the check. Here, we check that thecidrmask
of the value of theaddress_mask
variable is equal to “255.255.0.0"
, that is, that the IP range is/16
. - The
error_message
, that is, the error message that is displayed in the console output if the check returnsfalse
.
To test this precondition, if we set the value of the address_space
variable to "10.0.0.0/24"
, the terraform plan
execution returns this output:
Figure 2.18: Precondition custom validation error
The error message is displayed and the terraform plan
command doesn’t continue.
Then in Step 2, we add the check for testing the region (the data center’s location) of the Azure virtual network, which must be equal to “westeurope
". To do this, we add a postcondition
block inside the lifecycle
metadata with the following configuration:
postcondition {
condition = self.location == "westeurope"
error_message = "Location must be West Europe"
}
In the configuration above, we set the condition
property by using the self
keyword to refer to the current resource (in this case this is the Azure virtual network) and we set the error message.
Note that the self
keyword can be used only on postconditions, at the moment that all properties are determined, which is only after the terraform plan
command has been run.
To test this postcondition
, we set the location to "westus"
and we get this terraform plan
output:
Figure 2.19: Postcondition custom validation error
We can see that the error message is displayed.
See also
- The documentation of the pre- and postconditions is available at https://www.terraform.io/language/meta-arguments/lifecycle#custom-condition-checks.
- Here’s a tutorial on pre- and postconditions on modules: https://learn.hashicorp.com/tutorials/terraform/custom-conditions.
- Here’s a blog post about pre and postconditions: https://spacelift.io/blog/terraform-precondition-postcondition.
- Ned Bellavance’s video on pre and postconditions is available here: https://www.youtube.com/watch?v=55ZLu8tSnvk.