dynamic
块
在诸如资源等顶级块结构中,表达式通常只能在使用name = expression
形式为参数赋值时使用。这涵盖了许多用例,但某些资源类型在其参数中包含可重复的嵌套块,这些块通常表示与包含对象相关(或嵌入在包含对象中)的单独对象。
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name" # can use expressions here
setting {
# but the "setting" block is always a literal block
}
}
您可以使用特殊的dynamic
块类型动态构建可重复的嵌套块,例如setting
,该类型在resource
、data
、provider
和provisioner
块内受支持。
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name"
application = "${aws_elastic_beanstalk_application.tftest.name}"
solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
dynamic "setting" {
for_each = var.settings
content {
namespace = setting.value["namespace"]
name = setting.value["name"]
value = setting.value["value"]
}
}
}
dynamic
块的作用与for
表达式非常相似,但它生成嵌套块而不是复杂类型的值。它遍历给定的复杂值,并为该复杂值的每个元素生成一个嵌套块。
- 动态块的标签(上面示例中的
"setting"
)指定要生成哪种嵌套块。 for_each
参数提供要迭代的复杂值。iterator
参数(可选)设置一个临时变量的名称,该变量表示复杂值的当前元素。如果省略,则变量的名称默认为dynamic
块的标签(上面示例中的"setting"
)。labels
参数(可选)是一个字符串列表,按顺序指定用于每个生成的块的块标签。您可以在此值中使用临时迭代器变量。- 嵌套的
content
块定义每个生成的块的主体。您可以在此块内使用临时迭代器变量。
由于for_each
参数接受任何集合或结构化值,因此您可以使用for
表达式或splat表达式来转换现有的集合。
迭代器对象(上面示例中的setting
)有两个属性。
key
是当前元素的映射键或列表元素索引。如果for_each
表达式生成一个集合值,则key
与value
相同,不应使用。value
是当前元素的值。
dynamic
块只能生成属于正在配置的资源类型、数据源、提供程序或配置程序的参数。由于OpenTofu必须在安全评估表达式之前处理这些参数,因此无法生成元参数块,例如lifecycle
和provisioner
块。
for_each
的值必须是一个集合,每个集合对应一个所需的嵌套块。如果您需要根据嵌套数据结构或来自多个数据结构的元素组合来声明资源实例,则可以使用OpenTofu表达式和函数来推导出合适的值。有关此类情况的一些常见示例,请参阅flatten
和setproduct
函数。
多级嵌套块结构
某些提供程序定义了资源类型,这些类型包括彼此嵌套的多级块。如果需要,您可以通过在其他dynamic
块的content
部分嵌套dynamic
块来动态生成这些嵌套结构。
例如,一个模块可能会接受如下所示的复杂数据结构。
variable "load_balancer_origin_groups" {
type = map(object({
origins = set(object({
hostname = string
}))
}))
}
如果您正在定义一个资源,其类型为每个源组期望一个块,然后为每个组内的源嵌套块,则可以使用以下嵌套的dynamic
块来动态生成它。
dynamic "origin_group" {
for_each = var.load_balancer_origin_groups
content {
name = origin_group.key
dynamic "origin" {
for_each = origin_group.value.origins
content {
hostname = origin.value.hostname
}
}
}
}
在使用嵌套的dynamic
块时,尤其要注意每个块的迭代器符号。在上面的示例中,origin_group.value
指的是外部块的当前元素,而origin.value
指的是内部块的当前元素。
如果某个特定的资源类型定义的嵌套块与其父级之一具有相同的类型名称,则可以在每个dynamic
块中使用iterator
参数来选择不同的迭代器符号,从而使两者更容易区分。
dynamic
块的最佳实践
过度使用dynamic
块会使配置难以阅读和维护,因此我们建议仅在需要隐藏详细信息以构建可重用模块的简洁用户界面时才使用它们。尽可能始终按字面写出嵌套块。
如果你发现自己正在使用输入变量中直接对应的属性来定义大部分或全部的resource
块的参数和嵌套块,那么这可能表明你的模块没有创建有用的抽象。调用模块自己定义资源,然后将有关资源的信息传递到你的模块中可能更好。有关此设计权衡的更多信息,请参阅何时编写模块和模块组合。