跳至主要内容

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,该类型在resourcedataproviderprovisioner块内受支持。

代码块
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表达式生成一个集合值,则keyvalue相同,不应使用。
  • value是当前元素的值。

dynamic块只能生成属于正在配置的资源类型、数据源、提供程序或配置程序的参数。由于OpenTofu必须在安全评估表达式之前处理这些参数,因此无法生成元参数块,例如lifecycleprovisioner块。

for_each的值必须是一个集合,每个集合对应一个所需的嵌套块。如果您需要根据嵌套数据结构或来自多个数据结构的元素组合来声明资源实例,则可以使用OpenTofu表达式和函数来推导出合适的值。有关此类情况的一些常见示例,请参阅flattensetproduct函数。

多级嵌套块结构

某些提供程序定义了资源类型,这些类型包括彼此嵌套的多级块。如果需要,您可以通过在其他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块的参数和嵌套块,那么这可能表明你的模块没有创建有用的抽象。调用模块自己定义资源,然后将有关资源的信息传递到你的模块中可能更好。有关此设计权衡的更多信息,请参阅何时编写模块模块组合