Terraform:将变量列表更改为一个地图列表

Terraform: changing a list of variables into one list of maps

我有 3 个 terraform 变量,它们是列表。

container_ports = [5000, 5001]
container_names = ["image1", "image2"]
load_balancer_arns = ["lb1", "1b2"]

如何将结构更改为如下所示的地图列表?

ecs_service_lb_config = [
   {
    container_port = 5000
    container_name = "image1"
    load_balancer_arn = "lb1
   },{
    container_port = 5001
    container_name = "image2"
    load_balancer_arn = "lb2
   }
]    

一个简单的方法可以是:

ecs_service_lb_config = [
 {
   container_port = element(container_port, 0)
   container_name = element(container_name, 0)
   load_balancer_arn = element(load_balancer_arn, 0)
 },{
   container_port = element(container_port, 1)
   container_name = element(container_name, 1)
   load_balancer_arn = element(load_balancer_arn, 1)
 }
]  

这里的问题不是自动缩放代码,因为如果您需要添加更多元素,则需要将新块添加到地图中。 我正在寻找更好的解决方案,但这可能是一个快速解决方案。

但是如果我知道你为什么要使用 3 个不同的变量,如果你能给我一个更好的上下文,也许我可以给你一个最干净的解决方案。

如果您有权更改此模块的接口,那么我建议通过重新定义变量以到达您需要的对象列表来从根本上解决问题:

variable "ecs_service_load_balancers" {
  type = list(object({
    container_port    = number
    container_name    = string
    load_balancer_arn = string
  }))
}

请注意,这是对象列表而不是地图列表,因为我们指定了所需的特定属性,而不是仅仅调用调用者选择的任意 key/value 对。

模块的调用者随后将使用您在问题中显示的相同语法来指定它:

module "example" {
  # ...

  ecs_service_load_balancers = [
    {
      container_port    = 5000
      container_name    = "image1"
      load_balancer_arn = "lb1
    },
    {
      container_port    = 5001
      container_name    = "image2"
      load_balancer_arn = "lb2"
    },
  ]
}

这种结构的一个好处是,哪些属性值属于哪些对象更清晰;调用的 reader 无需通过索引仔细关联即可了解哪个是哪个。


如果您无法更改此模块的接口,但您仍希望将这些收集到内部模块中的对象列表中,那么您可以基于编程方式创建相同的数据结构关于单个变量值。

variable "container_ports" {
  type = list(number)
}

variable "container_names" {
  type = list(string)
}

variable "load_balancer_arns" {
  type = list(string)
}

locals {
  ecs_service_load_balancers = tolist([
    for i, n in var.container_names : {
      container_port    = var.container_ports[i]
      container_name    = var.container_names[i]
      load_balancer_arn = var.load_balancer_arns[i]
    }
  ])
}

这对其中一个变量使用了 for expression(我随意选择了 var.container_names,但实际上并不重要)并指定 i, n 作为局部符号,以便 i 将是列表索引。 for 表达式的主体然后可以使用 i 索引到所有三个列表,依赖于它们应该始终具有相同长度并且始终具有相关项的事实。

我需要声明符号 n 因为总是需要为当前元素值声明一个符号,但我没有内联使用它,因为我写出了 var.container_names[i] 而不是获取以与其他两个属性定义一致的方式使用相同的值,希望将来 reader 更容易理解此表达式的目标。

然后您可以使用 local.ecs_service_load_balancers 来获取与我在上面显示的单个对象列表变量声明生成的对象列表类似的对象列表。