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
}
}Вы можете динамически создавать повторяющиеся вложенные блоки, например setting, с помощью специального типа блока dynamic, который поддерживается внутри блоков 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возвращает значение типа set, тоkeyсовпадает сvalueи его не следует использовать. -
value— это значение текущего элемента.
Блок dynamic может создавать только аргументы, относящиеся к настраиваемому типу ресурса, источнику данных, провайдеру или provisioner. Нельзя создавать блоки метааргументов, например блоки lifecycle и provisioner, поскольку OpenTofu должен обработать их до того, как станет безопасно вычислять выражения.
Значение for_each должно быть коллекцией, содержащей по одному элементу для каждого требуемого вложенного блока. Если вам нужно объявить экземпляры ресурсов на основе вложенной структуры данных или комбинаций элементов из нескольких структур данных, можно использовать выражения и функции OpenTofu, чтобы получить подходящее значение. Распространённые примеры таких ситуаций см. в описании функций flatten и setproduct.
Многоуровневые структуры вложенных блоков
Некоторые провайдеры определяют типы ресурсов, включающие несколько уровней вложенных друг в друга блоков. При необходимости можно динамически создавать такие вложенные структуры, помещая блоки dynamic в часть content других блоков dynamic.
Например, модуль может принимать сложную структуру данных следующего вида:
variable "load_balancer_origin_groups" {
type = map(object({
origins = set(object({
hostname = string
}))
}))
}Если бы вы определяли ресурс, тип которого предполагает наличие блока для каждой группы источников и вложенных блоков для каждого источника в группе, можно было бы поручить OpenTofu динамически создать такую структуру с помощью следующих вложенных блоков 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 — текущий элемент внутреннего блока.
Если тип ресурса определяет вложенные блоки с тем же именем типа, что и у одного из родительских блоков, можно использовать аргумент iterator в каждом блоке dynamic, чтобы выбрать другой символ итератора и упростить их различение.
Рекомендации по использованию блоков dynamic
Чрезмерное использование блоков dynamic может затруднить чтение и сопровождение конфигурации, поэтому мы рекомендуем применять их только тогда, когда необходимо скрыть детали, чтобы создать удобный интерфейс для повторно используемого модуля. По возможности всегда записывайте вложенные блоки явно.
Если вы обнаружили, что задаёте большинство или все аргументы и вложенные блоки блока resource с помощью напрямую соответствующих атрибутов входной переменной, это может указывать на то, что ваш модуль не создаёт полезную абстракцию. Возможно, вызывающему модулю лучше самостоятельно определить ресурс, а затем передать сведения о нём вашему модулю. Подробнее об этом компромиссе при проектировании см. в разделах Когда следует писать модуль и Композиция модулей.
Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.10/language/expressions/dynamic-blocks/