- OpenTofu 语言
- 属性作为块
属性作为块
此页面是 OpenTofu 文档的附录。大多数用户不需要了解此行为的全部细节。
摘要
许多资源类型使用可重复的嵌套块来管理与主资源相关的子对象的集合。
很少情况下,某些资源类型也支持与嵌套块类型名称相同的参数,如果该参数设置为空列表(<ATTR> = []
),则将清除该类型的任何子对象。
大多数用户不需要了解这种“嵌套块或空列表”行为的更多细节。但是,如果您需要,请继续阅读
- 将 OpenTofu 的 JSON 语法 与此类型的资源一起使用。
- 创建一个可重用的模块来包装此类型的资源。
细节
该语言区分块内 参数语法和嵌套块语法
-
参数语法为包含对象设置一个命名参数。如果属性具有默认值,则显式指定的值将完全覆盖该默认值。
-
嵌套块语法表示容器的相关子对象,该对象具有自己的参数集。在可能存在多个此类对象的情况下,可以存在多个相同类型的块。如果嵌套属性本身具有默认值,则会分别为每个嵌套块保留这些默认值,并与任何显式定义的参数合并。
这些之间的区别对于 JSON 语法 尤其重要,因为相同的原始 JSON 结构(列表和对象)将根据特定名称是参数还是嵌套块类型而被不同地解释。
定义固定对象集合值
在使用以这种方式表现的资源类型参数时,在定义固定对象集合时,可以使用嵌套块语法,我们也建议这样做。
example {
foo = "bar"
}
example {
foo = "baz"
}
以上隐式指定分配给 example
参数的两个元素的对象列表,将其视为嵌套块类型。
如果您需要显式调用零个 example
对象,则必须使用带有空列表的参数语法。
example = []
这两种形式不能混合使用;不能同时存在显式零个 example
对象和显式单个 example
块声明。
对于这种特殊行为不适用的真正嵌套块,使用参数语法分配 []
是无效的。指定零个类型对象的正常方式是根本不编写任何嵌套块。
使用参数语法的任意表达式
尽管我们建议在简单情况下使用块语法以提高可读性,但此模式中有效的名称确实被定义为参数,因此可以使用参数语法将任意动态表达式分配给它们,只要表达式具有预期的结果类型即可。
example = [
for name in var.names: {
foo = name
}
]
# Not recommended, but valid: a constant list-of-objects expression
example = [
{
foo = "bar"
},
{
foo = "baz"
},
]
由于此类参数声明将完全覆盖任何默认值的规则,因此在直接创建对象列表表达式时,不会应用可选参数的常规处理,因此所有参数都必须分配一个值,即使是显式的 null
。
example = [
{
# Cannot omit foo in this case, even though it would be optional in the
# nested block syntax.
foo = null
},
]
如果您正在编写一个可重用的模块,允许调用者传入要分配给此类参数的对象列表,则可能希望使用 merge
函数来填充用户未显式设置的任何属性,以便为模块用户提供可选参数的效果。
example = [
for ex in var.examples: merge({
foo = null # (or any other suitable default value)
}, ex)
]
对于使用属性作为块使用模式的参数,以上模式优于使用 dynamic
块,因为调用者提供空列表的情况将导致显式分配空列表值,而不是根本不分配任何值,从而保留并忽略任何现有对象。 dynamic
块是动态生成正常嵌套块所必需的。
在 JSON 语法中
在 JSON 语法中,使用此特殊模式的参数始终使用 JSON 表达式映射 来生成对象列表。
因此,这些值在 JSON 语法中的解释等同于上面带参数语法的任意表达式中描述的解释,但以 JSON 语法表示。
由于 JSON 语法的歧义性,无法仅根据输入来区分参数和嵌套块的使用,因此 JSON 语法不支持这些参数的嵌套块处理模式。不幸的是,这是为了与现有提供程序设计模式兼容而做出的必要妥协之一,以权衡原生语法和 JSON 语法之间的等效性。提供程序可能会在未来的主要版本中逐步淘汰此类模式。