I am trying to create a module that creates an EC2 instance with a variable number of attached volumes. The volumes need to be declared as separate resources and become attached to the instance via the volume_attachment resource, because this is for a fileserver where the volumes will persist if I do a terraform apply using a new AMI id (i.e., I deploy the server, use it to write some data to the volumes, then I create a new AMI, run a terraform apply, and terraform destroys the attachment resource, retains the volumes because they haven’t changed, destroys the instance, launches a new instance, and creates new attachment resources which will attach the old volumes to the new instance).
I am in need of help getting the syntax and correct method for declaring the various resources and their links using for_each.
Example:
I have a .tf file which will contain 3 modules. The modules are for the same subfolder, ec2_instance, where the module definition passes parameters in, which takes a “vols” parameter containing the volume definitions. For each invocation of the module, there are differing numbers of volumes:
Module 1 might use:
vols = {
data01 = {
device_name = "xvde"
size = "100"
type = "gp2"
}
data02 = {
device_name = "xvdh"
size = "200"
type = "gp2"
}
}
and Module 2 might use:
vols = {
output01 = {
device_name = "xvde"
size = "800"
type = "gp2"
}
}
Currently, this is my file which declares 1 instance, 2 volumes and 2 volume_attachments. It will create a single instance with 2 volumes attached (and will be the basis of the inside of my new module):
resource "aws_instance" "storage" {
ami = data.aws_ami.storage.id
...
user_data = data.template_file.userdata_executescript.rendered
root_block_device {
volume_type = "gp2"
volume_size = 80
delete_on_termination = true
}
tags = merge(
var.common_tags,
{
"Name" = format("%s_storage", var.instance_name)
"Role" = format("%s_storage", var.stack_name)
"Backup" = "true"
},
)
}
resource "aws_ebs_volume" "volume_input" {
availability_zone = local.availability_zone
size = 100
type = "gp2"
encrypted = true
tags = merge(
var.common_tags,
{
"Name" = format("%s_storage-%s", var.stack_name, "data01")
"Backup" = "true"
},
)
}
resource "aws_ebs_volume" "volume_input__backup" {
availability_zone = local.availability_zone
size = 200
type = "gp2"
encrypted = true
tags = merge(
var.common_tags,
{
"Name" = format("%s_storage-%s", var.stack_name, "data02")
"Backup" = "true"
},
)
}
resource "aws_volume_attachment" "volume_input" {
device_name = "xvde"
volume_id = aws_ebs_volume.volume_input.id
instance_id = aws_instance.storage.id
}
resource "aws_volume_attachment" "volume_input__backup" {
device_name = "xvdh"
volume_id = aws_ebs_volume.volume_input__backup.id
instance_id = aws_instance.storage.id
}
As there will be a differing number of volumes and volume attachments each time the module is invoked, I thought I’d do this using a for_each to declare the volume and volume_attachment resources (at the top of each resource I’ve put the common values, then the ‘each’ values beneath where they differ per resource):
resource "aws_ebs_volume" "volume" {
for_each = var.vols
availability_zone = local.availability_zone
encrypted = true
size = each.value.size
type = each.value.type
tags = merge(
var.common_tags,
{
"Name" = format("%s_storage-%s", var.stack_name, each.key)
"Backup" = "true"
},
)
}
resource "aws_volume_attachment" "volume" {
for_each = var.vols
instance_id = aws_instance.storage.id
device_name = each.value.device_name
volume_id = aws_ebs_volume.volume["${lookup(var.vols[each.key], each.key, "")}"].id
}
What I need help with is understanding how to specify the volume_id in the aws_volume_attachment resource. I’ve made an attempt at it so you can see the type of value I am trying to lookup/get.
Once I’ve got this set of declarations working, I also need help understanding how to output the volume details into the userdata. I’m using EC2Launch v2 for Windows, which takes yaml input. Essentially, I need to create a userdata file which contains something like this, but with a different number of devices each time:
version: 1.0
tasks:
- task: initializeVolume
inputs:
initialize: devices
devices:
- device: xvde
name: data01
letter: D
partition: gpt
- device: xvdh
name: data02
letter: E
partition: gpt
I’m new to the for/for_each concepts in terraform and can’t seem to figure out the correct syntaxes and formats for repeating elements. Help is appreciated.
9 posts - 2 participants