Day-14&15-Terraform-AWS

Mokadi Surya Prasad
6 min readOct 21, 2024

--

Terraform Functions:

  1. Count & Index, Splat Expressions
  2. List
  3. Element
  4. Count
  5. For_each
  6. Locals
  7. Dynamic Blocks
  8. Lookup
  9. Terraform Conditions
  10. Using Null Resources
  11. Terraform Taint

Count & Index:

Count is used to create multiple public-subnet, private-subnet of a resource. It tells Terraform how many copies of a resource you want to create. This is useful when you need more than one of something (like virtual machines, security groups, etc.).

Index is used to refer to a specific item in a list or array. It helps you access individual elements by their position. In Terraform, the index starts at 0 for the first item.

  • Count: Specifies how many copies of a resource to create.
  • Index: Refers to the position of an item in a list, starting from 0.

resource “aws_subnet” “public-subnet” {

count = 3 #012

vpc_id = “${aws_vpc.default.id}”

cidr_block = “${element(var.public_cird_block, count.index)}”

availability_zone = “${element(var.azs, count.index)}”

tags = {

Name = “${var.vpc_name}-public-subnet”

Owner = local.Owner

CostCenter = local.CostCenter

TeamDL = local.TeamDL

environment = “${var.environment}”

}

}

resource “aws_subnet” “private-subnet” {

count = 3 #012

vpc_id = “${aws_vpc.default.id}”

cidr_block = “${element(var.private_cird_block, count.index)}”

availability_zone = “${element(var.azs, count.index)}”

tags = {

Name = “${var.vpc_name}-private-subnet”

Owner = local.Owner

CostCenter = local.CostCenter

TeamDL = local.TeamDL

environment = “${var.environment}”

}

}

Splat Expressions:

Splat expressions in Terraform are a convenient way to extract values from a list or a map. They help you get a specific attribute from each item in a collection without needing to write a loop for it.

  • Splat Expressions: Use [*] to extract a specific attribute from all items in a list or a specific value from a map.
  • Purpose: They make it easier and cleaner to get multiple values without writing complex loops.

resource “aws_route_table_association” “public-RTA” {

count=3

subnet_id = “${element(aws_subnet.public-subnet.*.id, count.index+1)}”

route_table_id = “${aws_route_table.public-route-table.id}”

}

resource “aws_route_table_association” “private-RTA” {

count=3

subnet_id = “${element(aws_subnet.private-subnet.*.id, count.index+1)}”

route_table_id = “${aws_route_table.private-route-table.id}”

}

length Function:

The length function in Terraform is used to find out how many items are in a list or how many characters are in a string.

vpc_cidr = “172.18.0.0/16”

public_cird_block = [“172.18.1.0/24”, “172.18.2.0/24”, “172.18.3.0/24”,”172.18.4.0/24"]

private_cird_block = [“172.18.10.0/24”, “172.18.20.0/24”, “172.18.30.0/24”, “172.18.40.0/24”]

resource “aws_subnet” “public-subnet” {

# count = 3 #012

count = “${length(var.public_cird_block)}”

vpc_id = “${aws_vpc.default.id}”

cidr_block = “${element(var.public_cird_block, count.index+1)}”

availability_zone = “${element(var.azs, count.index)}”

tags = {

Name = “${var.vpc_name}-public-subnet-${count.index+1}”

Owner = local.Owner

CostCenter = local.CostCenter

TeamDL = local.TeamDL

environment = “${var.environment}”

}

}

resource “aws_subnet” “private-subnet” {

#count = 3 #012

count = “${length(var.private_cird_block)}”

vpc_id = “${aws_vpc.default.id}”

cidr_block = “${element(var.private_cird_block, count.index+1)}”

availability_zone = “${element(var.azs, count.index)}”

tags = {

Name = “${var.vpc_name}-private-subnet-${count.index+1}”

Owner = local.Owner

CostCenter = local.CostCenter

TeamDL = local.TeamDL

environment = “${var.environment}”

}

}

resource “aws_route_table_association” “public-RTA” {

#count=3

count = “${length(var.public_cird_block)}”

subnet_id = “${element(aws_subnet.public-subnet.*.id, count.index)}”

route_table_id = “${aws_route_table.public-route-table.id}”

}

resource “aws_route_table_association” “private-RTA” {

#count=3

count = “${length(var.private_cird_block)}”

subnet_id = “${element(aws_subnet.private-subnet.*.id, count.index)}”

route_table_id = “${aws_route_table.private-route-table.id}”

}

Dynamic Blocks& For_each:

  • Dynamic Blocks: Used to create multiple similar configurations without repeating code.
  • For_each: Loops through a list or map to apply configurations to each item.

How It Works:

  • for_each = var.ports: This tells Terraform to loop through each item in the ports list.
  • content {…}: Inside this block, you define what to do for each port.
  • ingress.value refers to the current item in the loop (the current port).

ingress_value = [“80”, “8080”, “443”, “8443”, “22”, “3306”, “1990”, “1443”]

resource “aws_security_group” “allow_all” {

name = “${var.vpc_name}-allow_all”

description = “Allow all inbound traffic”

vpc_id = aws_vpc.default.id

dynamicingress” {

for_each = var.ingress_value

content {

to_port = ingress.value

from_port = ingress.value

protocol = “tcp”

cidr_blocks = [“0.0.0.0/0”]

}

}

egress {

from_port = 0

to_port = 0

protocol = “-1”

cidr_blocks = [“0.0.0.0/0”]

}

tags = {

Name = “${var.vpc_name}-allow_all”

Owner = local.Owner

CostCenter = local.CostCenter

TeamDL = local.TeamDL

environment = var.environment

}

}

Lookup:

Terraform lookup is used to find values in a map. For example, if I want to deploy AMIs in different regions like us-east-1 and us-east-2, I can use the lookup function. It looks like this: lookup(map, key, default). This way, I can easily deploy instances in those two regions by using the lookup function to get the correct AMI for each region.

amis = {
us-east-1 = “ami-0866a3c8686eaeeba”
us-east-2 = “ami-0ea3c35c5c3284d82”
}

ami = lookup(var.amis, var.aws_region)

Terraform Conditions:

Terraform conditions are used to deploy resources based on specific needs. For example, if I want to deploy resources in a Prod environment and a Dev environment, I can set a condition. If the requirement is for the Prod environment, I can create 3 instances. If it’s for the Dev environment, I create only 1 instance. This way, I can manage resources according to the environment needed.

resource “aws_instance” “private_server” {
count = “${var.environment == “Prod” ? 3 : 1 }”

}

Terraform Provisioners & Null Resources:

Terraform provisioners and null resources are used to run scripts in a Terraform environment. For example, if I want to deploy a small static website on an AWS EC2 instance without using the AWS console, I can do this with Terraform. I can use provisioners to connect via SSH and run commands to set up my website.

Using a null resource, I can trigger these commands to run automatically when I create the instance. This way, I can deploy my website easily by just running Terraform, using my key pair for the SSH connection.

resource “null_resource” “cluster” {
count = length(var.public_cird_block) # Adjust as needed for your use case

provisioner “file” {
source = “user-data.sh”
destination = “/tmp/user-data.sh”

connection {
type = “ssh”
user = “ubuntu” # Adjust based on your AMI
private_key = file(“DevSecOps_Key.pem”)
host = element(aws_instance.public_server.*.public_ip, count.index)
}
}

provisioner “remote-exec” {
inline = [
“sudo chmod +x /tmp/user-data.sh”,
“sudo /tmp/user-data.sh”,
“sudo apt update”,
“sudo apt install jq unzip -y”,
]

connection {
type = “ssh”
user = “ubuntu” # Adjust based on your AMI
private_key = file(“DevSecOps_Key.pem”)
host = element(aws_instance.public_server.*.public_ip, count.index)
}
}

depends_on = [aws_instance.public_server] # Ensure the instance is created first
}

Terraform Taint:

I use Terraform taint to mark a resource that needs to be changed. When I update my data.sh file, I run terraform taint null_resource[0]to tell Terraform to recreate it. Then, I run terraform apply to make the changes. This helps ensure my updates appear on the AWS EC2 instance.

--

--

Mokadi Surya Prasad
Mokadi Surya Prasad

No responses yet