Convert to map(objects)

Hi @jprouten,

You do seem close indeed!

The two important rules for for_each are:

  1. You must have a collection that has one element for each instance you want to declare.
  2. It must be possible to select or generate a unique string for each element only from values defined directly in the configuration to serve as its instance key.

It looks like you’ve already dealt with rule 1 in your local.nlb_config value, where you have one element for each combination of “nlbs” and “ec2s”, which seems like the right cardinality for an aws_lb_target_group_attachment.

I think the challenge for rule 2 is that the only unique identifier you have for your EC2 instances is the ID chosen by the remote system. That isn’t defined directly in your configuration (it’ll only be known after apply) and so it isn’t suitable to use as part of a unique key for for_each. Instead, you’ll need to select some other unique key that’s based on something your configuration decided, rather than something the remote system decided.

However, I noticed your var.target_id is itself a map of objects and so the keys from that map could potentially serve as the unique keys for your EC2 instances, if you adjust ec2sflat like this:

locals {
  ec2sflat = [
    for key, ec2 in var.target_id : {
      ec2_id  = ec2.id
      ec2_key = key
    }
  ]
}

To keep things unambiguous, let’s also rename the key attribute from local.nlbsflat elements to nlb_key, and thus the final merged data structure will have both ec2_key and nlb_key in each of its attributes, and then we can meet rule 2 by projecting the set into a map with another for expression:

resource "aws_lb_target_group_attachment" "this" {
  for_each = {
    for cfg in local.nlb_config : "${cfg.nlb_key}:${cfg.ec2_key}" => cfg
  }

  target_group_arn = aws_lb_target_group.this[each.value.nlb_key].arn
  target_id        = each.value.ec2_id
  port             = var.target_group_attachment_port
}

I think that local.nlb_config isn’t the right data structure for some of your other resources though, if I’m understanding the relationships correctly. It seems like you only need one aws_lb_target_group and aws_lb_listener per entry in var.nlb_target_group, because neither of those refer to any of the EC2 properties and so I don’t think you want to create a separate target group and listener for each EC2 instance.