Terraform- Data Block

Summary:

Your Manager told you to come up with a solution for the situation in which developers are not able to launch the Ec2 instance in all availability zone within your VPC. To solve this problem you want to come up with a solution that can dynamically launch desired ec2 instances in all availability zone within your VPC.

Solution: After some research, you decided to use data source block "aws_ec2_instance_type_offerings" that can look for instance type supported per az within a region.

In this solution, we have different files such as:

  1. var.tf- For storing variable names

  2. data.tf - contains the data block

  3. main.tf - contains resource block

  4. output.tf- contains output block

I have also used loops and dynamic filters to achieve our end result.

Code-Link: Click on the code link to download and use code.

Var.tf

##Var.tf###
variable "aws_region" {
  type    = string
  default = "us-east-1"

}

variable "aws_instance" {
  type    = string
  default = "t2.micro"

}

data.tf


# getting ami id
data "aws_ami" "ubuntu" {
  most_recent = true

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

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }

  owners = ["099720109477"] # Canonical official
}

# getting list of az in a region
data "aws_availability_zones" "az" {
  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }


}

# pass list of az into instance supported in the az
data "aws_ec2_instance_type_offerings" "example" {
  # for each can help you to iterate and it should be convereted into map or set
  for_each = toset(data.aws_availability_zones.az.names)
  filter {
    name   = "instance-type"
    values = [var.aws_instance]
  }
  #each.key will iterate all the values
  filter {
    name   = "location"
    values = [each.key]
  }

  location_type = "availability-zone"
}

main.tf

# Get instance implemented on available az
resource "aws_instance" "myec2_Instances" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.aws_instance
  # Create EC2 Instance in all Availabilty Zones of a VPC  
  for_each          = toset(keys({ for az, instance in data.aws_ec2_instance_type_offerings.example : az => instance.instance_types if length(instance.instance_types) != 0 }))
  availability_zone = each.key # You can also use each.value because for list items each.key == each.value
  tags = {
    "Name" = "For-Each-Demo-${each.key}"
  }
}

output.tf

# get instance list
output "output_v1_1" {
  # output should be in for loop for list of supported instances
  value = [for instance in data.aws_ec2_instance_type_offerings.example : instance.instance_types]
}

# now lets see how we can get available instance type with az as a output
output "output_v1_1" {

  value = { for az, instance in data.aws_ec2_instance_type_offerings.example : az => instance.instance_types }
}


# remove unsupported az and only get supported ec2 instance with az
output "output_v1_2" {

  value = { for az, instance in data.aws_ec2_instance_type_offerings.example : az => instance.instance_types if length(instance.instance_types) != 0 }

}


# only getting list of az using key function
output "availability_zone_that_supported_instance_type" {

  value = keys({ for az, instance in data.aws_ec2_instance_type_offerings.example : az => instance.instance_types if length(instance.instance_types) != 0 })

}

# get public dns of our instances
output "instance_publicdns" {
  description = "EC2 Instance Public DNS"

  value = toset([for instance in aws_instance.myec2_Instances : instance.public_dns])
}

Reference:

  1. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami