跳至主要内容

命名值引用

OpenTofu 提供了几种命名值。这些名称中的每一个都是一个引用关联值的表达式。您可以将它们用作独立表达式,也可以将它们与其他表达式结合起来计算新值。

命名值类型

OpenTofu 中可用的主要命名值类型有

  • 资源
  • 输入变量
  • 局部值
  • 子模块输出
  • 数据源
  • 文件系统和工作区信息
  • 块局部值

以下各节将详细解释每种命名值类型。

虽然这些名称中的许多名称使用点分隔路径,类似于 对象值的属性表示法,但它们并未实现为真正的对象。这意味着您必须按原样使用它们:您不能使用方括号表示法替换点分隔路径,也不能迭代命名实体的“父对象”;例如,您不能在 for 表达式中使用 aws_instance 来迭代每个 AWS 实例资源。

资源

<RESOURCE TYPE>.<NAME> 表示给定类型和名称的 托管资源

资源引用的值可能会有所不同,具体取决于资源是否使用 countfor_each

  • 如果资源不使用 countfor_each,则引用的值为一个对象。资源的属性是该对象的元素,您可以使用 点或方括号表示法 访问它们。
  • 如果资源的 count 参数已设置,则引用的值为一个表示其实例的列表
  • 如果资源的 for_each 参数已设置,则引用的值为一个表示其实例的映射

任何与下面列出的其他模式不匹配的命名值都将被 OpenTofu 解释为对托管资源的引用。

有关如何使用资源引用的更多信息,请参阅下面的 资源属性引用

输入变量

var.<NAME> 是给定名称的 输入变量 的值。

如果变量在其声明中包含类型约束(type 参数),OpenTofu 将自动将调用者给定的值转换为符合类型约束的值。

因此,您可以安全地假设使用 var. 的引用将始终产生符合类型约束的值,即使调用者提供了已自动转换的不同类型的值。

特别是,请注意,如果您将变量定义为具有特定属性的对象类型,那么即使调用者实际上传入具有附加属性的值,在模块中的其他表达式中也只会提供这些特定属性。您必须在类型约束中定义您打算在模块中的其他地方使用的所有属性。

局部值

local.<NAME> 是给定名称的 局部值 的值。

局部值可以引用其他局部值,即使是在同一个 locals 块中,只要您没有引入循环依赖关系。

子模块输出

module.<MODULE NAME> 是一个值,表示 module 的结果。

如果相应的 module 块没有设置 countfor_each,则该值将是一个对象,该对象对子模块中定义的每个输出值都有一个属性。要访问模块的 输出值 之一,请使用 module.<MODULE NAME>.<OUTPUT NAME>

如果相应的 module 使用 for_each,则该值将是一个对象映射,其键对应于 for_each 表达式中的键,其值是每个具有一个属性的对象,用于子模块中定义的每个输出值,每个代表一个模块实例。

如果对应的模块使用count,则结果类似于for_each,只是值是一个包含请求元素数量的列表,每个元素代表一个模块实例。

数据源

data.<数据类型>.<名称>是一个对象,表示给定数据源类型和名称的数据资源。如果该资源设置了count参数,则该值是一个表示其实例的对象列表。如果该资源设置了for_each参数,则该值是一个表示其实例的对象映射。

有关更多信息,请参阅资源属性的引用,它也适用于数据资源,除了添加data.前缀以标记引用为数据资源之外。

文件系统和工作区信息

以下值可用

  • path.module是放置表达式的模块的文件系统路径。我们不建议在写操作中使用path.module,因为它可能会产生不同的行为,具体取决于使用的是远程模块源还是本地模块源。本地模块的多次调用使用相同的源目录,在每次调用期间覆盖path.module中的数据。这会导致竞争条件和意外结果。
  • path.root是配置的根模块的文件系统路径。
  • path.cwd是在应用任何-chdir参数之前,从运行 OpenTofu 的原始工作目录的文件系统路径。此路径是一个绝对路径,其中包含有关文件系统结构的详细信息。它在某些高级情况下也很有用,例如,OpenTofu 从根模块目录以外的目录运行。我们建议尽可能使用path.rootpath.module而不是path.cwd
  • terraform.workspace是当前选择的工作区的名称。

谨慎使用本节中的值,因为它们包含有关配置应用的上下文的信息,因此可能会无意中损害模块的可移植性或可组合性。

例如,如果您直接使用path.cwd将路径填充到资源参数中,然后从不同的目录或在具有不同目录结构的不同计算机上应用相同的配置,则提供程序会认为路径的更改是要应用的更改,即使路径仍然指向同一个文件。

类似地,如果您使用这些值中的任何一个作为共享模块中的命名空间形式,例如使用terraform.workspace作为全局唯一对象名称的前缀,则可能无法在同一个配置中多次调用您的模块。

除了path.module之外,我们建议仅在配置的根模块中使用本节中的值。如果您正在编写一个需要前缀来帮助创建唯一名称的共享模块,请为您的模块定义一个输入变量,并允许调用模块定义前缀。调用模块然后可以使用terraform.workspace来定义它,如果合适,或者使用其他值,如果不行。

代码块
module "example" {
# ...

name_prefix = "app-${terraform.workspace}"
}

块局部值

在某些块的主体内部,或者在某些其他特定上下文中,除了上面列出的全局值之外,还有其他命名的值可用。这些局部名称在它们出现的特定上下文的文档中进行了描述。一些最常见的局部名称是

本节中的名称仅与顶级配置块有关。如果您使用dynamicresourcedata块中动态生成资源类型特定的嵌套块,那么您将以不同的方式引用每个元素的键和值。有关详细信息,请参阅dynamic块文档。

命名值和依赖关系

像资源和模块调用这样的结构通常在它们块主体中使用对命名值的引用,OpenTofu 会分析这些表达式以自动推断对象之间的依赖关系。例如,资源参数中引用另一个托管资源的表达式会在两个资源之间创建隐式依赖关系。

资源属性的引用

最常见的引用类型是对已通过resourcedata块声明的资源的属性的引用。因为这些块的内容本身可能非常复杂,所以引用这些内容的表达式也可能很复杂。

考虑以下示例资源块

代码块
resource "aws_instance" "example" {
ami = "ami-abc123"
instance_type = "t2.micro"

ebs_block_device {
device_name = "sda2"
volume_size = 16
}
ebs_block_device {
device_name = "sda3"
volume_size = 20
}
}

aws_instance的文档列出了此资源类型支持的所有参数和嵌套块,还列出了由此资源类型导出的一些属性。所有这些不同的资源类型模式结构都可以在引用中使用,如下所示

  • 配置中设置的ami参数可以在其他地方使用引用表达式aws_instance.example.ami

  • 此资源类型导出的id属性可以使用相同的语法读取,给出aws_instance.example.id

  • ebs_block_device嵌套块的参数可以使用splat 表达式访问。例如,要获取所有device_name值的列表,请使用aws_instance.example.ebs_block_device[*].device_name

  • 此特定资源类型中的嵌套块没有导出任何属性,但是如果ebs_block_device具有一个记录的id属性,那么它们的列表可以类似地访问,例如aws_instance.example.ebs_block_device[*].id

  • 有时嵌套块被定义为接受一个逻辑键来标识每个块,这与资源自身的名称有类似的目的,因为它提供了一种在表达式中方便地引用该单个块的方法。如果aws_instance具有一个假设的嵌套块类型device,该类型接受这样的键,它在配置中看起来像这样

    代码块
      device "foo" {
    size = 2
    }
    device "bar" {
    size = 4
    }

    具有的块中的参数可以使用索引语法访问,例如aws_instance.example.device["foo"].size

    要获得标记嵌套块类型的特定参数的值映射,请使用for表达式{for k, device in aws_instance.example.device : k => device.size}

当资源设置了count参数时,资源本身变成一个列表,其中包含实例对象,而不是单个对象。在这种情况下,使用splat 表达式或索引语法访问实例的属性

  • aws_instance.example[*].id返回每个实例的所有 id 的列表。
  • aws_instance.example[0].id仅返回第一个实例的 id。

当资源设置了for_each参数时,资源本身变成一个映射,其中包含实例对象,而不是单个对象,并且必须通过键指定实例的属性,或者可以使用for表达式访问。

  • aws_instance.example["a"].id返回“a”键资源的 id。
  • [for value in aws_instance.example: value.id]返回每个实例的所有 id 的列表。

请注意,与count不同,splat 表达式不能直接应用于使用for_each管理的资源,因为 splat 表达式必须作用于列表值。但是,您可以使用values()函数将实例提取为列表,并在 splat 表达式中使用该列表值

  • values(aws_instance.example)[*].id

敏感资源属性

在定义资源类型的模式时,提供程序开发人员可以将某些属性标记为敏感,在这种情况下,OpenTofu 会显示一个占位符标记(敏感值),而不是在渲染涉及该属性的计划时显示实际值。

标记为敏感的提供程序属性的行为类似于声明为敏感的输入变量,其中 OpenTofu 会在计划中隐藏该值,并应用消息,还会将您从中派生的任何其他值也隐藏为敏感。但是,该行为存在一些限制,如OpenTofu 可能会公开敏感变量的情况中所述。

如果您将资源属性中的敏感值用作输出值的一部分,则 OpenTofu 将要求您也标记输出值本身为敏感,以确认您确实打算导出它。

OpenTofu 仍然会在状态中记录敏感值,因此任何能够访问状态数据的人都可以以明文方式访问敏感值。有关更多信息,请参见状态中的敏感数据

未知值

当 OpenTofu 正在计划将应用您的配置的一组更改时,某些资源属性值无法立即填充,因为它们的价值是由远程系统动态决定的。例如,如果特定远程对象类型在创建时被分配了一个生成的唯一 ID,则 OpenTofu 无法预测此 ID 的值,直到对象被创建。

OpenTofu 使用特殊的未知值占位符来表示它在计划阶段无法预测的信息。OpenTofu 语言会自动处理表达式中的未知值。例如,将已知值添加到未知值会自动产生未知值作为结果。

但是,在某些情况下,未知值确实会产生重大影响

  • 资源的count元参数不能是未知的,因为它必须在计划阶段进行评估,以确定要创建多少个实例。

  • 如果在数据资源的配置中使用未知值,则该数据资源无法在计划阶段读取,因此它将被推迟到应用阶段。在这种情况下,数据资源的结果也会是未知值。

  • 如果将未知值分配给module块中的参数,则子模块中对相应输入变量的任何引用都将使用该未知值。

  • 如果在输出值的value参数中使用未知值,则父模块中对该输出值的任何引用都将使用该未知值。

  • OpenTofu 会尝试验证未知值在可能的情况下是否为合适的类型,但直到应用阶段才可能检测到这些值的错误使用,从而导致应用失败。

未知值在tofu plan输出中显示为(已知后应用)