【问题标题】:How to Use a Non-unique Key in Terraform Resource Loop to Create Unique Resources如何在 Terraform 资源循环中使用非唯一键创建唯一资源
【发布时间】:2021-05-21 04:28:59
【问题描述】:

我想使用通用模块为域创建每种类型的 DNS 记录,因此可以使用以下方式调用它:

module "example_com_dns" {
  source = "[PATH_TO_MODULES]/modules/dns"

  domain  = "example.com"

  a_records = {
    "@"    = [SOME IP]
    "www"  = [SOME IP]
    "home" = [SOME IP]
  }

  txt_records = {
    "@"                    = "txt-foobar1"
    "@"                    = "txt-foobar2"
    "mail._domainkey.self" = "foobar"
  }

  mx_entries = {
     "10" = "mail.someprovider.com"
     "20" = "mail2.someprovider.com"
  }

  cname_records {
    "cname-foo" = "cname-bar
  }
}

我有一些适用于 A、CNAME 和 MX 记录的东西,但 TXT 有一个我需要解决的极端情况。我的模块为每种类型的记录都有资源块,这些记录通过循环运行。我只是粘贴 TXT 的,但它们都是一样的:

resource "digitalocean_record" "this_txt_record" {
  for_each = var.txt_records

  domain = var.domain
  type   = "TXT"
  name   = each.key
  value  = each.value
}

这一切都很好,除了因为有 2 条记录的键为“@”,因此只创建了最后一条记录(在我上面的示例中,这是"txt-foobar2"):


...

  # module.example_com.digitalocean_record.this_txt_record["@"] will be created
  + resource "digitalocean_record" "this_txt_record" {
      + domain = "example.com"
      + fqdn   = (known after apply)
      + id     = (known after apply)
      + name   = "@"
      + ttl    = (known after apply)
      + type   = "TXT"
      + value  = "txt-foobar2"
    }

我希望它同时创建“txt-foobar1”和“txt-foobar2”,即使在地图中给定非唯一键。

也许这是错误的方法,我只需要找出一个聪明的循环来解析这个结构吗?:

  txt_records = [
    { "@" = "foo" },
    { "@" = "bar"},
    { "mail._domainkey.self" = "foobar"}
  ]

如果是这样,我目前也失败了:)

【问题讨论】:

  • 在您提议的新结构中,"mail._domainkey.self" = "foobar" 会在哪里?
  • 哦,在同一个列表中,我只是忘了添加它。我现在编辑了问题中的示例以包含它。
  • mail._domainkey.self" 是常量字符串,还是可以取不同的值?
  • 那个总是一样的,但这只是一个例子。大多数情况下,您会有一个 TXT 的唯一记录映射(对于某些其他记录类型,我相信它甚至是强制性的),但是对于我们需要设置 SPF 记录之类的用例,我们总是使用“@ "。

标签: terraform digital-ocean


【解决方案1】:

资源不能通过for_each'ing 列表来创建,因为必须有一个唯一键将成为 terraform 资源名称的一部分。列表索引不能是可靠的键,因为如果您重新排序列表中的项目,您的 TF 计划将全部搞砸。

另一方面,根据定义,地图确实具有唯一键。

您可以从列表中生成地图!我发现了这个小技巧here。请注意,您还需要手动计算唯一映射键(以下示例中的 ${txt_record[0]}=${txt_record[1]})。

您的资源已更新:

module "example_com_dns" {
  ...

  txt_records = [
    ["@",                     "txt-foobar1"],
    ["@",                     "txt-foobar2"],
    ["mail._domainkey.self",  "foobar"],
  ]
}
resource "digitalocean_record" "this_txt_record" {
  for_each = {for txt_record in var.txt_records: "${txt_record[0]}=${txt_record[1]}" => txt_record}

  domain = var.domain
  type   = "TXT"
  name   = each.value[0]
  value  = each.value[1]
}

如果您愿意,也可以稍微详细一点:

module "example_com_dns" {
  ...

  txt_records = [
    {name: "@", value: "txt-foobar1"},
    {name: "@", value: "txt-foobar2"},
    {name: "mail._domainkey.self", value: "foobar"},
  ]
}
resource "digitalocean_record" "this_txt_record" {
  for_each = {for txt_record in var.txt_records: "${txt_record.name}=${txt_record.value}" => txt_record}

  domain = var.domain
  type   = "TXT"
  name   = each.value.name
  value  = each.value.value
}

【讨论】:

  • 这就是我想要的。我正在努力联系each.value.value。另外,我不知道在这样的地图中使用: 进行分配。这和使用=有什么区别吗?我在 HCL 规范中找不到任何对它的引用。
  • @Afraz 对,=: 都可以使用。检查github.com/hashicorp/hcl/blob/main/hclsyntax/…objectelem定义)
【解决方案2】:

已经给出的替代方法是使用以下内容:

 variable "txt_records" {
  default = {
       "@" = ["foo", "bar"],
       "mail._domainkey.self" = ["foobar"]
       }
 }

然后您可以使用以下方法展平txt_records

locals {

  txt_records_flat = merge([
      for key, values in var.txt_records:
        {for value in values: 
           "${key}-${value}" => {"record_name" = key, "record_value" = value}
        }
  ]...)
}

导致local.txt_records_flat of:

{
  "@-bar" = {
    "record_name" = "@"
    "record_value" = "bar"
  }
  "@-foo" = {
    "record_name" = "@"
    "record_value" = "foo"
  }
  "mail._domainkey.self-foobar" = {
    "record_name" = "mail._domainkey.self"
    "record_value" = "foobar"
  }
}

那你就用它吧:

resource "digitalocean_record" "this_txt_record" {
  for_each = local.txt_records_flat

  domain = var.domain
  type   = "TXT"
  name   = each.value.record_name
  value  = each.value.record_value
}

【讨论】:

  • 我没有尝试过这个,我选择了 Max 的答案,但我很确定它也会起作用,所以谢谢!
猜你喜欢
  • 2019-07-01
  • 1970-01-01
  • 2020-12-17
  • 2022-07-28
  • 2022-07-24
  • 2021-12-08
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
相关资源
最近更新 更多