如何使用引用其他资源的for_each定义资源块



我在地形-中创建了一些资源

resource "aws_dms_replication_instance" "foobar_instance_1" {
}
resource "aws_dms_replication_instance" "foobar_instance_2" {
}
resource "aws_dms_endpoint" "foobar_source_1" {
}
resource "aws_dms_endpoint" "foobar_source_2" {
}

然后定义一个依赖于以上两种资源的复制任务——

resource "aws_dms_replication_task" "foobar_task_1" {
replication_instance_arn = aws_dms_replication_instance.foobar_instance_1.replication_instance_arn
source_endpoint_arn       = aws_dms_endpoint.foobar_source_1.endpoint_arn
.
.
.
}

我想使用一个tf变量来使用for_each自动创建类似的aws_dms_replication_task。我在variables.tf中创建了一个Map变量看起来像这样-

variable "task_map" {
type        = map(object({
source_endpoint     = string
repl_instance     = string
}))
default = {
"dms_attr_map" = {
source_ep     = "foobar_source_1"
repl_instance = "foobar_instance_1"
},
"dms_attr_map2" = {
source_ep     = "foobar_source_2"
repl_instance = "foobar_instance_2"
}
}
}

现在,我继续创建一个资源块来循环task_map并创建replication_task

resource "aws_dms_replication_task" "for_each_task_1" {
for_each                  = var.task_map
replication_instance_arn  =  aws_dms_replication_instance.${each.value["repl_instance"]}.replication_instance_arn
source_endpoint_arn       = aws_dms_endpoint.${each.value["source_ep"]}.endpoint_arn
.   
.
.
}

当我执行我的计划时,terrraform计划抛出一个错误,即使用${each.value["repl_instance"]}引用replication_instance是错误的。

错误消息-

│错误:无效字符│ │在/modules/cdc/main.tf第236行:此字符不用于│语言╵

╷ │错误:属性名称无效│ │在/模块/cdc/main.tf行233:在│点╵

错误消息指向我使用for_each引用replication_instance和source_endpoint 的特定行

aws_dms_endpoint.${each.value["source_ep"]}.endpoint_arn
aws_dms_replication_instance.${each.value["repl_instance"]}.replication_instance_arn

如何使用for_each引用使用其名称创建的资源。

谢谢。

如何使用for_each引用使用其名称创建的资源。

你不能这么做。换句话说,您不能以以下形式创建对资源的动态引用:

aws_dms_endpoint.${each.value["source_ep"]}.endpoint_arn

相反,您必须使用映射或列表来创建aws_dms_replication_instanceaws_dms_endpoint。例如:

resource "aws_dms_replication_instance" "foobar_instance" {
for_each = toset(["foobar_instance_1", "foobar_instance_2"])
}
resource "aws_dms_endpoint" "foobar_source" {
for_each = toset(["foobar_source_1", "foobar_source_2"])
}

结束,然后将它们称为:

resource "aws_dms_replication_task" "for_each_task_1" {
for_each                  = var.task_map
replication_instance_arn  = aws_dms_replication_instance.foobar_instance[each.value["repl_instance"]].replication_instance_arn
source_endpoint_arn       = aws_dms_endpoint.foobar_source[each.value["source_ep"]].endpoint_arn
.   
.
.
}

当考虑这样的问题时,重要的是要认识到像aws_dms_replication_instance.foobar_instance_1这样的引用表达式是一个不可分割的单元:aws_dms_replication_instance本身并不是一个可以动态查询的独立数据结构,因为Terraform需要能够准确地确定特定表达式依赖于哪些资源才能生成依赖图,在评估任何表达式之前。

但是,可以构建自己的映射数据结构,其中包含您感兴趣的资源集:

locals {
source_endpoints = {
"foobar_1" = aws_dms_endpoint.foobar_source_1
"foobar_2" = aws_dms_endpoint.foobar_source_2
}
replication_instances = {
"foobar_1" = aws_dms_replication_instance.foobar_instance_1
"foobar_2" = aws_dms_replication_instance.foobar_instance_2
}
}

然后,您可以使用local.source_endpointslocal.replication_instances作为映射来查找模块调用方指定的密钥:

resource "aws_dms_replication_task" "for_each_task_1" {
for_each = var.task_map
replication_instance_arn = local.replication_instances[each.value.repl_instance].replication_instance_arn
source_endpoint_arn      = local.source_endpoints[each.value.source_ep].endpoint_arn
# ...
}

这是可行的,因为局部值也是参与依赖关系图的对象。Terraform可以看出,local.source_endpoints同时依赖于aws_dms_endpoint.foobar_source_1aws_dms_endpoint.foobar_source_2,因此间接地,任何依赖于local.source_endpoints的东西都必须有效地依赖于这些资源。


虽然这对您的问题并不重要,但我想注意的是,这种设计意味着您的模块将声明aws_dms_endpointaws_dms_replication_instance对象的完整集合,即使其中一些对象没有任何引用它们的var.task_map元素。

如果模块的唯一实际使用涉及引用所有这些,我不会担心,但如果这不是真的,那么这种设计的一个变体是允许调用者通过输入变量指定他们需要的端点和复制实例,并在所有这三种资源上使用for_each

如果你这样做,那么你就可以避免构建中间数据结构,因为for_each资源已经是支持相同类型动态查找的自然映射:

resource "aws_dms_replication_instance" "example" {
for_each = var.replication_instances
# ...
}
resource "aws_dms_endpoint" "example" {
for_each = var.source_endpoints
# ...
}
resource "aws_dms_replication_task" "for_each_task_1" {
for_each = var.task_map
replication_instance_arn = aws_dms_replication_instance.example[each.value.repl_instance].replication_instance_arn
source_endpoint_arn      = aws_dms_endpoint.example[each.value.source_ep].endpoint_arn
# ...
}

在这个变体中,模块的调用方控制存在哪些复制实例和终结点,以及每个任务使用哪些,因此模块用户的负担更大,但他们也可以灵活地不声明他们不会实际使用的对象,以防这些对象有很大的成本。

最新更新