Understanding Key Terraform Concepts: Dynamic Blocks, Data Sources, Locals, Common Tags, and Functions

ESHNITHIN YADAVESHNITHIN YADAV
3 min read

Terraform is a powerful Infrastructure as Code (IaC) tool that allows you to define and manage cloud resources using declarative configuration files. To write efficient and reusable Terraform code, it's essential to understand some key concepts like dynamic blocks, data sources, locals, common tags, and functions.

In this article, we’ll explore each of these topics with simple explanations and practical examples.


1. Dynamic Blocks in Terraform

Dynamic blocks allow you to generate multiple nested blocks within a resource dynamically based on a variable or a map. This is useful when the number of similar configurations varies.

Example: Dynamic Security Group Rules

Suppose you want to create multiple ingress rules in an AWS security group. Instead of writing each rule manually, you can use a dynamic block:

variable "ingress_rules" {
  type = list(object({
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))
  default = [
    {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}

resource "aws_security_group" "web_sg" {
  name = "web-sg"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

Here, the dynamic block generates multiple ingress rules based on the ingress_rules variable.


2. Data Sources in Terraform

Data sources allow Terraform to fetch information from existing resources (either within Terraform or externally). This helps in referencing resources not managed by the current configuration.

Example: Fetching AMI ID from AWS

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical (Ubuntu)

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
}

Here, data "aws_ami" fetches the latest Ubuntu AMI ID, which is then used in an aws_instance.


3. Locals in Terraform

Locals (locals) allow you to define reusable expressions or values within a Terraform configuration, reducing redundancy.

Example: Defining Common Values

locals {
  environment = "prod"
  common_tags = {
    Owner       = "DevOps Team"
    Environment = local.environment
  }
}

resource "aws_instance" "server" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
  tags          = local.common_tags
}

Here, local.common_tags is reused across multiple resources.


4. Common Tags in Terraform

Tags help organize and manage cloud resources. Using a consistent tagging strategy is a best practice.

Example: Applying Tags to Multiple Resources

locals {
  common_tags = {
    Project     = "E-Commerce"
    ManagedBy   = "Terraform"
    Environment = "production"
  }
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags       = local.common_tags
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
  tags       = local.common_tags
}

This ensures all resources have the same set of tags.


5. Terraform Functions

Terraform provides built-in functions for string manipulation, numeric operations, collections, and more.

Common Functions with Examples

a) String Functions

output "upper_case" {
  value = upper("hello world") # "HELLO WORLD"
}

output "substring" {
  value = substr("terraform", 0, 5) # "terra"
}

b) Numeric Functions

output "max_value" {
  value = max(5, 12, 9) # 12
}

c) Collection Functions

locals {
  list = ["a", "b", "c"]
}

output "element" {
  value = element(local.list, 1) # "b"
}

output "merged_map" {
  value = merge({a=1}, {b=2}) # {a=1, b=2}
}

d) File Functions

output "file_content" {
  value = file("${path.module}/config.json")
}

Conclusion

Understanding these Terraform concepts helps in writing clean, reusable, and efficient infrastructure code:

  • Dynamic blocks reduce repetition for nested configurations.

  • Data sources fetch external resource data.

  • Locals improve readability by storing reusable values.

  • Common tags ensure consistency across resources.

  • Functions enable powerful transformations and computations.

By mastering these concepts, you can write better Terraform configurations and manage infrastructure more effectively. Happy Terraforming! 🚀

0
Subscribe to my newsletter

Read articles from ESHNITHIN YADAV directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

ESHNITHIN YADAV
ESHNITHIN YADAV