Terraform preconditions offer you a way to enforce conditions and even rules before creating, updating or destroying your Terraform resources. By adding preconditions you are adding another “level” of checks to ensure that the Terraform resources you deploy align with specific criteria, further adding reliability and reducing the risk of deployment issues
Understanding Terraform’s Lifecycle Block and Preconditions
Preconditions are added to the Terraform lifecycle block. This allows you to manage specific behaviours for each Terraform resource. In this case, it involves the preconditions you want to use.
A Simple Precondition Example
Lets look at a simple example to start. The below resource group is only to be deployed in Azure regions uksouth
or ukwest
. Lets add a precondition to ensure the the resource group is only possible to be deployed to the two locations:
resource "azurerm_resource_group" "tamopsrg" {
name = "tamops-rg"
location = var.location
lifecycle {
precondition {
condition = contains(["uksouth", "ukwest"], var.location)
error_message = "Location must be either 'uksouth' or 'ukwest'."
}
}
}
I have highlighted the Terraform lifecycle block above, notice the use of precondition
? With the condition
it must need along with the error_message
when the condition is not met.
A quick test, with the below variable that is an invalid location:
variable "location" {
description = "Location for the resources"
type = string
default = "West Europe"
}
We can see the Terraform precondition statement worked correctly, as the deployment has failed with the error_message: Location must be either 'uksouth' or 'ukwest'
% terraform plan
Planning failed. Terraform encountered an error while generating this plan.
╷
│ Error: Resource precondition failed
│
│ on main.tf line 7, in resource "azurerm_resource_group" "tamopsrg":
│ 7: condition = contains(["uksouth", "ukwest"], var.location)
│ ├────────────────
│ │ var.location is "West Europe"
│
│ Location must be either 'uksouth' or 'ukwest'.
Benefits of Using Terraform Preconditions
Like any sort of precondition, there are benefits. I have summarised 5 benefits to explain why you may want to use Terraform preconditions in your configuration.
- Consistency: Another enabler tool to ensure consistency and set standards are enforced across your deployments
- Error Prevention: Catch any potential configuration errors early in your deployment
- Compliance: Helps to maintain compliance by enforcing specific standards and/or rules
- Cost Control: Another enabler for cost controlling, preventing the creation of over-sized resources
- Documentation: An interesting one, preconditions can also act as self-serving documentation
Best Practices for Preconditions in Azure
- Keep It Simple: Keep those preconditions as simple as possible! Create concise conditions that are easy to understand and maintain
- Use Variables: Use Terraform variables to make preconditions flexible and reusable
- Combine with Data Sources: Along with variables for flexibility configurations, also look at using Terraform data sources to create dynamic preconditions based on existing resources
- Test thoroughly: Ensure all preconditions work as expected
- Document those preconditions: You may want to document preconditions, within your documentation library
More advanced preconditions
What makes the likes of Terraform great, is that you can work with even more advanced preconditions, lets look at a few
Using Multiple Preconditions
Thats right, you can define multiple preconditions within the same lifecycle block:
resource "azurerm_resource_group" "tamopsrg" {
name = var.rg_name
location = var.location
lifecycle {
precondition {
condition = contains(["uksouth", "ukwest"], var.location)
error_message = "Location must be either 'uksouth' or 'ukwest'."
}
precondition {
condition = contains(["tamops-rg"], var.rg_name)
error_message = "RG name must be tamops-rg'."
}
}
}
Using Terraform Functions in your Preconditions
Terraform functions can also be used as part of your precondition. Lets look at using cidrsubnet
to ensure the subnet being used for Azure Virtual Network creation is at least /24
resource "azurerm_virtual_network" "tamopsvnet" {
name = "${var.rg_name}-vnet"
address_space = [var.vnet_address_space]
location = azurerm_resource_group.tamopsrg.location
resource_group_name = azurerm_resource_group.tamopsrg.name
lifecycle {
precondition {
condition = cidrsubnet(var.vnet_address_space, 8, 0) != ""
error_message = "The VNet address space must support at least 256 addresses."
}
}
}
Wrapping up
Integrating preconditions into your Terraform configurations for Azure resources adds valuable validation, preserving the integrity of your infrastructure. As your Terraform practices evolve, consider using preconditions for more complex validations and integrations across your resources. However, be mindful of overuse, as too many checks can complicate configurations, making them harder to manage.
GitHub repository containing example above