我正在编写一个地形模块,它应该在不同的环境中重用。
为了使事情变得简单,这里有一个从一个环境根模块调用模块的基本示例:
##QA-resources.tf
module "some_module" {
source = "./path/to/module"
}
some_variable = ${module.some_module.some_output}
问题是,当一个模块已经创建时,Terraform会抛出一个错误:
创建[资源类型][资源名称]时出错:具有[资源名称]的EntityAlreadyExists:[资源类型]已存在。状态代码:409,请求id:。。。
当模块是在外部terraform.tfstate
的作用域下创建的,并且其中一个资源具有类似"Name"的唯一字段时,就会发生这种情况。
在我的案例中,它发生在尝试使用IAM模块时,该模块已经创建了具有该特定名称的角色,但在许多其他情况下也可能发生(我不希望讨论特定于我的用例(。
我希望,如果模块的某个资源存在,则不会发生故障,并且模块的输出将可用于root
模块。
如何管理(可能使用特定命令或标志(有什么建议吗?
我发现了几个相关的线程:
Terraform没有重用它刚刚创建并失败的AWS角色?
解决地形中EntityAlreadyExists错误的最佳方法是什么?
Terraform错误EntityAlreadyExists:名为iam_for_lambda的角色已存在
编辑
对于@Martin Atkins的请求,以下是导致错误的资源。
它是附加了2个策略(通过var.policies
传递(的AWS EKS集群的基本角色:
resource "aws_iam_role" "k8s_role" {
name = "k8s-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "role-policy-attach" {
role = "${aws_iam_role.k8s_role.name}"
count = "${length(var.policies)}"
policy_arn = "${element(var.policies, count.index)}"
}
此角色被包装为一个模块,并被传递给根模块
由于根模块试图创建角色时该角色已存在,因此发生了上面在块引号中提到的错误。
在Terraform的视图中,每个对象要么由Terraform管理,要么不由Terraform管理。Terraform避免隐式地获取现有对象的所有权,因为如果要这样做,那么当您随后运行terraform destroy
时,您可能会无意中破坏Terraform不打算管理的东西。
在您的情况下,这意味着您需要决定名为k8s-role
的角色是否由Terraform管理,如果您有多个Terraform配置,则需要选择一个配置来管理该对象。
在一个将管理对象的Terraform配置中,可以使用resource "aws_iam_role"
来指定。如果任何其他配置需要访问它,或者它根本不会用Terraform管理,那么在需要的情况下,您可以直接引用角色名称k8s-role
。如果您需要更多关于该角色的信息,而不仅仅是它的名称,那么您可以使用aws_iam_role
数据源来获取该信息,而无需声明要管理对象:
data "aws_iam_role" "k8s" {
name = "k8s-role"
}
例如,如果您需要使用此角色的ARN,则可以使用data.aws_iam_role.k8s.arn
访问此数据资源的arn
属性。
最后,如果您的角色当前不是由Terraform管理的,但您想将其归Terraform所有,您可以明确地告诉Terraform开始管理现有对象,方法是导入该对象以创建现有对象和您的resource
块之间的关联:
terraform import aws_iam_role.k8s_role k8s-role