【问题标题】:Terraform - inverting a mapTerraform - 反转地图
【发布时间】:2020-12-05 01:03:01
【问题描述】:

我一直在尝试编写一个可以改变这个的 terraform 表达式:

subnets = {
   my_subnet_1 = {
     nsg       = "my_nsg_1",
     addresses = "my_addresses_1"
   }
   my_subnet_2 = {
     nsg       = "my_nsg_2",
     addresses = "my_addresses_2"
   }
}

进入

nsgs_assocs = {
  my_nsg_1 = "my_subnet_1"
  my_nsg_2 = "my_subnet_2"
}

我尝试了以下方法:

locals {
  nsgs_assocs = zipmap(
    var.subnets.*.nsg,
    keys(var.subnets)
  )
}

但这会报错:

Error: Invalid function argument

  on ..\..\modules\vnet\main.tf line 22, in locals:
  21:   nsgs_assocs = zipmap(
  22:     var.subnets.*.nsg,
  23:     keys(var.subnets)
  24:   )

Invalid value for "keys" parameter: element 0: string required.

对于上下文,我继承了一堆脚本,我试图在不更改 terraform plan 的结果的情况下对其进行重构。

其中一个模块有很多相关的查找图 - 例如:

nsgs_assocs = {
  my_nsg_1 = "my_subnet_1"
  my_nsg_2 = "my_subnet_2"
}

subnet_addresses = {
  my_subnet_1 = "my_addresses_1"
  my_subnet_2 = "my_addresses_2"
}

我已将其浓缩为我上面的第一个示例,我认为从长远来看它更易于维护。

但是,为了向后兼容现有的 terraform 状态,我需要在我的模块中生成原始的 nsgs_assocs,以便 for_each 继续使用 nsg 名称作为资源键而不是子网名称(这会导致由于密钥更改而销毁/创建对)。

【问题讨论】:

  • 预期的结果是什么?
  • @marcin - 我试图让我的本地 nsg_assocs 与原始值相同,但使用新的 subnets 作为数据源。我会尽快更新问题以澄清......

标签: terraform


【解决方案1】:

你在正确的轨道上。它不起作用,因为splat expression 与数组一起工作,而var.subnets 是一个映射。为了修复它,您需要将其转换为数组,可以使用values terraform function来完成:

locals {
  nsgs_assocs = zipmap(
    values(var.subnets)[*].nsg,
    keys(var.subnets)
  )
}

【讨论】:

  • 啊,我的根本问题在于“splat”文档的小字体 - “如果将 splat 表达式应用于不是列表或元组的值,则该值会自动包装在处理前的单元素列表”。我的var.subnets.*.nsg 实际上是在做[var.subnets].*.nsg。有趣的是,这在控制台中失败并出现错误“此地图没有键为“nsg”的元素”但我在terraform plan 中得到Invalid value for "keys" parameter: element 0: string required.(除非我误解了splat 操作的效果
  • 我才刚刚找到terraform console,如果我之前知道的话,这会节省我几个小时:-)。
【解决方案2】:

如果你有:

variable "subnets" {
    default = {
       my_subnet_1 = {
         nsg       = "my_nsg_1",
         addresses = "my_addresses_1"
       }
       my_subnet_2 = {
         nsg       = "my_nsg_2",
         addresses = "my_addresses_2"
       }
    }
}

那么下面的不正确

var.subnets.*.nsg

因此,应该是values(var.subnets).*.nsg:

locals {
  nsgs_assocs = zipmap(
    values(var.subnets).*.nsg,
    keys(var.subnets)
  )
}

导致:

{
  "my_nsg_1" = "my_subnet_1"
  "my_nsg_2" = "my_subnet_2"
}

【讨论】:

  • +1 以获得有效的答案,但我已经接受了@rkm's,因为它涉及 为什么 我最初的尝试也失败了,这帮助我了解了什么正在进行中。
【解决方案3】:

有几种不同的方法可以实现这一点,其他人分享的基于zipmap 的解决方案也是很好的答案,但我也想展示一个使用for expressions 的示例,因为我(主观上)倾向于这样认为表格最容易阅读和理解:

locals {
  nsgs_allocs = {
    for k, s in var.subnets : s.nsg => k
  }
}

只要您的所有子网都具有唯一的 nsg 值,上述内容应该会产生您正在寻找的结果。

在新键不是唯一的情况下——例如,如果在您的情况下可能有多个具有相同nsg 值的子网——您可以使用for表达式的“分组”模式,它将生成子网值列表的映射,因此每个键下可能有多个值:

locals {
  nsgs_allocs = {
    for k, s in var.subnets : s.nsg => k...
  }
}
nsgs_assocs = {
  my_nsg_1 = ["my_subnet_1"]
  my_nsg_2 = ["my_subnet_2"]
}

【讨论】:

  • 我对 terraform 非常陌生,所以在遍历地图时知道 for k, v: 很有用。我不确定我是否被... 操作符迷住了。来自 C#/Linq 背景,group 函数不会那么刺耳,但至少如果我现在在野外找到它,我会知道它是什么 :-)。
猜你喜欢
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-09
  • 2021-08-03
相关资源
最近更新 更多