DEV Community

Cover image for Mastering Terraform: How Loops and Conditionals Unlock Smarter Infrastructure Automation
Patrick Odhiambo
Patrick Odhiambo

Posted on

Mastering Terraform: How Loops and Conditionals Unlock Smarter Infrastructure Automation

In the ever-growing world of cloud infrastructure, managing and automating deployments has become increasingly complex. This is where Terraform comes in — as one of the most powerful tools in Infrastructure as Code (IaC), Terraform allows engineers to declaratively define and provision infrastructure with ease. However, as configurations grow, keeping them concise and manageable is a challenge. Fortunately, Terraform offers loops and conditionals, features that can significantly simplify repetitive and complex configurations.

In this blog, we’ll explore how loops and conditionals in Terraform can streamline infrastructure management and help you write more efficient, maintainable, and DRY (Don’t Repeat Yourself) Terraform code.

What are Loops and Conditionals in Terraform?

Before diving into the "how," let’s break down what loops and conditionals are in Terraform.

  • Loops: Loops allow you to create multiple resources or apply similar configurations across different items without duplicating code. Terraform supports two types of loops: for_each and count. Both loops help eliminate redundancy by dynamically creating resources based on variables or data sources.

  • Conditionals: Conditionals let you define resources or values based on certain conditions. Using if-else style logic, you can customize infrastructure deployments according to environment variables, inputs, or other dynamic factors.

Now, let’s explore how these features can simplify infrastructure as code in Terraform.

Using Loops in Terraform

Terraform’s loop mechanisms help in scenarios where you need to provision multiple resources with similar configurations. Without loops, you’d end up repeating nearly identical blocks of code, which is not only cumbersome but also error-prone. By leveraging loops, you can efficiently manage similar resources with minimal code.

1. The count Meta-Argument

The count argument is one of Terraform’s most basic mechanisms for creating multiple instances of a resource. It works by simply repeating a resource a specified number of times.

Example: Deploying Multiple EC2 Instances

Let’s say you want to deploy 3 EC2 instances. Without loops, you’d have to write the resource block three times:

resource "aws_instance" "example1" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}

resource "aws_instance" "example2" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}

resource "aws_instance" "example3" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}
Enter fullscreen mode Exit fullscreen mode

With the count argument, this becomes much simpler:

resource "aws_instance" "example" {
  count         = 3
  ami           = "ami-123456"
  instance_type = "t2.micro"
}
Enter fullscreen mode Exit fullscreen mode

Terraform will now create three identical instances of the resource, dramatically reducing the amount of code.

Dynamic Resource Allocation with count

In real-world scenarios, you often don’t know how many resources to create upfront. This is where count becomes powerful. You can use variables to dynamically set the number of instances:

variable "instance_count" {
  default = 3
}

resource "aws_instance" "example" {
  count         = var.instance_count
  ami           = "ami-123456"
  instance_type = "t2.micro"
}
Enter fullscreen mode Exit fullscreen mode

By changing the instance_count variable, you can scale up or down your infrastructure with a single change, making your code more adaptable to different requirements.

2. The for_each Meta-Argument

While count is useful for creating identical resources, the for_each argument shines when you need to create multiple instances with unique properties. With for_each, you can iterate over a map or a set of values and apply unique configurations to each resource.

Example: Creating Multiple EC2 Instances with Unique Tags

Imagine you want to create multiple EC2 instances, each with its own tag. With for_each, you can pass a map of instance names and dynamically create resources:

variable "instances" {
  default = {
    instance1 = "ami-123456"
    instance2 = "ami-654321"
    instance3 = "ami-789012"
  }
}

resource "aws_instance" "example" {
  for_each = var.instances
  ami           = each.value
  instance_type = "t2.micro"

  tags = {
    Name = each.key
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, for_each iterates over the instances map and creates a unique EC2 instance for each entry with a custom AMI and tag.

Using Conditionals in Terraform

Conditionals in Terraform allow you to make your code more flexible and adaptable to different scenarios without requiring separate configuration files. This feature is particularly useful when managing multiple environments (e.g., development, staging, production) or configuring optional resources.

1. Conditional Expressions

A conditional expression in Terraform follows the syntax of condition ? true_value : false_value. This lets you dynamically set variables, resource arguments, or outputs based on certain conditions.

Example: Choosing Instance Types Based on Environment

Suppose you want to deploy smaller instances in a development environment but larger instances in production. You can use a conditional expression to dynamically set the instance type based on the environment:

variable "environment" {
  default = "dev"
}

resource "aws_instance" "example" {
  ami = "ami-123456"
  instance_type = var.environment == "prod" ? "t2.large" : "t2.micro"
}
Enter fullscreen mode Exit fullscreen mode

In this example, Terraform will provision a t2.large instance if the environment is prod, and a t2.micro instance for all other environments.

2. Optional Resource Creation with Conditionals

Terraform conditionals can also be used to control whether a resource is created or not. By combining the count meta-argument with conditionals, you can make certain resources optional.

Example: Conditionally Creating a Security Group

Let’s say you only want to create a security group in a production environment. You can set the count argument to 1 or 0 based on a condition:

variable "create_security_group" {
  default = false
}

resource "aws_security_group" "example" {
  count = var.create_security_group ? 1 : 0

  name        = "example_sg"
  description = "Example security group"
}
Enter fullscreen mode Exit fullscreen mode

In this case, Terraform will only create the security group if create_security_group is set to true. Otherwise, no security group is created.

3. Ternary Operations with Variables

You can also use conditionals to set variable values based on certain conditions, making your variables more flexible and reusable across different environments.

Example: Setting Defaults for Variable Values

If you want to set different default values for variables based on the environment, you can do this with a ternary operation:

variable "region" {
  default = var.environment == "prod" ? "us-west-1" : "us-east-1"
}

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
  availability_zone = var.region
}
Enter fullscreen mode Exit fullscreen mode

In this example, the region is dynamically set based on whether the environment is production or not.

Combining Loops and Conditionals

While loops and conditionals are powerful on their own, combining them can create even more dynamic infrastructure configurations.

Example: Conditional Looping

Imagine you want to create different numbers of EC2 instances based on the environment. In production, you want five instances, while in development, you only want two. You can combine a conditional with a loop like this:

variable "environment" {
  default = "dev"
}

resource "aws_instance" "example" {
  count = var.environment == "prod" ? 5 : 2

  ami           = "ami-123456"
  instance_type = "t2.micro"
}
Enter fullscreen mode Exit fullscreen mode

With this configuration, Terraform will provision five EC2 instances in production and two in development, all controlled by a single variable.

Best Practices for Using Loops and Conditionals

While loops and conditionals are powerful, it’s important to use them judiciously to avoid overcomplicating your Terraform code. Here are some best practices to keep in mind:

  • Keep it Simple: Avoid nesting too many loops or conditionals within each other. Complex logic can make your code harder to read and maintain.
  • Use Modules: When possible, break down complex infrastructure into reusable modules. Loops and conditionals can be used within modules to make them more flexible.
  • Document Your Code: Be sure to add comments explaining why certain conditionals or loops are used, especially when they involve complex logic.
  • Test in Small Environments: When using loops and conditionals, test in smaller environments (like dev) before applying them to production. This ensures that your logic works as expected.

Parting Shot

Loops and conditionals are essential tools in Terraform that make Infrastructure as Code more flexible, scalable, and manageable. By understanding and applying these concepts, you can write cleaner, more efficient configurations that adapt dynamically to different environments and scenarios.

Whether you’re deploying hundreds of resources across multiple environments or managing dynamic configurations, Terraform’s loops and conditionals simplify the process and reduce the complexity of your infrastructure code. By mastering these tools, you’ll be well on your way to building scalable, maintainable cloud infrastructure with Terraform.

Happy Terraforming !!

Top comments (0)