给定键未标识此集合值中的元素:terraform

The given key does not identify an element in this collection value : terraform

我正在尝试使用 terraform 部署 lambda 函数,代码是用 python 编写的。这是执行操作的地形代码。

data archive_file UpdateSeqNumInLedgerSummary {
  count       = (var.environment_id == var.prd_environment) ? 1 : 0
  ..
  ..
  ..
  #
}

resource aws_lambda_function update_seqnum_in_indexedledgersummary {
  count            = (var.environment_id == var.prd_environment) ? 1 : 0
  ..
  ..
  ..
  #
}

在部署期间,我还尝试使用 aws_lambda_invocation 调用 lambda 函数。这是我正在做的

data aws_lambda_invocation update_seqnum_invocation {
  count         = (var.environment_id == var.prd_environment) ? 1 : 0
  function_name = aws_lambda_function.update_seqnum_in_indexedledgersummary[count.index].function_name
  input = <<JSON
  {}
  JSON
}

但是在部署期间我收到以下错误

Error: Invalid index

  on seqnum-update.tf line 124, in data "aws_lambda_invocation" "update_seqnum_invocation":
 124:   function_name = aws_lambda_function.update_seqnum_in_indexedledgersummary[count.index].function_name
    |----------------
    | aws_lambda_function.update_seqnum_in_indexedledgersummary is empty tuple
    | count.index is 0

The given key does not identify an element in this collection value.

(第 124 行片段的 count.index 部分作为相关子表达式加了下划线。)

有人可以帮我解决这个问题吗?

这里的问题似乎是 Terraform 无法从您描述这些关系的方式推断出 data.aws_lambda_invocation.update_seqnum_invocation 数据资源必须在对 aws_lambda_function.update_seqnum_in_indexedledgersummary 进行更改后只读。

看来您使用的是旧版本的Terraform,一些旧版本的Terraform对数据资源和托管资源之间的关系依赖推断不够精确,这可能会导致这样的问题。因此,升级到最新版本的 Terraform 可能会使这项工作更可靠,因为现代 Terraform 包含一个附加规则,即当数据资源引用托管资源并且计划对托管资源进行更改时,因此不得读取数据资源直到应用步骤。

要在较旧的 Terraform 版本中获得这种效果,您可以向 Terraform 提供更多信息,以便它更好地理解您的意图。

首先,我建议将 count 更改为 data.aws_lambda_invocation.update_seqnum_invocation,使其派生自 aws_lambda_function.update_seqnum_in_indexedledgersummary 的计数,从而使 Terraform 能够清楚地看到这两个计数必须始终一起更改:

data "aws_lambda_invocation" "update_seqnum_invocation" {
  count = length(aws_lambda_function.update_seqnum_in_indexedledgersummary)

  # ...
}

另一个更改有点困难,因为它涉及找到某种方法使数据资源的配置在相应函数尚不存在时包含 (known after apply) 值。 Terraform 然后将其用作信号,表明数据资源读取必须等到应用步骤。但是,由于这些资源类型的设计,其中 aws_lambda_invocation 通过名称引用函数并且名称直接在您的配置中指定,因此似乎没有 natural 要包含在具有这种效果的数据资源配置中的值。

但是,我们可以通过引入类型为 null_resource (which belongs to the hashicorp/null provider) 的额外中间资源来强制执行此操作,保证在等待创建时产生未知的 id 值:

resource "null_resource" "example" {
  count = length(aws_lambda_function.update_seqnum_in_indexedledgersummary)
}

data "aws_lambda_invocation" "update_seqnum_invocation" {
  count = length(aws_lambda_function.update_seqnum_in_indexedledgersummary)

  # ...
  input = jsonencode({
    irrelevant = null_resource.example.id
  })
}

上面的一个不幸的部分是它需要向调用的 input 添加一个无用的额外参数,因为我们需要在某处包含未知的 ID 值 在该配置中。以上将使 input 成为 (known after apply),因此仅在应用步骤期间强制读取 data.aws_lambda_invocation.update_seqnum_invocation 数据资源。


上面我重点介绍了如何让这些部分协同工作的细节,但我还想指出,您在这里所做的有点误用了 aws_lambda_invocation 数据资源,即这很尴尬的很大一部分原因是:

与 Terraform 中的所有数据源一样,data "aws_lambda_invocation" 旨在 收集数据以在您的配置中的其他地方使用 而不是描述要对您的基础架构进行的更改.因此,它通常应与在当前 Terraform 配置之外定义的函数一起使用,该函数提供当前 Terraform 配置所需的一些数据。

虽然可以在应用步骤中让 Terraform 读取数据资源,从而获得数据资源进行基础架构更改的效果,但这种方法本质上是脆弱的并且随着提供者的发展和 Terraform Core 本身的发展而容易崩溃,因为在这两种情况下,目标通常是在规划阶段收集尽可能多的数据,因此它被认为是 改进 能够在计划阶段而不是应用阶段读取更多数据源。

这个函数究竟做了什么不在你的问题范围内,所以我不能建议一个具体的替代方案,但 Terraform 中的一般期望是所有 更改 基础设施将由 resource 块而不是 data 块表示,因此如果您需要修改某些内容作为应用此配置的一个步骤,最好找到现有的托管资源类型(使用 resource 块)可以执行该操作,或者开发一个自定义 Terraform 提供程序来提供您需要的资源类型。那将按照其设计的方式使用 Terraform,因此不应在未来版本的提供程序或 Terraform Core 中中断。