简体   繁体   中英

using a resource with for_each and a list of strings for a single string entry in resource

I'm trying to create loadbalancer target group attachments via a for_eah approach to safe myself a lot of coding time. However I can't seem to use a for_each in a for_each. Does anyone have a pointer on this?


Additional explanation:

The resource aws_lb_target_group_attachment only accepts a single target_id in the form of a string, pointing to an instance ID.

So in this case I would like the resource to be created twice. Once for each target_id in the list of target_ids.


locals {
  dev_alb_defaults = {
    vpc_id      = local.dev_alb_vpc_id
    health_check_enabled              = true
    health_check_interval             = 30
    health_check_timeout              = 5
    health_check_healthy_threshold    = 2
    health_check_unhealthy_threshold  = 2
    health_check_matcher              = 200
  }

  dev_alb_targets = {
    i-am-service = {
      tg_port = 443
      target_ids = [ "i-0123456789ab", "i-0123456789bc" ]
    }
  }
}

resource "aws_lb_target_group" "dev_lb_tg" {
  for_each = { for k, v in local.dev_alb_targets : k => v }

  name     = "${var.customer}-${var.dev_prefix}-${try(each.value.name, each.key)}-tg"
  port     = try(each.value.tg_port, null)
  protocol = try(each.value.tg_protocol, null)
  vpc_id   = try(each.value.vpc_id,local.dev_alb_defaults.vpc_id, null)

  health_check {
    enabled             = try(each.value.health_check_enabled, local.dev_alb_defaults.health_check_enabled, false)
    path                = try(each.value.health_check_path, local.dev_alb_defaults.health_check_path, null)
    port                = try(each.value.health_check_port, each.value.tg_port, null)
    protocol            = try(each.value.health_check_protocol, local.dev_alb_defaults.health_check_protocol, null)
    interval            = try(each.value.health_check_interval, local.dev_alb_defaults.health_check_interval, null)
    timeout             = try(each.value.health_check_timeout, local.dev_alb_defaults.health_check_timeout, null)
    healthy_threshold   = try(each.value.health_check_healthy_threshold, local.dev_alb_defaults.health_check_healthy_threshold, null)
    unhealthy_threshold = try(each.value.health_check_unhealthy_threshold, local.dev_alb_defaults.health_check_unhealthy_threshold, null)
    matcher             = try(each.value.health_check_matcher, local.dev_alb_defaults.health_check_matcher, null)
  }
}

resource "aws_lb_target_group_attachment" "dev_lb_tg" {
  for_each = { for k, v in local.dev_alb_targets : k => v }

  target_group_arn = aws_lb_target_group.dev_lb_tg["${try(each.value.name, each.key)}"].arn
  port             = try(each.value.tg_port, null)
  target_id        = try(each.value.target_ids, null)
  }
}

The effect I hoped it had is: creating only 1 target group and creating 2 aws_lb_target_group_attachments. It creates 1 target group, however it does not create 2 target group attachments. I've tried variants in which I used tolist() for tg_instances or tostring() However I can't get it to accept the input.

╷
│ Error: Incorrect attribute value type
│ 
│   on dev-alb.tf line 288, in resource "aws_lb_target_group_attachment" "dev_lb_tg":
│  288:   target_id        = each.value.target_ids
│     ├────────────────
│     │ each.value.target_ids is list of string with 2 elements
│ 
│ Inappropriate value for attribute "target_id": string required.
╵

Intermediate solution I have right now, which I don't like to use and I would like to condense to a proper solution:

locals {
  dev_alb_defaults = {
    target_id1 = "i-0123456789ab"
    target_id2 = "i-0123456789bc"
  }
  dev_alb_targets = {
    i-am-service = {
      tg_port = 443
    }
  }
}

resource "aws_lb_target_group_attachment" "dev_lb_tg1" {
  for_each = { for k, v in local.dev_alb_targets : k => v }

  target_group_arn = aws_lb_target_group.dev_lb_tg["${try(each.value.name, each.key)}"].arn
  port             = try(each.value.tg_port, null)
  target_id        = local.dev_alb_defaults.target_id1
  }
}

resource "aws_lb_target_group_attachment" "dev_lb_tg2" {
  for_each = { for k, v in local.dev_alb_targets : k => v }

  target_group_arn = aws_lb_target_group.dev_lb_tg["${try(each.value.name, each.key)}"].arn
  port             = try(each.value.tg_port, null)
  target_id        = local.dev_alb_defaults.target_id2
  }
}

You have to flatten you local variable:

locals {
  dev_alb_targets = {
    i-am-service = {
      tg_port = 443
      target_ids = [ "i-0123456789ab", "i-0123456789bc" ]
    }
  }
  
  flat_dev_alb_targets = merge([
        for service, details in local.dev_alb_targets: {
          for target in details.target_ids:
            "${service}-${target}" => {
               tg_port = details.tg_port
               target_id = target
            }
        }
      ]...) # no NOT remove the dots 
}

then

resource "aws_lb_target_group_attachment" "dev_lb_tg" {
  for_each         = local.flat_dev_alb_targets

  target_group_arn = aws_lb_target_group.dev_lb_tg["${try(each.value.name, each.key)}"].arn
  port             = try(each.value.tg_port, null)
  target_id        = try(each.value.target_id, null)
  }
}

Also your code does not show what each.value.name is, so its difficult to speculate on full aspects and requirements on how to flatten it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM