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создает значение типа множество, тоkeyидентиченvalue, и его не следует использовать. -
value— это значение текущего элемента.
Блок dynamic может создавать только аргументы, относящиеся к настраиваемому типу ресурса, источнику данных, провайдеру или провижионеру. Создавать блоки метааргументов, такие как блоки 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.9/language/expressions/dynamic-blocks/