I am trying to create target group attachment to the instances. e.g.
if there are 3 target groups and 2 instances, would like to attach 3 target groups to the 2 instances.
Here is my code
instances
resource "aws_instance" "web_servers" {
ami = "ami-1234"
instance_type = "t3a.small"
subnet_id = module.vpc.private_subnets[0]
key_name = aws_key_pair.keypair.key_name
count = 2
root_block_device {
volume_type = "gp3"
volume_size = var.ws_storage
encrypted = true
delete_on_termination = true
}
tags = merge(
{ Name = "${var.project}-${var.env}-ws-${count.index}" },
var.tags
)
}
Target group attachment local variable
locals {
tg_attachments = distinct(flatten([
for tg in var.lb : [
for instance in aws_instance.web_servers : {
tg_name = tg.tg_name
tg_port = tg.listener_port
tg_protocol = tg.protocol
tg_instance = instance.id
}
]
]))
}
target group attachment
resource "aws_lb_target_group_attachment" "ws_tg_attachement" {
depends_on = [
time_sleep.wait_30_seconds,
aws_lb_listener.listener,
aws_instance.web_servers,
aws_lb_target_group.tg
]
for_each = { for entry in local.tg_attachments: "${entry.tg_name}-${entry.tg_port}-${entry.tg_instance}" => entry }
target_group_arn = aws_lb_target_group.tg["${each.value.tg_name}-${each.value.tg_port}"].arn
target_id = each.value.tg_instance
port = each.value.tg_port
}
ERROR
for_each = { for entry in local.tg_attachments: "${entry.tg_name}-${entry.tg_port}-${entry.tg_instance}" => entry }
│ ├────────────────
│ │ local.tg_attachments is a list of object, known only after apply
│
│ The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many
│ instances will be created. To work around this, use the -target argument to first apply only the resources that the for_each
│ depends on.
3
Answers
I am able to resolve the issue writing the code as follows.
Targert Group attachment
lb variable
web_server variable
As the error suggest, you can’t create resources based on list or maps with unknown arguments at
plan
time. In your case:will only be known after
apply
(not before), and that’s why TF errors out. You either have to refactor your code to have all values known at plan time (changeinstance.id
with something that you know at plan time), or use-target
to create instances first:Your local value result is a wholly-unknown list because you’ve used the
distinct
function. In order to decide the result of that function Terraform must compare all of the values in the list, which includes comparing the instance ids. Because the instance IDs aren’t known yet, Terraform also cannot predict the result of thedistinct
function.However, if you use the instance index instead of the instance ID then Terraform will always know that value during planning, because instance IDs are a Terraform concept rather than a remote API concept:
The index of a list element is the "key" of that element, so you can use the two-symbol form of
for
as shown above to get aninstance_idx
for each element. That’ll settg_instance_idx
to0
,1
,2
… depending on thecount
value foraws_instance.web_servers
. Those index values will always be known during the planning phase, because Terraform always knows thecount
value for a resource during planning.This means that when you set
target_id
you will then need to finally cross-reference with the original resource to get the actual instance ID, like this: