Terraform:如何删除从数组/列表创建的用户资源?

标签 terraform

我有一个 users.tf 文件,它为 aws 创建管理员用户。它通过定义一个列表来做到这一点(例如 users = ["bob", "john", "tom"])

然后使用 terraform 中的 count 功能使用 aws_iam_user 资源对其进行迭代,如下所示:

resource "aws_iam_user" "user" {
  count = length(local.users)
  name  = local.users[count.index]
}

这里的问题是,如果我删除数组的第一个元素(上例中的“bob”),terraform 在发出 terraform plan 后会建议做什么,而不是删除 bob ,就是把bob改成john,把john改成tom,删除tom。

像这样:

  # aws_iam_user.user[0] will be updated in-place
  ~ resource "aws_iam_user" "user" {
        arn           = "arn:aws:iam::5555555:user/bob"
        force_destroy = false
        id            = "bob"
      ~ name          = "bob" -> "john"
        path          = "/"
        tags          = {}
        unique_id     = "BLABLABLA11111"
    }

  # aws_iam_user.user[1] will be updated in-place
  ~ resource "aws_iam_user" "user" {
        arn           = "arn:aws:iam::5555555:user/john"
        force_destroy = false
        id            = "john"
      ~ name          = "john" -> "tom"
        path          = "/"
        tags          = {}
        unique_id     = "BLABLABLA22222"
    }

  # aws_iam_user.user[2] will be destroyed
  - resource "aws_iam_user" "user" {
      - arn           = "arn:aws:iam::5555555:user/tom" -> null
      - force_destroy = false -> null
      - id            = "tom" -> null
      - name          = "tom" -> null
      - path          = "/" -> null
      - tags          = {} -> null
      - unique_id     = "BLABLABLA3333" -> null

这将导致 john 获得 bob 的 arn,而 tom 获得 john 的 arn。这是不可取的。

我尝试使用 very new feature (在写这个问题前 19 小时发布)for_each 循环而不是计数,并将键定义为原始索引号,希望 terraform 将它们视为相同的资源。

是的,没有这样的运气:

...
# aws_iam_user.user[1] will be destroyed
...
# aws_iam_user.user["1"] will be created
...

我总结一下我的问题:

当资源是通过遍历列表创建的时,是否有任何方法可以删除该资源(特别是 aws_iam_user),以便所有剩余资源保持原样?

最佳答案

你在这里看到的是the count documentation的情况在最后一段中警告:

Note that the separate resource instances created by count are still identified by their index, and not by the string values in the given list. This means that if an element is removed from the middle of the list, all of the indexed instances after it will see their subnet_id values change, which will cause more remote object changes than were probably intended. The practice of generating multiple instances from lists should be used sparingly, and with due care given to what will happen if the list is changed later.

幸运的是,这正是 for_each 特性旨在解决的问题。不过,为了有效地使用它,在传递给 for_each 的 map 中选择有意义的唯一键非常重要:

resource "aws_iam_user" "user" {
  for_each = { for name in local.users : name => name }

  name  = each.value
}

这将导致 Terraform 跟踪实例标识符,如 aws_iam_user.user["john"] 而不是 aws_iam_user.user[1]

虽然您所在的州有现有的基于 count 的实例,因此需要一些迁移步骤才能到达那里。不幸的是,Terraform 没有足够的信息来自动将现有的基于索引的地址与新的基于名称的地址相关联,但是通过将现有列表与单独的一次性脚本一起使用,您可以告诉 Terraform 如何通过运行命令来转换这些地址对列表中的每个条目都这样:

terraform state mv 'aws_iam_user.user[1]' 'aws_iam_user.user["john"]'

之后,Terraform 将按名称跟踪这些对象,因此添加和删除名称只会影响与您更改的名称相关的对象。


如果您现在还没有准备好完全切换到 for_each,您可以使用类似的策略和一次性脚本来“修复”通过从你的 list :

# First, Terraform must "forget" the user that you removed
terraform state rm 'aws_iam_user.user[0]'

# Then renumber the subsequent items to correlate with their new
# positions in the list.
terraform state mv 'aws_iam_user.user[1]' 'aws_iam_user.user[0]'
terraform state mv 'aws_iam_user.user[2]' 'aws_iam_user.user[1]'
# etc, etc

如果您的用户数量较多,手动完成这当然是一个相当乏味且容易出错的过程,因此最好编写一个小程序来生成脚本。

关于Terraform:如何删除从数组/列表创建的用户资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57311928/

相关文章:

api - terraform provider + Docker注册表v2 = 404

amazon-web-services - AWS Service Catalog 使用 terraform 预置产品

git - 我应该将 .tfstate 文件提交到 Git 吗?

azure - Terraform 应用到 Azure - 在哪里可以看到通过对 Azure 运行应用所做的更改列表

amazon-web-services - 生成非 Terraform 创建的资源列表的最佳方法

terraform - gitignore .tfvars 但不是 .auto.tfvars

amazon-web-services - AWS CloudFormation 配置... UserData 与 Ansible 之类的?

terraform - 为什么我的 AWS ACM 证书没有经过验证?

azure - 什么是有效的 IP 范围?

amazon-web-services - 地形 | secret 经理 |重用现有 secret 而不删除