Complete guide to conditional If/Else statement in Terraform

If/Else statement in Terraform is much more powerful than you think. In this blog, I will explain how to use the If/Else conditional statement in Terraform effectively.

There are two opinions when it comes to the If/Else statement in Terraform

  • First one — Terraform doesn’t have an If/Else conditional statement
  • And the second one — Terraform provides If/Else conditional logic but you can’t do much with 

I kinda agree and at the same time, disagree with the second opinion.

Terraform provides conditional statement-type logic using Ternary Operators and there is so much you can do with it.


If/Else statement syntax in Terraform

condition ? true_val : false_val

The above statement means if the given condition is true, use true_val else use false_val

Let’s take the below example of creating vpc network in google cloud


locals {
use_local_name = false
name = "main-vpc"
}

resource "google_compute_network" "base-vpc" {
name = local.use_local_name ? local.name : 'base-vpc'
auto_create_subnetworks = false
}

In the above example, i am using checking if the local variable use_local_name is true, if the condition is met then use the local.name as the name of the VPC, else use the name ‘base-vpc’


Let me show where we can use this If/Else conditional logic to make our terraform code more flexible.

Conditional Attribute Assignment

resource "aws_instance" "example" {
instance_type = var.environment == "production" ? "t2.large" : "t2.micro"
# Additional resource configuration
}

In the above example, we can define the instance type to use as per the environment type while creating an aws instance. If it’s production, use ‘t2.large’ else use “t2.micro”.

To replace invalid values

variable "namespace"{
type = string
}

resource "kubernetes_namespace" "this" {
metadata {
name = var.namespace != "" ? var.namespace : "my-namespace"
}
}

In the above example, we check if the value provided for the variable namespace is an empty string, if it is, then it will assume the value “my-namespace”

Dynamic resource creation

Suppose you want to create an AWS instance only when it is explicitly told to do so. We can use the meta argument Count with conditional logic as below

You can think about it this way: you can set count to 1 on a specific resource and get one copy of that resource. if its set to 0 then no resource will be created

variable "create_instances" {
type = bool
default = false
}

resource "aws_instance" "example" {
count = var.create_instances ? 1 : 0

# Instance configuration
}

If you set the value for variable create_instances to true the count value will be set to 1 and one copy of the AWS instance will be created.

If you will not set any value, or set the value as false, then the value for variable create_instances will be false and no aws instance will be created.

With Dynamic Block

The dynamic block allows you to generate multiple blocks of configuration dynamically based on a list or map variable.

We can combine Terraform’s dynamic blocks with if/else conditions to create more complex configurations.

Let’s take an example where we want to configure firewall logging when it is explicitly asked for using variable ingress_tcp_log_enabled

variable "ingress_tcp_log_enabled"{
type = bool
default = false

}

resource "google_compute_firewall" "ingress-tcp" {
project = var.project_id
network = var.network

name = "${var.prefix}-ingress-allow-tcp"

allow {
protocol = "tcp"
ports = var.tcp_ports
}

dynamic "log_config" {
for_each = var.ingress_tcp_log_enabled ? ["enable-logs"] : []
content {
metadata = "INCLUDE_ALL_METADATA"
}
}

source_ranges = var.cidr_tcp
}

Or we can use it to dynamically create tags

dynamic "tag" {
for_each = var.create_tags ? var.tags : []
# Condition true_val false-val
content {
key = tag.key
value = tag.value
}
}

Note: In conditional expression, the two result types can be of any type, lets say one is number and other is string 
var.network_name ? 1000 : “base-vpc”
Terraform will attempt find a type in which it can convert both results, in this case it will convert both to string. 
var.network_name ? “1000” : “base-vpc”
It can often cause confusion, to avoid this, it is recommended to write specific conversion function as below
var.network_name ? tostring(1000) : “base-vpc”

Akhilesh Mishra

Akhilesh Mishra

I am Akhilesh Mishra, a self-taught Devops engineer with 11+ years working on private and public cloud (GCP & AWS)technologies.

I also mentor DevOps aspirants in their journey to devops by providing guided learning and Mentorship.

Topmate: https://topmate.io/akhilesh_mishra/