Why does depends_on argument is not activated

Viewed 49

I have one folder where I keep the main.tf and variables.tf and I got stucked when trying to create a load balancer for my 2 instances:

resource "aws_instance" "wordpress-app-eu-west-2a" {
  ami = var.bastion-ami
  instance_type = var.bastion-instance-type
  subnet_id = aws_subnet.public-eu-west-2a.id
  vpc_security_group_ids = [aws_security_group.bastion.id]
  associate_public_ip_address = true
  key_name = "wordpress-key"
  user_data = file("wordpressapp.sh")
  tags = {
    Name = "Wordpress-APP-2a"
  }
}

The above code is the same for the 2nd instance wordpress-app-eu-west-2a

I have created the resource "aws_lb" , resource "aws_lb_target_group" , resource "aws_lb_listener" but I get an error when configuring the resource "aws_lb_target_group_attachment"

 aws_instance.wordpress-app-eu-west-2a.id will be known only after apply
 aws_instance.wordpress-app-eu-west-2b.id will be known only after apply

Inappropriate value for attribute "target_id": string required.`

Here is the configuration for the "aws_lb_target_group_attachment":

resource "aws_lb_target_group_attachment" "wordpress" {
  target_group_arn = aws_lb_target_group.wordpress.arn
  target_id = [aws_instance.wordpress-app-eu-west-2b.id, aws_instance.wordpress-app-eu-west-2a.id]
  port = 80

  depends_on = [aws_instance.wordpress-app-eu-west-2b, aws_instance.wordpress-app-eu-west-2a]
}

I tried to google why this behaviour might happen but I couldn't find a reason to understand why the depends_on is not working as it should.


Initial error message:

Error: Incorrect attribute value type

on main.tf line 393, in resource "aws_lb_target_group_attachment" "wordpress":

393:   target_id = [aws_instance.wordpress-app-eu-west-2b.id, aws_instance.wordpress-app-eu-west-2a.id]

aws_instance.wordpress-app-eu-west-2a.id will be known only after apply
aws_instance.wordpress-app-eu-west-2b.id will be known only after apply

Inappropriate value for attribute "target_id": string required.

Then I found this article - https://discuss.hashicorp.com/t/aws-target-group-attachment-target-id-error/37558

The new code of the aws_lb_target_group_attachment looks like this:

resource "aws_lb_target_group_attachment" "wordpress" {

  for_each = toset([aws_instance.wordpress-app-eu-west-2b.id, aws_instance.wordpress-app-eu-west-2a.id])
  target_group_arn = aws_lb_target_group.wordpress.arn
  target_id = each.key
  port = 80

  depends_on = [
   aws_instance.wordpress-app-eu-west-2b,
   aws_instance.wordpress-app-eu-west-2a
 ]
}

But when doing a terraform plan I get another error regarding for_each :

Error: Invalid for_each argument

on main.tf line 391, in resource "aws_lb_target_group_attachment" "wordpress":
  391:   for_each = toset([aws_instance.wordpress-app-eu-west-2b.id, aws_instance.wordpress-app-eu-west-2a.id])

aws_instance.wordpress-app-eu-west-2a.id is a string, known only after apply
aws_instance.wordpress-app-eu-west-2b.id is a string, known only after apply

The "for_each" set includes values derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.

When working with unknown values in for_each, it's better to use a map value where the keys are defined statically in your configuration and where only the values contain apply-time results.

Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge.
1 Answers

Each aws_lb_target_group_attachment instance represents an association between exactly one target group and exactly one "target" (e.g. EC2 instance).

Therefore to add more than one EC2 instance to the same target group requires one instance of aws_lb_target_group_attachment for each of the EC2 instances.

It is possible to achieve that using for_each, but for_each requires each of the instances to have a unique key decided in your configuration which you provide as the keys of the map value assigned to for_each. Your EC2 instances are not already naturally in a map, so a good first step is to construct that map as a local value:

local {
  wordpress_instance_ids = tomap({
    "eu-west-2a" = aws_instance.wordpress-app-eu-west-2a.id
    "eu-west-2b" = aws_instance.wordpress-app-eu-west-2b.id
  })
}

With that declaration, local.wordpress_instance_ids is a map from availability zone to EC2 instance ID. Crucially, there is one entry in this map per EC2 instance and so this map is now ready to use with resource for_each to declare multiple target group attachments:

resource "aws_lb_target_group_attachment" "wordpress" {
  for_each = local.wordpress_instance_ids

  target_group_arn = aws_lb_target_group.wordpress.arn
  target_id        = each.value
  port             = 80
}

Because the keys of local.wordpress_instance_ids are the availability zones, this declares two target group attachment instances with the following addresses:

  • aws_lb_target_group_attachment.wordpress["eu-west-2a"]
  • aws_lb_target_group_attachment.wordpress["eu-west-2b"]

The resource configuration uses each.value to refer to the value of each element of the map, which in this case means the EC2 instance ID for each availability zone.

Related