如何 select terraform 中 for_each 对象的特定实例

How to select specific instance of an for_each object in terraform

在模块us-region-1中,我定义了一个aws_lambda_layer_version

模块资源中的图层:

resource aws_lambda_layer_version "abc"{
  for_each         = ".xxxx."
  layer_name = each.key
}

并且在全局主地形中,我定义了一个 lamba 层来引用它 aws_lambda_layer_version,所以我必须定义一个数据资源来获取引用并依赖于模块资源

数据层

data aws_lambda_layer_version "abc"{
  for_each         = "..."
  layer_name = each.key
  depends_on = [??????]
  # `aws_lambda_layer_version.abc` not work because it's not choose specific instance of aws_lambda_layer_version.abc.
}

Lambda 函数

resource "aws_lambda_function" "test-lambda-layers" {
  for_each         = ".xxxx."
  layers           = [data.aws_lambda_layer_version.abc[each.key].arn]
}

Terraform 中的依赖关系存在于整个资源之间,而不存在于各个资源实例之间。这是因为 countfor_each 参数本身可以创建依赖关系,因此 Terraform 只有在开始遍历依赖关系图后才能决定资源的实例。

话虽如此,我并不清楚你的问题为什么依赖于你的案例中的特定实例很重要。依赖关系只影响操作的顺序,而不影响 Terraform 将执行的操作,因此对 aws_lambda_layer_version.abc 的所有实例的依赖应该是对单个实例的依赖的可接受替代品:它仍然会提供相同的保证仅在它所依赖的事物之后才处理依赖,它只会等到其他一些不相关的对象首先完成。

resource "aws_lambda_layer_version" "abc" {
  for_each = ...

  layer_name = each.key
}

data "aws_lambda_layer_version" "abc" {
  for_each = aws_lambda_layer_version.abc

  layer_name = each.value.layer_name
}

话虽如此,这个更新的配置仍然表现出 Terraform 反模式:特定的 Terraform 配置通常应该管理特定的对象 从远程读取该对象 API,永远不会同时出现。从你的问题的其余部分来看,你似乎需要使用 AWS Lambda Layer Version 对象的 ARN,在这种情况下你可以直接访问 the equivalent attribute from the managed resource type,而不是要求 Terraform 读回它已经管理的同一个对象:

resource "aws_lambda_function" "example" {
  for_each = aws_lambda_layer_version.abc

  layers = [each.value.arn]
}

如果您这样做的动机是在模块之间传播这些声明,那么更好的方法是直接在模块之间传递数据,而不是使用数据资源作为间接方式。在声明 aws_lambda_layer_version.abc 的模块中,您可以编写如下输出值:

output "lambda_layer_versions" {
  value = tomap({
    for k, lv in aws_lambda_layer_version.abc : k => {
      id  = lv.id
      arn = lv.arn
    }
  })
}

这将构建一个对象映射,其键与您的 for_each 实例键相同,其中每个对象具有 idarn 属性。

然后您的根模块可以从此对象访问 ARN:

module "layers" {
  source = "./module/lambda-layers"

  # ...
}

resource "aws_lambda_function" "test-lambda-layers" {
  for_each = module.layers.lambda_layer_versions

  layers = [each.value.arn]
}