我有一个文件users.tf
文件,它为aws创建管理用户。它通过定义一个列表(例如users = ["bob", "john", "tom"]
)来做到这一点。
然后使用terraform中的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
这将导致约翰得到鲍勃的arn,而汤姆得到约翰的arn。这是不可取的。
我尝试使用for_each循环的for_each循环(在编写这个问题前19小时发布)代替count,并将键定义为原始索引号,希望terraform将它们视为相同的资源。
是啊,没那么幸运:
...
# aws_iam_user.user[1] will be destroyed
...
# aws_iam_user.user["1"] will be created
...
我将总结我的问题:
是否有任何方法删除资源(特别是aws_iam_user
),当该资源是通过迭代列表来创建的,这样所有剩余的资源都保持原样吗?
发布于 2019-08-01 17:08:09
您在这里看到的是文档在其最后一段中警告的情况:
请注意,
count
创建的独立资源实例仍然由其索引来标识,而不是由给定列表中的字符串值标识。这意味着,如果从列表的中间删除一个元素,那么在它看到元素的subnet_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
-based实例,因此需要采取一些迁移步骤才能实现。不幸的是,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
当然,这将是一个相当繁琐,容易出错的过程,如果您有超过少数用户,所以最好编写一个小程序来生成脚本。
https://stackoverflow.com/questions/57311928
复制相似问题