I am using Terraform (called via Terragrunt, if that's relevant) to create an instance from an AMI and mount an existing volume:
resource "aws_instance" "jenkins_master_with_snap" {
count = "${var.master_with_snapshot}"
ami = "${var.jenkins_ami}"
instance_type = "${var.jenkins_instance_type}"
iam_instance_profile = "${data.terraform_remote_state.global.jenkins_profile_name}"
subnet_id = "${data.aws_subnet.jenkins_subnet_with_snap.id}"
key_name = "${var.key_name}"
vpc_security_group_ids = [
"${aws_security_group.jenkins_master_target_sg.id}",
"${data.terraform_remote_state.cicd.cicd_sg_ipa}"
]
ebs_block_device {
snapshot_id = "${var.master_snapshot_id}"
device_name = "${var.jenkins_volume_device}"
volume_type = "gp2"
}
}
It's worth noting that the AMI used to create this resource already has a snapshot mapped to it from the build process, so this resource basically just replaces it with a different snapshot. I'm not sure if this is why I'm having the problem or not.
I'm using the resulting resource attributes to populate a Python template that will be zipped and uploaded as a lambda function. The Python script requires the volume-id
from this instance's EBS block device.
data "template_file" "ebs_backup_lambda_with_snapshot_template" {
count = "${var.master_with_snapshot}"
template = "${file("${path.module}/jenkins_lambda_ebs_backup.py.tpl")}"
vars {
volume_id = "${aws_instance.jenkins_master_with_snap.ebs_block_device.???.volume_id}"
}
}
Onto the actual problem: I do not know how to properly reference the volume ID in the vars
section of the template_file
resource above. Here is the resulting state:
ebs_block_device.# = 1
ebs_block_device.1440725774.delete_on_termination = true
ebs_block_device.1440725774.device_name = /dev/xvdf
ebs_block_device.1440725774.encrypted = true
ebs_block_device.1440725774.iops = 900
ebs_block_device.1440725774.snapshot_id = snap-1111111111111
ebs_block_device.1440725774.volume_id = vol-1111111111111
ebs_block_device.1440725774.volume_size = 300
ebs_block_device.1440725774.volume_type = gp2
ebs_optimized = false
root_block_device.# = 1
root_block_device.0.delete_on_termination = false
root_block_device.0.iops = 0
root_block_device.0.volume_id = vol-1111111111111
root_block_device.0.volume_size = 8
root_block_device.0.volume_type = standard
The problem is that the index for the EBS volume is that insane integer 1440725774
. I have no idea why that is occuring. In the console, there's only a single map in the list I'm interested in:
> aws_instance.jenkins_master_with_snap.ebs_block_device
[
{ delete_on_termination = 1 device_name = /dev/xvdf encrypted = 1 iops = 900 snapshot_id = snap-1111111111111 volume_id = vol-1111111111111 volume_size = 300 volume_type = gp2}
]
And it appears the only way to reference any of those keys is to use that index value directly:
> aws_instance.jenkins_master_with_snap.ebs_block_device.1440725774.volume_id
vol-1111111111111
Is there any way to reliably reference a single element in a list like this when I have no idea what the index is going to be? I can't just hardcode that integer into the template_file
resource above and assume it's going to be the same every time. Does anyone have any clues as to why this is occurring in the first place?
Perhaps instead of inlining ebs_block_device block, create a separate aws_ebs_volume resource, then attach it with an aws_volume_attachment. Then reference the aws_ebs_volume.name.id
attribute to get the ID you need.
Example (extended from the example code in aws_volume_attachment
):
resource "aws_volume_attachment" "ebs_att" {
device_name = "/dev/sdh"
volume_id = "${aws_ebs_volume.example.id}"
instance_id = "${aws_instance.web.id}"
}
resource "aws_instance" "web" {
ami = "ami-21f78e11"
availability_zone = "us-west-2a"
instance_type = "t1.micro"
tags {
Name = "HelloWorld"
}
subnet_id = "<REDACTED>"
}
resource "aws_ebs_volume" "example" {
availability_zone = "us-west-2a"
size = 1
}
data "template_file" "example" {
template = "Your volume ID is $${volume_id}"
vars {
volume_id = "${aws_ebs_volume.example.id}"
}
}
output "custom_template" {
value = "${data.template_file.example.rendered}"
}
The resultant output:
Outputs:
custom_template = Your volume ID is vol-0b1064d4ca6f89a15
You can then use ${aws_ebs_volume.example.id}
in your template vars to populate your lambda.