如何在 terraform 的同一块中引用前一行的变量?

How to reference a variable from an earlier line in the same block in terraform?

假设我有一个 module(或 resource,或 locals 块,或其他)

module "example" {
  foo = "foo"
  bar = "${foo}" # why wont' this work??
}

terraform“语言”不支持这一点让我很沮丧。我应该如何在无法引用变量的情况下编写简单的 DRY 代码?

编辑:我认为那个例子太做作了。这是一个更好的:

module "example" {
  domain = "example.com"
  uri = "https://${domain}" # why wont' this work??
}

支持,但取决于您的模块。你的模块必须先输出foo。然后你可以这样做:

module "exmaple" {
  source = "./mymodule1"
  foo = "dfsaf"
  bar = module.exmaple.foo 
}

mymodule1 的最简单示例是:

variable "foo" {
    default = 1
}

variable "bar" {
   default = 2
}

output "foo" {
  value = var.foo
}

但在您的示例中,这样做确实没有意义,因为 bar 始终与 foo 相同,因此它甚至不应该公开。

更好更自然的方法是:


locals {
  foo = "foo"
}

module "exmaple" {
  source = "./mymodule1"
  foo = local.foo
  bar = local.foo
}

您的问题似乎是两个不同的问题:您如何才能实现您描述的目标,以及为什么您首先尝试的事情没有奏效。

其他人已经回答了如何分解出要在多个位置使用的值,所以我只想尝试解决第二个问题,即为什么这不起作用,以防它对你继续使用 Terraform 的旅程有用.

Terraform 语言旨在显示为分层数据结构,而不是要执行的线性代码,这当然有一些重要的权衡。在 return 中,希望使 well-written Terraform 配置读起来像应该存在的清单而不是创建它的程序,Terraform 语言确实在某种程度上掩盖了您可能会遇到的真实控制流和符号范围习惯于其他语言。

特别是对于您的问题,我认为重要的是要认识到 module 块中的参数不像变量声明,而更像是传递给函数的参数。

对于你的第二个例子,将其重新编写成 function-call-like 语法可能会有所帮助:

module "example" {
  source = "./mymodule1"

  domain = "example.com"
  uri    = "https://${domain}"
}
# NOTE: pseudocode
example(domain: "example.com", uri: "https://#{domain}")

在大多数 imperative-style 语言中,函数参数绑定到符号 在模块内 而不是在模块外,因此将 domain 定义为 "example.com" 这里不会使该符号对同一调用中的其他后续参数可见。

现在以 Marcin 的最后一个例子为例,改编成类似于你的第二个例子:

locals {
  domain = "example.com"
}

module "example" {
  source = "./mymodule1"

  domain = local.domain
  url    = "https://${local.domain}"
}
# NOTE: pseudocode
domain = "example.com"
example(domain: domain, uri: "https://#{domain}")

当然,与 general-purpose 语言相比,这也暴露了 Terraform 的另一个不同之处,即它没有将所有内容都分配给它的共享变量范围,而是将局部变量放在命名空间中 local。但是尽管语法不同,它们都是局部值,范围限定在定义它们的模块中,因此您可以在同一模块中的其他任何地方引用 local.domain 。 (注意:这是一个 whole-module 作用域,而不是您在其他语言中可能习惯的词法作用域。)

类似的原则适用于resourcedataprovider块;这两个更像是函数的参数而不是变量声明,但只是采用不同的语法,目的是将其显示为一系列声明而不是顺序代码。