'depends_on' appears to have no effect. What am I doing wrong?

Previously posted here ().

Terraform Version

Terraform v0.12.24
+ provider.aws v2.54.0

Terraform Main.tf

resource "aws_volume_attachment" "student_linux_data_ebs_attach" {
  count = var.student_instance_count
  instance_id = aws_instance.student_linux[count.index].id
  volume_id = aws_ebs_volume.student_linux_data_ebs[count.index].id
  device_name = var.student_linux_ebs_attach_location
}

Terraform Outputs.tf

output student_linux_instances_info {
  depends_on = [aws_volume_attachment.student_linux_data_ebs_attach]
  value = [
    for i in aws_instance.student_linux: {
      "AMI (Source)":i.ami,
      "Instance Type":i.instance_type,
      "Instance ID":i.id,
      "Availability Zone":i.availability_zone,
...
      "Device Info":{
        "Root Device" = {
          "Delete On Termination":i.root_block_device[0].delete_on_termination
          "Volume Type":i.root_block_device[0].volume_type
          "Volume Size":i.root_block_device[0].volume_size
        }
        "EBS Device" = {
          "Delete on Termination":element(tolist(i.ebs_block_device[*].delete_on_termination), 0)
          "Device Name":element(tolist(i.ebs_block_device[*].device_name), 0)
          "Volume Type":element(tolist(i.ebs_block_device[*].volume_type), 0)
          "Volume Size":element(tolist(i.ebs_block_device[*].volume_size), 0)
        }
...

Expected Behavior

Terraform waits for the referenced aws_volume_attachment to complete before attempting to query the volumes attached to the Instance.

Actual Behavior

Terraform appears to not wait until the EBS volume is attached to the Instance before querying it, thus resulting in the below errors:

Error: Error in function call

  on outputs.tf line 57, in output "student_linux_instances_info":
  57:           "Delete on Termination":element(tolist(i.ebs_block_device[*].delete_on_termination), 0)
    |----------------
    | i.ebs_block_device is empty set of object

Call to function "element" failed: cannot use element function with an empty
list.


Error: Error in function call

  on outputs.tf line 58, in output "student_linux_instances_info":
  58:           "Device Name":element(tolist(i.ebs_block_device[*].device_name), 0)
    |----------------
    | i.ebs_block_device is empty set of object

Call to function "element" failed: cannot use element function with an empty
list.

...

If I wait a few seconds and issue a terraform refresh, all outputs are properly queried and retrieved.

Steps to Reproduce

  1. terraform init
  2. terraform apply

Additional Information

What am I doing wrong here?

Hi @fligi7,

I think this isn’t a dependencies problem, but rather a modelling problem: the aws_instance attribute ebs_block_device only contains the block devices that are requested directly within the aws_instance configuration, not any that are dynamically attached afterwards. As a general rule, a Terraform resource instance only changes during its own apply action, not as a side-effect of other actions.

If you want to make use of the values in your dynamically-attached volume then you’ll need to access attributes of aws_volume_attachment.student_linux_data_ebs_attach instead, because that is where those values live due to how you’ve chosen to model this in Terraform.

For example:

output "student_linux_instances_info" {
  value = [
    for index, inst in aws_instance.student_linux: {
      "AMI (Source)": inst.ami,
      "Instance Type": inst.instance_type,
      "Instance ID": inst.id,
      "Availability Zone": inst.availability_zone,
...
      "Device Info":{
        "Root Device" = {
          "Delete On Termination": inst.root_block_device[0].delete_on_termination
          "Volume Type": inst.root_block_device[0].volume_type
          "Volume Size": inst.root_block_device[0].volume_size
        }
        "EBS Device" = {
          "Delete on Termination": aws_volume_attachment.student_linux_data_ebs_attach[index].delete_on_termination
          "Device Name": aws_volume_attachment.student_linux_data_ebs_attach[index].device_name
          "Volume Type": aws_volume_attachment.student_linux_data_ebs_attach[index].volume_type
          "Volume Size": aws_volume_attachment.student_linux_data_ebs_attach[index].volume_size
        }
...

This relies on the fact that the volume attachments are correlated with the instances using count.index, and so we can assume that the index of an instance in aws_instance.student_linux will always match the index of its corresponding instance of aws_volume_attachment.student_linux_data_ebs_attach, and thus we can use index in the for expression to look up the appropriate object.

Note that depends_on is not needed now, because the references to aws_volume_attachment.student_linux_data_ebs_attach already imply that dependency.

Thanks for the reply!

The reason I am creating/attaching an EBS volume separately from declaring it within the aws_instance resource creation is that I want to tag the EBS volume differently than the Root volume. As I understand it, the volume_tags tags all associated volumes of the Instance with the same tags, which I don’t want.

To avoid that, I created and attached the EBS separately, which it sounds like is causing the issue (if I’m reading your response correctly).

If I go back and declare the EBS creation via ebs_block_device within the aws_instance resource creation, is there a clever way to tag both the root and EBS volumes differently than having to create separate ebs_volume resource statements for each block device to tag them accordingly?

Hi @fligi7!

Unfortunately my knowledge of the AWS provider specifically is not great enough to offer an answer to this follow-on question, but hopefully someone else in the forum will have some ideas. I do have some vague memory that the limitation here is in the underlying API (ec2:RunInstances) rather than in Terraform itself, where there’s only a single set of tags in that API which EC2 itself applies to all of the additional objects that are created as a side-effect, so I will admit I’m not optimistic that there is a different way to get this done.

My initial answer was focused on how to get the end result you wanted without declaring it all as a single resource, which I believe should be possible in the event that you can’t find a way to get the tagging result you want any other way.