【问题标题】:Are terraform "loops" useless? Or am I missing something?terraform“循环”没用吗?还是我错过了什么?
【发布时间】:2019-03-14 07:48:50
【问题描述】:

我今天写了一些使用“循环”的配置,但后来我才想知道这是否是正确的路径,因为 terraform 将状态文件中的资源作为列表/数组保存。

考虑以下配置:

locals {
    users_list = [ "ab", "cd", "ef" ]
}

resource "aws_iam_user" "users" {
    count = "${length(local.users_list)}"
    name = "${local.users_list["${count.index}"]}"
    path = "/"
}

运行 'terraform apply' 将创建用户,并在状态文件中创建以下资源:

  • aws_iam_user.users[0]
  • aws_iam_user.users[1]
  • aws_iam_user.users[2]

但是,例如,如果我删除了前两个用户中的一个,如下所示:

locals {
        users_list = [ "cd", "ef" ]
}

然后 terraform 将尝试更改状态文件 ( [0] --> "cd", [1] --> "ef" ) 中的资源,以及 AWS 中的用户本身,这可能是灾难性的,因为每个用户都有自己的密钥,这样做会造成混乱。这也与其他资源类型有关,虽然有些资源删除并重新创建不会造成如此混乱,但这仍然是错误的。

所以,对于我的问题,如标题所示 - 也许我完全错了?或者这就是它的工作方式? (使整个“循环”机制无用)

【问题讨论】:

  • 在上述情况下删除 ab 用户会导致什么问题?键是否也在数组中创建?

标签: terraform


【解决方案1】:

实际上 v0.11.x 之前的 terraform 并没有正式支持循环。使用count.index作为循环的方式来自博客Terraform tips & tricks: loops, if-statements, and gotchas

从 0.12 版本开始(目前仍处于测试阶段),它支持带有新关键字 for_each 的循环,但我仍然不保证它是否能解决您的问题。

所以我详细说明了问题是什么,以及如何解决它,像@Aniket Chopade 这样的人可以理解这个问题的根源。

更改本地人后,

$ terraform apply -auto-approve
aws_iam_user.users[0]: Refreshing state... (ID: ab)
aws_iam_user.users[1]: Refreshing state... (ID: cd)
aws_iam_user.users[2]: Refreshing state... (ID: ef)
aws_iam_user.users[2]: Destroying... (ID: ef)
aws_iam_user.users[1]: Modifying... (ID: cd)
  name: "cd" => "ef"
aws_iam_user.users[0]: Modifying... (ID: ab)
  name: "ab" => "cd"
aws_iam_user.users[2]: Destruction complete after 2s

Error: Error applying plan:

2 error(s) occurred:

* aws_iam_user.users[0]: 1 error(s) occurred:

* aws_iam_user.users.0: Error updating IAM User ab: EntityAlreadyExists: User with name cd already exists.
    status code: 409, request id: 24853da7-452c-11e9-a853-bf4c89d8ebba
* aws_iam_user.users[1]: 1 error(s) occurred:

* aws_iam_user.users.1: Error updating IAM User cd: EntityAlreadyExists: User with name ef already exists.
    status code: 409, request id: 24839027-452c-11e9-b3d5-3deb12943195

我必须taint这些资源,标记为销毁并再次申请。

$ terraform taint aws_iam_user.users.1
The resource aws_iam_user.users.1 in the module root has been marked as tainted!

$ terraform taint aws_iam_user.users.0
The resource aws_iam_user.users.0 in the module root has been marked as tainted!

$ terraform apply -auto-approve
...
aws_iam_user.users[0]: Destroying... (ID: ab)
aws_iam_user.users[1]: Destroying... (ID: cd)
aws_iam_user.users[0]: Destruction complete after 2s
aws_iam_user.users[0]: Creating...
  arn:           "" => "<computed>"
  force_destroy: "" => "false"
  name:          "" => "cd"
  path:          "" => "/"
  unique_id:     "" => "<computed>"
aws_iam_user.users[1]: Destruction complete after 2s
aws_iam_user.users[1]: Creating...
  arn:           "" => "<computed>"
  force_destroy: "" => "false"
  name:          "" => "ef"
  path:          "" => "/"
  unique_id:     "" => "<computed>"

我的结论是,在当前情况下,taint 强制 terraform 创建新资源的资源如果您更改列表中的顺序

【讨论】:

  • 感谢您的回答。作为一种解决方法,我宁愿只更改状态下的数组(使用terraform state mv),这样其他用户就会保持原样,只有我删除的用户会被销毁。但这当然太混乱了。另外,如果资源仍然是状态文件中的数组,我不确定 0.12 版中的 for_each(或 for)循环是否会有所帮助。您提供的链接中的示例是资源内部的动态时钟。我认为实现这一目标的唯一方法是以下两种方法之一:(在下一条评论中)
  • 1. Terraform 应该将状态文件中的资源保存为资源映射/哈希而不是数组,这样它就会知道哪个用户属于哪里。 2. 资源仍然会保存为数组,但是 terraform 会做一些计算来了解我是否刚刚从列表中删除了一个项目。也许我会为此打开一个功能请求,但我不确定 terraform 的内部以及这些选项是否有意义。
  • @roeezab 不,terraform state mv 根本没有解决这个问题。 terraform state rm 仅用于从 tfstate 文件中清理指定的资源,而不是真正清理 aws 帐户中的资源。 taint 将标记要销毁的资源,因此terraform apply 将始终先销毁这些受污染的资源,然后再应用其余更改。
  • 同意直接向 GitHub 中的 terraform 团队提出功能/错误请求。
  • 这并非完全正确。 count 一直被正式用于创建多个资源(否则它有什么意义),其中包括 API 没有要传递给它的计数概念的地方(例如,EC2 实例允许您指定在单个 API 调用中在预留中创建的多个实例)。 0.12 确实在资源中添加了额外的循环功能,它最终将取代count 语法,但count 仍然对资源有效。此外,0.12 将正确处理自动删除 count 资源中的非最后一个元素。
猜你喜欢
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 2014-03-14
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多