Terraform For expression使用一个元组和两个字符串列表,创建一个映射以用于每个元素

Terraform For expression使用一个元组和两个字符串列表,创建一个映射以用于每个元素,terraform,Terraform,如何使用一个元组和两个字符串列表为每个对象创建一个要在中使用的对象映射 假设我有一个来自ec2模块的实例ID或实例IP的元组/列表和一个来自ALB模块的目标组ARN的元组/列表,如下所示 instance_ids = ["10.1.1.1", "10.2.2.2"] target_gropup_arn = ["arn1", "arn2"] 在main.tf中 output "out"

如何使用一个元组和两个字符串列表为每个对象创建一个要在中使用的对象映射

假设我有一个来自ec2模块的实例ID或实例IP的元组/列表和一个来自ALB模块的目标组ARN的元组/列表,如下所示

instance_ids      = ["10.1.1.1", "10.2.2.2"]
target_gropup_arn = ["arn1", "arn2"]
在main.tf中

output "out" {
  value = local.aws_lb_target_group_attachment
}
variable "target_groups" {
  type = any
  default = [
    {
      protocol = "TCP"
      port     = "22"
    },
    {
    protocol = "TCP"
    port     = "443"
    }
  ]
}
locals {
  instance_ips      = toset(["10.1.1.1", "10.2.2.2"])
  target_gropup_arn = toset(["arn1", "arn2"])

  aws_lb_target_group_attachment = { for idx in flatten([for instance_ids in local.instance_ids :
  [for tg in var.target_groups :
  [for arn in local.target_gropup_arn :
  {
    target_id = instance_ids
    target_group_arn = arn
    port = tg.port
  }]
  ]]) : "${idx.target_id}:${idx.port}:${idx.target_group_arn}" => idx }
}
当我运行terraform apply时,我得到以下输出,但这不是我所需要的预期映射

Outputs:

out = {
  "10.1.1.1:22:arn1" = {
    "port" = "22"
    "target_group_arn" = "arn1"
    "target_id" = "10.1.1.1"
  }
  "10.1.1.1:22:arn2" = {
    "port" = "22"
    "target_group_arn" = "arn2"
    "target_id" = "10.1.1.1"
  }
  "10.1.1.1:443:arn1" = {
    "port" = "443"
    "target_group_arn" = "arn1"
    "target_id" = "10.1.1.1"
  }
  "10.1.1.1:443:arn2" = {
    "port" = "443"
    "target_group_arn" = "arn2"
    "target_id" = "10.1.1.1"
  }
  "10.2.2.2:22:arn1" = {
    "port" = "22"
    "target_group_arn" = "arn1"
    "target_id" = "10.2.2.2"
  }
  "10.2.2.2:22:arn2" = {
    "port" = "22"
    "target_group_arn" = "arn2"
    "target_id" = "10.2.2.2"
  }
  "10.2.2.2:443:arn1" = {
    "port" = "443"
    "target_group_arn" = "arn1"
    "target_id" = "10.2.2.2"
  }
  "10.2.2.2:443:arn2" = {
    "port" = "443"
    "target_group_arn" = "arn2"
    "target_id" = "10.2.2.2"
  }
}
预期输出为(伪输出)


这是必需的,以便以后我可以使用它使用“aws_lb_target_group_attachment”资源来附加多个实例。

您的技术没有按您所知的那样工作,因为您正在创建ip和arn的笛卡尔积,但根据您的示例输出,您只希望第一个ip与第一个arn分组,以及要与第二arn分组的第二ip

以下是一个可行的解决方案: 细分: 在这里,我们循环遍历IP列表,并构建一个新映射,其中包含您希望在最终输出中使用的三个键中的两个。我们利用了ips和ARN之间存在1-1映射的事实。也就是说,第一个ip对应于第一个arn,第二个ip对应于第二个arn,依此类推

  aws_lb_target_group_attachment = merge([for tg in var.target_groups :
    { for pair in local.arn_id_map :
      "${pair.target_id}:${tg.port}" => merge(pair, { "port" : tg.port })
    }
  ]...)
从第一个循环开始,我们迭代目标组,创建一个列表理解,这意味着该层的值将是一个列表。然后在内部进行地图理解,迭代上一步创建的ip+arn对

在内部,我们创建了一个地图,其结构是您想要的最终输出。内部合并是获取ip+arn对并使用端口创建新映射的干净方法

但随着层的展开,我们最终得到一个包含两个映射的列表,每个映射包含2个子映射(每个ip+端口组合对应一个子映射)。我们需要“展平”结构,但是
flatte()
在地图列表上不起作用

要“展平”映射,我们通常会访问
merge()
,但在本例中,它并不直接起作用,因为
merge()
希望每个参数都是映射。但我们有一份地图清单。因此,我们使用
将列表传递到merge中,并将其展开为merge可以直接接受的参数

结果如您所愿:

out = {
  "10.1.1.1:22" = {
    "port" = "22"
    "target_group_arn" = "arn1"
    "target_id" = "10.1.1.1"
  }
  "10.1.1.1:443" = {
    "port" = "443"
    "target_group_arn" = "arn1"
    "target_id" = "10.1.1.1"
  }
  "10.2.2.2:22" = {
    "port" = "22"
    "target_group_arn" = "arn2"
    "target_id" = "10.2.2.2"
  }
  "10.2.2.2:443" = {
    "port" = "443"
    "target_group_arn" = "arn2"
    "target_id" = "10.2.2.2"
  }
}

有人能帮我解决这个问题吗?嗨@Casey,这个解决方案似乎奏效了,但我遇到了一个问题,如果实例ID如下所示,那么我的实例数比目标组的实例数多。实例ID=[“10.1.1.1”,“10.2.2.2.2”,“10.2.2.1”]目标\u arns=[“arn1”,“arn2”]错误:main.tf第23行的索引无效,局部变量中:23:arn_id_map=[对于i,local.instance_id:{“target_id”:id,“target_group_arn”:local.target_arns[i]}]|--------------------local.target_arns是包含2个元素的元组,给定的键未标识此集合值中的元素。
  arn_id_map = [for i, id in local.instance_ids : { "target_id" : id, "target_group_arn" : local.target_arns[i] }]
  aws_lb_target_group_attachment = merge([for tg in var.target_groups :
    { for pair in local.arn_id_map :
      "${pair.target_id}:${tg.port}" => merge(pair, { "port" : tg.port })
    }
  ]...)
out = {
  "10.1.1.1:22" = {
    "port" = "22"
    "target_group_arn" = "arn1"
    "target_id" = "10.1.1.1"
  }
  "10.1.1.1:443" = {
    "port" = "443"
    "target_group_arn" = "arn1"
    "target_id" = "10.1.1.1"
  }
  "10.2.2.2:22" = {
    "port" = "22"
    "target_group_arn" = "arn2"
    "target_id" = "10.2.2.2"
  }
  "10.2.2.2:443" = {
    "port" = "443"
    "target_group_arn" = "arn2"
    "target_id" = "10.2.2.2"
  }
}