具有动态列表的Terraform将在索引更改时重新创建资源

时间:2020-02-07 17:43:23

标签: terraform

使用动态列表时,如果添加或删除条目,则更改索引​​之后的每个条目都会更新。
如何让terraform仅插入新条目?

示例

我有一个清单

  • 10
  • 20
  • 30

(适用地形)

现在将我的列表更改为添加15

  • 10
  • 15
  • 20
  • 30

(适用地形) Terraform将替换20-> 15,30-> 20并创建30

简单的解决方案

一种解决方案是自行声明每个元素(不使用列表)

复杂的解决方法

在申请之前,我可以直接更改状态文件以更改索引。 这似乎很危险。

更多上下文

我有一个包含数百个dns条目的json数据文件。 我使用data.external

将其加载到列表中
data "external" "read_dns_entries" {
   program = [ "${path.module}/terraform_script_dns_entries_from_file" ]
}

locals {
  file_dns_records_without_aliases = jsondecode(data.external.read_dns_entries.result.EntriesWithoutAlias)
}

resource "aws_route53_record" "record" {
  count = length(local.file_dns_records_without_aliases)

  zone_id         = local.file_dns_records_without_aliases[count.index].ZoneID
  name            = local.file_dns_records_without_aliases[count.index].Name
  type            = local.file_dns_records_without_aliases[count.index].Type
  allow_overwrite = true
  ttl             = local.file_dns_records_without_aliases[count.index].TTL
  records         = local.file_dns_records_without_aliases[count.index].Records

  lifecycle {
    create_before_destroy = true
  }
}

我正在使用Terraform v0.12.18

参考文献

这个封闭的问题正在谈论它。 https://github.com/hashicorp/terraform/issues/3449

这是希望Terraform 0.12可以使用for_each进行修复
Are terraform "loops" useless? Or am I missing something?

1 个答案:

答案 0 :(得分:1)

如果您可以使用Terraform 0.12.x或更高版本,请考虑选择

  1. for_each而非count
  2. 使用地图代替输入数据表示列表(因为for_each在地图上运行)

一个人可以用{ for item in list: key => value }表达式从列表中组成地图(请参见https://www.terraform.io/docs/configuration/expressions.html#for-expressions)。与count通过位置跟踪资源相反,for_each通过id(映射键)跟踪状态下资源的表示。由于位置随着新资源的插入或删除而不断变化/变化,因此这是一个相当脆弱的结构。这就是为什么人们会在对资源列表进行改组,插入或删除之后注意到对计划进行许多破坏/创建操作的原因;)。

为便于记录,以下是清洁器设置的摘要:

data "external" "read_dns_entries" {
  program = ["${path.module}/terraform_script_dns_entries_from_file"]
}

locals {
  #file_dns_records_without_aliases = jsondecode(data.external.read_dns_entries.result.EntriesWithoutAlias)
  file_dns_records_without_aliases = {
    for entry in jsondecode(data.external.read_dns_entries.result.EntriesWithoutAlias) :
    entry.Name => entry
  }
}

resource "aws_route53_record" "record" {
  # count = length(local.file_dns_records_without_aliases)
  for_each = local.file_dns_records_without_aliases

  zone_id         = each.value.ZoneID
  name            = each.value.Name
  type            = each.value.Type
  allow_overwrite = true
  ttl             = each.value.TTL
  records         = each.value.Records

  lifecycle {
    create_before_destroy = true
  }
}

P.S .:似乎data.external在这里不是很惯用,而使用file("${path.module}/terraform_script_dns_entries_from_file")进行争论会更清楚,因为其目的只是读取文件的内容。