Posted: Wednesday, November 13, 2024
Word Count: 1682
Reading Time: 8 minutes
Conditional statements in Terraform enable users to define infrastructure with flexibility, allowing for configurations that adapt based on environment variables, user inputs, or other conditions. In this article, we’ll explore how to use conditional expressions in Terraform, with practical examples to illustrate their power.
In Terraform, a conditional expression allows you to define values that depend on a condition. This is similar to the “if-else” logic in more traditional programming. The syntax follows a ternary form, where you provide a condition, a true value, and a false value.
The syntax looks like this:
<condition> ? <value_if_true> : <value_if_false>
Here, the condition is evaluated, and if it’s true
, the expression returns value_if_true
; otherwise, it returns value_if_false
.
Let’s start with a basic example that determines whether to enable a certain feature. Suppose you want to enable a monitoring resource only in a production environment. You can use a variable to define the environment and conditionally deploy the resource.
provider "azurerm" {
features {}
subscription_id = var.subscription_id
}
variable "environment" {
type = string
default = "dev"
}
resource "azurerm_log_analytics_workspace" "monitoring" {
count = var.environment == "prod" ? 1 : 0
name = "${lower(var.environment)}-log-workspace"
location = "East US"
resource_group_name = azurerm_resource_group.main.name
sku = "PerGB2018"
}
resource "azurerm_resource_group" "main" {
name = "example-resources"
location = "East US"
}
Bits and That Technology BlogIn this example:
var.environment
is set to "prod"
, the count
attribute for azurerm_log_analytics_workspace
becomes 1
, creating the resource.var.environment
is "dev"
or anything else, count
is 0
, and Terraform skips creating the resource.TERRAFORM PLAN OUTPUT IF VARIABLE IS CHANGED TO PROD
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_log_analytics_workspace.monitoring[0] will be created
+ resource "azurerm_log_analytics_workspace" "monitoring" {
+ allow_resource_only_permissions = true
+ daily_quota_gb = -1
+ id = (known after apply)
+ internet_ingestion_enabled = true
+ internet_query_enabled = true
+ local_authentication_disabled = false
+ location = "eastus"
+ name = "prod-log-workspace"
+ primary_shared_key = (sensitive value)
+ resource_group_name = "example-resources"
+ retention_in_days = (known after apply)
+ secondary_shared_key = (sensitive value)
+ sku = "PerGB2018"
+ workspace_id = (known after apply)
}
# azurerm_resource_group.main will be created
+ resource "azurerm_resource_group" "main" {
+ id = (known after apply)
+ location = "eastus"
+ name = "example-resources"
}
Plan: 2 to add, 0 to change, 0 to destroy.
Conditionals also shine when defining variable values based on other variables. For instance, you may want to choose different machine sizes based on the environment.
provider "azurerm" {
features {}
subscription_id = var.subscription_id
}
variable "subscription_id" {
default = "<Enter your Subcription Id>"
}
variable "environment" {
type = string
default = "dev"
}
variable "storage_sku" {
type = string
default = var.environment == "prod" ? "Standard_GRS" : "Standard_LRS"
}
resource "azurerm_storage_account" "example" {
name = "examplestorageacct${random_integer.suffix.result}"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
account_tier = "Standard"
account_replication_type = var.storage_sku
tags = {
environment = var.environment
}
}
resource "azurerm_resource_group" "main" {
name = "example-resources"
location = "East US"
}
resource "random_integer" "suffix" {
min = 10000
max = 99999
}
Bits and That Technology BlogIn this example:
var.environment
is set to "prod"
, the storage_sku
variable is assigned "Standard_GRS"
, enabling Geo-Redundant Storage suitable for production environments.var.environment
is "dev"
or anything else, storage_sku
defaults to "Standard_LRS"
, which uses Locally Redundant Storage and is a more cost-effective option for development environments.TERRAFORM PLAN OUTPUT - SINCE DEV WAS SELECTED LRS WAS IS DESIGNATED AS THE REPLICATION TYPE
# azurerm_resource_group.main will be created
+ resource "azurerm_resource_group" "main" {
+ id = (known after apply)
+ location = "eastus"
+ name = "example-resources"
}
# azurerm_storage_account.example will be created
+ resource "azurerm_storage_account" "example" {
+ access_tier = (known after apply)
+ account_kind = "StorageV2"
+ account_replication_type = "LRS"
+ account_tier = "Standard"
+ allow_nested_items_to_be_public = true
+ cross_tenant_replication_enabled = false
+ default_to_oauth_authentication = false
+ dns_endpoint_type = "Standard"
+ https_traffic_only_enabled = true
+ id = (known after apply)
+ infrastructure_encryption_enabled = false
+ is_hns_enabled = false
+ large_file_share_enabled = (known after apply)
+ local_user_enabled = true
+ location = "eastus"
+ min_tls_version = "TLS1_2"
+ name = (known after apply)
+ nfsv3_enabled = false
+ primary_access_key = (sensitive value)
+ primary_blob_connection_string = (sensitive value)
+ primary_blob_endpoint = (known after apply)
+ primary_blob_host = (known after apply)
+ primary_blob_internet_endpoint = (known after apply)
+ primary_blob_internet_host = (known after apply)
+ primary_blob_microsoft_endpoint = (known after apply)
+ primary_blob_microsoft_host = (known after apply)
+ primary_connection_string = (sensitive value)
+ primary_dfs_endpoint = (known after apply)
+ primary_dfs_host = (known after apply)
+ primary_dfs_internet_endpoint = (known after apply)
+ primary_dfs_internet_host = (known after apply)
+ primary_dfs_microsoft_endpoint = (known after apply)
+ primary_dfs_microsoft_host = (known after apply)
+ primary_file_endpoint = (known after apply)
+ primary_file_host = (known after apply)
+ primary_file_internet_endpoint = (known after apply)
+ primary_file_internet_host = (known after apply)
+ primary_file_microsoft_endpoint = (known after apply)
+ primary_file_microsoft_host = (known after apply)
+ primary_location = (known after apply)
+ primary_queue_endpoint = (known after apply)
+ primary_queue_host = (known after apply)
+ primary_queue_microsoft_endpoint = (known after apply)
+ primary_queue_microsoft_host = (known after apply)
+ primary_table_endpoint = (known after apply)
+ primary_table_host = (known after apply)
+ primary_table_microsoft_endpoint = (known after apply)
+ primary_table_microsoft_host = (known after apply)
+ primary_web_endpoint = (known after apply)
+ primary_web_host = (known after apply)
+ primary_web_internet_endpoint = (known after apply)
+ primary_web_internet_host = (known after apply)
+ primary_web_microsoft_endpoint = (known after apply)
+ primary_web_microsoft_host = (known after apply)
+ public_network_access_enabled = true
+ queue_encryption_key_type = "Service"
+ resource_group_name = "example-resources"
+ secondary_access_key = (sensitive value)
+ secondary_blob_connection_string = (sensitive value)
+ secondary_blob_endpoint = (known after apply)
+ secondary_blob_host = (known after apply)
+ secondary_blob_internet_endpoint = (known after apply)
+ secondary_blob_internet_host = (known after apply)
+ secondary_blob_microsoft_endpoint = (known after apply)
+ secondary_blob_microsoft_host = (known after apply)
+ secondary_connection_string = (sensitive value)
+ secondary_dfs_endpoint = (known after apply)
+ secondary_dfs_host = (known after apply)
+ secondary_dfs_internet_endpoint = (known after apply)
+ secondary_dfs_internet_host = (known after apply)
+ secondary_dfs_microsoft_endpoint = (known after apply)
+ secondary_dfs_microsoft_host = (known after apply)
+ secondary_file_endpoint = (known after apply)
+ secondary_file_host = (known after apply)
+ secondary_file_internet_endpoint = (known after apply)
+ secondary_file_internet_host = (known after apply)
+ secondary_file_microsoft_endpoint = (known after apply)
+ secondary_file_microsoft_host = (known after apply)
+ secondary_location = (known after apply)
+ secondary_queue_endpoint = (known after apply)
+ secondary_queue_host = (known after apply)
+ secondary_queue_microsoft_endpoint = (known after apply)
+ secondary_queue_microsoft_host = (known after apply)
+ secondary_table_endpoint = (known after apply)
+ secondary_table_host = (known after apply)
+ secondary_table_microsoft_endpoint = (known after apply)
+ secondary_table_microsoft_host = (known after apply)
+ secondary_web_endpoint = (known after apply)
+ secondary_web_host = (known after apply)
+ secondary_web_internet_endpoint = (known after apply)
+ secondary_web_internet_host = (known after apply)
+ secondary_web_microsoft_endpoint = (known after apply)
+ secondary_web_microsoft_host = (known after apply)
+ sftp_enabled = false
+ shared_access_key_enabled = true
+ table_encryption_key_type = "Service"
+ tags = {
+ "environment" = "dev"
}
+ blob_properties (known after apply)
+ network_rules (known after apply)
+ queue_properties (known after apply)
+ routing (known after apply)
+ share_properties (known after apply)
}
# random_integer.suffix will be created
+ resource "random_integer" "suffix" {
+ id = (known after apply)
+ max = 99999
+ min = 10000
+ result = (known after apply)
}
Plan: 3 to add, 0 to change, 0 to destroy.
In more advanced cases, you might need to use multiple conditions. Terraform conditionals can be nested or combined with logical operators like &&
(and) and ||
(or).
provider "azurerm" {
features {}
subscription_id = var.subscription_id
}
variable "subscription_id" {
default = "<Enter your Subcription Id>"
}
variable "environment" {
type = string
default = "dev"
}
variable "region" {
type = string
default = "us-east-1"
}
variable "use_ha" {
type = bool
default = false
}
output "service_url" {
value = var.environment == "prod" && var.region == "us-east-1" && var.use_ha ? "https://prod-ha.example.com" : "https://standard.example.com"
}
Bits and That Technology BlogIn this example:
var.environment
is set to "prod"
, var.region
is "us-east-1"
, and var.use_ha
is true
:
service_url
is assigned "https://prod-ha.example.com"
, which represents a high-availability service URL specifically for production in the "us-east-1"
region.var.environment
is "dev"
, var.region
is something other than "us-east-1"
, or var.use_ha
is false
):
service_url
defaults to "https://standard.example.com"
, representing a standard service URL for non-production or lower availability configurations.TERRAFORM PLAN OUTPUT
Changes to Outputs:
+ service_url = "https://standard.example.com"
Although conditionals offer flexibility, overusing them can lead to complex and hard-to-read configurations. If you find yourself nesting too many conditionals, consider refactoring your code or breaking it down into simpler, modular components.
<condition> ? <value_if_true> : <value_if_false>
Mastering conditionals in Terraform can make your configurations more efficient, adaptable, and cost-effective. Whether you’re deploying resources conditionally or selecting variable values based on environment contexts, these expressions are powerful tools in any Terraform practitioner’s toolkit.
Leave a Reply