【问题标题】:Terraform: How to remove a user resource created from an array/list?Terraform:如何删除从数组/列表创建的用户资源?
【发布时间】:2019-12-10 05:20:41
【问题描述】:

我有一个文件 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。这是不可取的。

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

是的,没有这样的运气:

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

我将总结我的问题:

当通过迭代列表创建资源时,有什么方法可以删除资源(特别是 aws_iam_user),以使所有剩余资源保持原样?

【问题讨论】:

    标签: terraform


    【解决方案1】:

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

    请注意,count 创建的单独资源实例仍由它们的 index 标识,而不是由给定列表中的字符串值标识。这意味着如果从列表的中间删除一个元素,所有索引实例之后都会看到它们的子网ID值发生变化,这将导致比预期更多的远程对象更改。从列表中生成多个实例的做法应谨慎使用,并应适当注意以后更改列表时会发生什么。

    幸运的是,这正是for_each 功能旨在解决的问题。不过,为了有效地使用它,在传递给 for_each 的映射中选择有意义的唯一键很重要:

    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,您可以使用类似的策略和一次性脚本来“修复”通过从列表中删除项目而造成的漏洞:

    # 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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-28
      • 1970-01-01
      • 2020-08-01
      • 2018-09-27
      • 2020-11-18
      • 2019-05-19
      • 2022-01-15
      • 2019-06-25
      相关资源
      最近更新 更多