I am attempting to provide the ability to specify an arbitrary number of resources in a variables file and based on the configuration specified therein use various Terraform programming constructs (if/then, for each, etc.) to turn it into relevant calls to a module which creates/manages a resource (an AWS instance in this case). For example, we could have one configuration (variables.tf
) such as the below for a UAT environment (VPC) with two instance components:
"vpc" = {
"vpc_id" = "uat-1"
"vpc_cidr_block" = "1.2.3.4/5"
"vpc_name" = "org-uat"
}
"instances" = {
"db" = {
"subnet_id" = "db-sub-1"
"subnet_name" = "uat-db-1"
"subnet__cidr_block" = "11.22.33.44/5"
}
"web" = {
"subnet_id" = "web-sub-1"
"subnet_name" = "uat-web-1"
"subnet__cidr_block" = "10.21.32.43/5"
}
}
and another for a development environment (VPC) that has three instance components:
"vpc" = {
"vpc_id" = "dev-1"
"vpc_cidr_block" = "1.2.33.4/56"
"vpc_name" = "org-dev"
}
"instances" = {
"app" = {
"subnet_id" = "app-sub-1"
"subnet_name" = "dev-app-1"
"subnet_cidr_block" = "10.21.32.44/56"
}
"db" = {
"subnet_id" = "db-sub-1"
"subnet_name" = "dev-db-1"
"subnet_cidr_block" = "11.22.33.44/5"
}
"web" = {
"subnet_id" = "web-sub-1"
"subnet_name" = "dev-web-1"
"subnet_cidr_block" = "10.21.32.43/5"
}
}
The idea is to loop over the instances and to call a module for instance management. There are for loops and if/then/else constructs that make it possible to do something like this within the terraform.tf
in the environment’s directory (the below is not valid HCL, only pseudocode):
for instance in ${var.instances}:
module "instance" {
source = "../../modules/api/dev"
vpc_cidr_block = ${var.vpc.vpc_cidr_block}
vpc_id = ${var.vpc.vpc_id}
vpc_name = ${var.vpc.vpc_name}
subnet_cidr_block = ${instance.subnet_cidr_block}
subnet_name = ${instance.subnet_name}
subnet_id = ${instance.subnet_id}
}
where the above is looping over items in the instances map/dictionary and calls an “instance” module for each. The instance module just configures an AWS instance based on the VPC and subnet variable values passed as inputs:
data "aws_vpc" "example_vpc" {
cidr_block = var.vpc_cidr_block
tags = {
Name = var.vpc_name
}
}
data "aws_subnet" "example_subnet" {
vpc_id = data.aws_vpc.example_vpc.id
cidr_block = var.subnet_cidr_block
availability_zone = var.subnet_availability_zone
tags = {
Name = var.subnet_name
}
}
resource "aws_key_pair" "example_aws_key_pair" {
key_name = "example_key"
public_key = file("~/.ssh/terraform.pub")
}
resource "aws_instance" "example_aws_instance" {
key_name = aws_key_pair.example_aws_key_pair.key_name
ami = "ami-b374d5a5"
instance_type = "t2.micro"
subnet_id = data.aws_subnet.example_subnet.id
connection {
type = "ssh"
user = "terraform"
private_key = file("~/.ssh/terraform")
host = self.public_ip
}
tags = {
"Name" : "dev_terraform_${terraform.workspace}_${var.environment}"
"Terraform" : "true"
}
}
The inputs for the above module are declared like so:
variable "environment" {}
variable "subnet_availability_zone" {}
variable "subnet_cidr_block" {}
variable "subnet_name" {}
variable "vpc_cidr_block" {}
variable "vpc_id" {}
variable "vpc_name" {}
Does this appear to be a reasonable approach to allow a user to configure/manage an infrastructure containing one to many AWS instances, assuming the user can define these instances in a variables/config file?
I am new with Terraform so there may be some really obvious errors in my approach or (attempted) implementation, please advise if so, any help is very kindly appreciated!