Learning Terraform with Real World Scenarios-Part 2

Linu Bajy
5 min readDec 9, 2022

--

Hey everyone, continuing from the Part-1, here are a few other interesting blocks and functions of Terraform.

Repo : https://github.com/linubajy/Terraform

Example 1-Data Blocks

A data block can be your friend by helping you to fetch data from the provider, here AWS. We specify the object that we need along with certain filters to fetch. Using those values, we will be able to fetch the resource, without actually going into the Console. A common use case would be when we want to fetch the latest custom AMI , that we have deployed. We can fetch it using the parameter “most_recent=true”. This can then be used to bring up a new EC2 instance wit that AMI.

Terraform example file — data_source.tf— to bring up the latest ubuntu OS AMI. Without even going to the Console, using the data_source block, I was able to fetch the latest Ubuntu AMI according to the specified Ubuntu Version.

Note: Make sure the Image name has the following format to ensure its from an Official Amazon Owner, or else it could bring up images from AWS Community or elsewhere.

/* Example for data source block */
/* Credentials have been given a dummy value for security purpose. To run the code ,we require credentials of the AWS Account to fetch data */

provider "aws" {
region = "us-east-1"
access_key = "mock"
secret_key = "mock"


}

data "aws_ami" "ami_virginia" {
most_recent = true
owners = ["amazon"]

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

resource "aws_instance" "myec2" {
ami = data.aws_ami.ami_virginia.id
instance_type = "t2.micro"
}

Output for data_source.tf

data_source(1)

Example 2 — Dynamic Block

Terraform example file — dynamic_block.tf — Enables you to copy a chunk of identical code , such that there is only a small change. In this case , we wanted to create rules for a Security Group. So except for the port values, the rest of the parts of code will be identical. The port values can be fetched from a list , iterating one by one to replace the port value each time. It exhibits code modularity.

/* Dynamic block example */

provider "aws" {
region = "us-west-2"
skip_credentials_validation = true
skip_requesting_account_id = true
skip_metadata_api_check = true
access_key = "mock"
secret_key = "mock"

}

variable "ports" {
type = list
default = [100,200]
}

resource "aws_security_group" "dynamic_sg" {
name = "dynamic sg"
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value //fetches value from for_each everytime
to_port = ingress.value //fetches value from for_each everytime
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

}

}

Output for dynamic_block.tf

dynamic_block(1)

Example 3 — Splat

A Splat is basically like a wildcard expression. If you are familiar with Regular Expression (RegEx), you would know what a ‘*’ does. Its almost like the Queen piece of the Chess set :P . It can fetch all the values , having the least filter of all.

Terraform example file — splat.tf — contains a splat expression. Here the different AMI names would be generated , which can be displayed as Output in the output block. So even if the value of count is modified later on, it will still display all of those new AMI values.

/* Example for Splat Expression for 3 users */

provider "aws" {
region = "us-west-1"
skip_credentials_validation = true
skip_requesting_account_id = true
skip_metadata_api_check = true
access_key = "mock"
secret_key = "mock"
}


resource "aws_instance" "myinstance" {
ami = "ami-test.${count.index}"
instance_type = "t2.micro"
count = 3


}

output "instances" {
value = aws_instance.myinstance[*].ami // splat expression
}

Output for splat.tf

splat(1)

Example 4— Tags

Tags are used to uniquely identify a resource. But at times it becomes painful to add varying details each time. To make it reusable at different locations, we specify the tag names in locals block. Inside locals , we can have different blocks and associate the required tags to it.

Terraform file — tags.tf

Notes:

  • We use locals for definition of blocks , but when calling (declaring), we use local, not locals. It is not a typo :)
  • When there are multiple resources that can have the same tag, it makes much more sense to reuse and assign tags rather than to write the same repeatedly.
  • Here EC2 instance is the Frontend instance and RDS instance would be the Backend infra. All tags are kept inside locals block.
/* Create tags for resources using locals block */
provider "aws" {
region = "eu-west-1"
skip_credentials_validation = true
skip_requesting_account_id = true
skip_metadata_api_check = true
access_key = "mock"
secret_key = "mock"

}

locals {

frontend_tags = {
name = "DevOps"
service = "Frontend"
}

backend_tags = {
name = "DevOps"
service = "Backend"
}

}


resource "aws_instance" "myec2" {
ami = "ami-01cae1550c0adea9c"
instance_type = "t2.micro"
tags = local.frontend_tags
}

resource "aws_db_instance" "RDS" {
allocated_storage = 10
db_name = "App-DB"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t3.micro"
username = "foo"
password = "foobarbaz"
parameter_group_name = "default.mysql5.7"
skip_final_snapshot = true
tags = local.backend_tags
}

Output for tags.tf

tags(1)
tags(2)

Example 4 — Zipmap function

Zipmap is a built in terraform function, which can be used to create a map dynamically. For static values , we can have a variable of type map, but zipmap is a gamechanger for dynamic values.

Format : zipmap( <keys>,<values>)

  • Keys , Values can be Lists

Terraform example file — zipmap.tf — Takes the outputs for the name of the iam_user and maps it to its associated ARN.

/* Zipmap Function Example */
/* Credentials have been given a dummy value for security purpose.
Valid AWS Credentials is mandatory for this exercise */

provider "aws" {
region = "us-east-1"
access_key = "demo"
secret_key = "demo"
}

resource "aws_iam_user" "lb" {
name = "iam_user-${count.index + 1}"
path = "/system/"
count =3

}

output "arns" {
value = aws_iam_user.lb[*].arn
}

output "username_with_arn" {
value = zipmap (aws_iam_user.lb[*].name , aws_iam_user.lb[*].arn )
}

*/

Output for zipmap.tf

zipmap(1)

More cool exercises on the way. Remember, nothing can replace the fun and experience you get from practice :)

Cheers!

--

--

Linu Bajy
Linu Bajy

Written by Linu Bajy

Enthusiastic Learner . DevOps Professional .

No responses yet