【问题标题】:Merge maps inside list in terraform合并地形列表中的地图
【发布时间】:2019-12-13 21:39:11
【问题描述】:

我有一张这样的地图列表 -

[
  {
    "outer_key_1" = [
      {
        "ip_cidr" = "172.16.6.0/24"
        "range_name" = "range1"
      },
      {
        "ip_cidr" = "172.16.7.0/24"
        "range_name" = "range2"
      },
      {
        "ip_cidr" = "172.17.6.0/24"
        "range_name" = "range3"
      },
      {
        "ip_cidr" = "172.17.7.0/24"
        "range_name" = "range4"
      },
    ]
  },
  {
    "outer_key_2" = [
      {
        "ip_cidr" = "172.16.5.0/24"
        "range_name" = "range5"
      },
      {
        "ip_cidr" = "172.17.5.0/24"
        "range_name" = "range6"
      },
    ]
  },
]

我想合并列表中的地图。这是在输出变量module.module_name.module_op 中。

所需输出:


{
    "outer_key_1" = [
      {
        "ip_cidr" = "172.16.6.0/24"
        "range_name" = "range1"
      },
      {
        "ip_cidr" = "172.16.7.0/24"
        "range_name" = "range2"
      },
      {
        "ip_cidr" = "172.17.6.0/24"
        "range_name" = "range3"
      },
      {
        "ip_cidr" = "172.17.7.0/24"
        "range_name" = "range4"
      },
    ]

    "outer_key_2" = [
      {
        "ip_cidr" = "172.16.5.0/24"
        "range_name" = "range5"
      },
      {
        "ip_cidr" = "172.17.5.0/24"
        "range_name" = "range6"
      },
    ]
}

我已经使用

locals {
  result = merge(module.module_name.module_op[0], module.module_name.module_op[1])
}

我如何以更迭代的方式做到这一点。

我不会总是在我的列表中只有 2 张地图,它可以更多。

我尝试像这样在 terraform 12 中使用 for 循环 -

output "result" {
  value = [ for tuple in module.module_name.module_op : merge(tuple) ]
}

还有这个——

output "secondary_subnets" {
  value = { for tuple in module.module_name.module_op : merge(tuple) }
}

第一个返回我的输入,第二个返回一个错误,提示我需要添加一个键,因为我正在返回一个对象。

有没有办法做到这一点?

提前致谢。

【问题讨论】:

    标签: for-loop terraform


    【解决方案1】:

    您实际上可以将地图列表传递给merge() 函数:

    Terraform 语言具有将列表/元组转换为多个参数的一般功能,方法是在最后一个参数表达式后使用特殊符号 ...

    因此,在上面的示例中,您可以这样做:

    locals {
      result = merge(module.module_name.module_op...)
    }
    

    这将合并列表中的所有地图,允许动态调整大小的列表。

    【讨论】:

    • 非常感谢!我在 terraform 文档中只能找到 Splat Expressions,它返回一个元组,因此与 merge() 不兼容。
    • 非常感谢。这是在 terraform 文档中提到的任何地方吗?我发现它的唯一方法是谷歌在 terraform github 上打开的已关闭问题。
    • @DanielHajduk 它在 HCL 规范中定义:github.com/hashicorp/hcl/blob/main/hclsyntax/… 如果在 terraform 文档中提到它会很好。
    【解决方案2】:

    很遗憾,您的地图中的values() 是列表。否则,您可以执行以下操作,这将适用于 list(map(<not_list>))

    例如

    locals {
      my_list_of_maps = [
        {
           key1 = "val1"
           key2 = "val2"
        },
        {
           key3 = "val3"
        },
      ]
    }
    
    zipmap(
      flatten(
        [for item in local.my_list_of_maps : keys(item)]
      ),
      flatten(
        [for item in local.my_list_of_maps : values(item)]
      )
    )
    

    这将像这样处理

    zipmap(
      flatten([["key1", "key2"], ["key3"]]),
      flatten([["val1", "val2"], ["val3"]])
    )
    

    =>

    zipmap(
      ["key1", "key2", "key3"],
      ["val1", "val2", "val3"]
    )
    

    =>

    {
      key1 = "val1"
      key2 = "val2"
      key3 = "val3"
    }
    

    我在这里使用了简单的list(map(string)),但地图的values() 可能更复杂。然而,由于使用了flatten()(递归地展平嵌套列表),values() 本身不能是列表。

    为了让它发挥作用,您始终可以将数据转换为如下所示:

    [
      {
        "outer_key_1" = {
          range1 = "172.16.6.0/24"
          range2 = "172.16.7.0/24"
          range3 = "172.17.6.0/24"
          range4 = "172.17.7.0/24"
        }
      },
      {
        "outer_key_2" = {
          range5 = "172.16.5.0/24"
          range6 = "172.17.5.0/24"
        }
      },
    ]
    

    上述逻辑将毫无问题地工作。

    顺便说一句,zipmap() 的行为类似于merge()。所以如果有重复的钥匙,迟到的会覆盖现有的钥匙。

    【讨论】:

    • 你可以像这样转换你的数据:[for outer in <input> : {for key, val in outer : key => {for inner in val : inner["range_name"] => inner["ip_cidr"]}}]
    猜你喜欢
    • 2021-10-10
    • 2019-05-02
    • 2020-10-26
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    相关资源
    最近更新 更多