Иногда требуется создать несколько ресурсов, которые будут отличаться незначительными изменениями (например, имя). В terraform имеются специальные мета-аргументы, которые позволяют описать данную инфраструктуру максимально быстро, избегая повторений блоков. Однако, при таком подходе стоит учитывать то, что созданная при помощи такого подхода инфраструктура является неким "монолитом" и любые изменения будут применятся для всех ресурсов, которые были созданы с помощью мета аргументов. __ВНИМАНИЕ: СОЗДАННЫЕ ТАКИМ ОБРАЗОМ РЕСУРСЫ, УПРАВЛЯЮТСЯ КАК ОДИН РЕСУРС__ ## Создание дисков. Обычный вариант Предположим, что необходимо создать несколько дисков, которые будут иметь одинаковые поля, а отличаться только именем. Тогда, будут использованы несколько блоков resource с описанием данных ресурсов: ```terraform resource "dynamix_disk" "disk1" { account_id = 777 disk_name = "disk-1" size_max = 10 gid = 212 } resource "dynamix_disk" "disk2" { account_id = 777 disk_name = "disk-2" size_max = 10 gid = 212 } ``` Все блоки повторяются и отличаются только именем. Если не планируется изменение каждого ресурса по-отдельности, то можно вынести имена дисков в отдельную переменную, и считывать их из нее. ## Рефакторинг Вынесем значения имен дисков в блок locals: ```terraform locals { disk_names = [ "disk-1", "disk-2", ] } resource "dynamix_disk" "disk1" { account_id = 777 disk_name = "disk-1" size_max = 10 gid = 212 } resource "dynamix_disk" "disk2" { account_id = 777 disk_name = "disk-2" size_max = 10 gid = 212 } ``` Оставшиеся блоки resource идентичны друг другу, за исключением наименования ресурса, поэтому, их создание и работу с ними можно объединить. ## Мета аргумент for_each Мета аргумент for_each служит для итерации по набору (set) строки, либо по мапе (map, object). Результатом работы этого мета аргумента станет так же объект, ключами которого будут либо строки, входящие в набор, либо параметры, указанные при итерировании объекта. Мета аргумент for_each предоставляет переменную each, в которую, при каждой итерации будут ключи (если итерация идет по набору строк), либо ключи и соответствующие им значения, если итерация идет по объекту. Обратиться к ним можно через символ ".", например: ```terraform each.key each.value ``` Таким образом, конфигурирование одинаковых ресурсов сократится до одного. При добавлении в код выше, получится: ```terraform locals { disk_names = [ "disk-1", "disk-2", ] } #обратите внимание, что ресурс был переименован resource "dynamix_disk" "disks" { #преобразование массива к набору строк для успешной работы for_each for_each = toset(local.disk_names) account_id = 777 #получение имени диска из переменной each disk_name = each.key size_max = 10 gid = 212 } #блок output демонстрирует вывод работы на экран output "test" { value = dynamix_disk.disks } ``` При выполнении данной конфигурации в terraform output будет следующее: ``` Changes to Outputs: + test = { + disk-1 = { + account_id = 777 + account_name = (known after apply) + acl = (known after apply) + boot_partition = (known after apply) + compute_id = (known after apply) + compute_name = (known after apply) + created_time = (known after apply) + deleted_time = (known after apply) + desc = (known after apply) + destruction_time = (known after apply) + detach = false + devicename = (known after apply) + disk_id = (known after apply) + disk_name = "disk-1" + disk_path = (known after apply) + gid = 212 + guid = (known after apply) + id = (known after apply) + image_id = (known after apply) + images = (known after apply) + iotune = (known after apply) + iqn = (known after apply) + login = (known after apply) + milestones = (known after apply) + order = (known after apply) + params = (known after apply) + parent_id = (known after apply) + passwd = (known after apply) + pci_slot = (known after apply) + permanently = false + pool = (known after apply) + purge_attempts = (known after apply) + purge_time = (known after apply) + reality_device_number = (known after apply) + reference_id = (known after apply) + res_id = (known after apply) + res_name = (known after apply) + restore = false + role = (known after apply) + sep_id = (known after apply) + sep_type = (known after apply) + size_max = 10 + size_used = (known after apply) + snapshots = (known after apply) + status = (known after apply) + tech_status = (known after apply) + timeouts = null + type = (known after apply) + vmid = (known after apply) } + disk-2 = { + account_id = 777 + account_name = (known after apply) + acl = (known after apply) + boot_partition = (known after apply) + compute_id = (known after apply) + compute_name = (known after apply) + created_time = (known after apply) + deleted_time = (known after apply) + desc = (known after apply) + destruction_time = (known after apply) + detach = false + devicename = (known after apply) + disk_id = (known after apply) + disk_name = "disk-2" + disk_path = (known after apply) + gid = 212 + guid = (known after apply) + id = (known after apply) + image_id = (known after apply) + images = (known after apply) + iotune = (known after apply) + iqn = (known after apply) + login = (known after apply) + milestones = (known after apply) + order = (known after apply) + params = (known after apply) + parent_id = (known after apply) + passwd = (known after apply) + pci_slot = (known after apply) + permanently = false + pool = (known after apply) + purge_attempts = (known after apply) + purge_time = (known after apply) + reality_device_number = (known after apply) + reference_id = (known after apply) + res_id = (known after apply) + res_name = (known after apply) + restore = false + role = (known after apply) + sep_id = (known after apply) + sep_type = (known after apply) + size_max = 10 + size_used = (known after apply) + snapshots = (known after apply) + status = (known after apply) + tech_status = (known after apply) + timeouts = null + type = (known after apply) + vmid = (known after apply) } } ``` После подтверждения команды, будет создан файл состояния инфраструктуры, в который запишутся данные. ### Обращение к конфигурации, созданной с помощью for_each Получить доступ к ресурсам, созданным с помощью for_each можно по сл. схеме: ``` .[""] ``` Пример получения доступа к ресурсу disk-2: ``` dynamix_disk.disks["disk-2"] ``` Чтобы получить доступ к полям, которые содержит ресурс: ``` .[""]. ``` Например, для получения account_id для disk-2: ``` dynamix_disk.disks["disk-2"].account_id ``` ### Использование for_each для более сложной конфигурации Иногда, необходимо объединить несколько ресурсов с разной конфигурацией в один ресурс, с помощью for_each. Для того, чтобы это сделать, необходимо воспользоваться функцией for для перебора информации о каждом ресурсе, в котором так же необходимо указать какое из полей будет указывать на определенный ресурс. Рассмотрим более сложный пример создания нескольких дисков: ```terraform #создание массива из объектов, описывающих инфраструктуру locals { disks = [ { account_id = 777 diskname = "test-disk" disk2_gb = 100 gid = 212 }, { account_id = 778 diskname = "test-disk-1" disk2_gb = 200 gid = 213 } ] } resource "dynamix_disk" "disks" { #цикл for проходит по каждому элементы списка, превращая его в объект, где #ключом будет - имя диска #знаяением - сам диск for_each = { for disk in local.disks : disk.diskname => disk } #получение account_id каждого диска account_id = each.value.account_id #шаблон задания имени диска #так же, если не надо вносить изменения, можно использовать: #disk_name = each.value.diskname disk_name = "${each.value.diskname}-data" #получение размера диска size_max = each.value.disk2_gb #получение gid диска gid = each.value.gid } ``` Таким образом, будут созданы ресурсы с разной конфигурацией. ## Мета аргумент count Мета аргумент count так же служит для множественного создания ресурсов, объединяя их в один, с тем лишь исключением, что это будет массив, а не объект. Аргумент count принимает на вход либо число, либо выражение, которое возвращает число. Число - количество итерацией, которые предстоит произвести. Например: ```terraform count = 3 count = length(some_data) ``` Рассмотрим пример: ```terraform #без изменений locals { disk_names = [ "disk-1", "disk-2", ] } #без изменений, ресурс так же называется - "disks" resource "dynamix_disk" "disks" { #Используется функция length для подсчета длины списка имен дисков count = length(local.disk_names) account_id = 777 #аргумент count имеет поле index, которое возвращает индекс(счетчик) текущей итерации disk_name = local.disk_names[count.index] size_max = 10 gid = 212 } output "test" { value = dynamix_disk.disks } ``` При выполнении данной конфигурации в terraform output будет следующее: ``` Changes to Outputs: + test = [ + { + account_id = 777 + account_name = (known after apply) + acl = (known after apply) + boot_partition = (known after apply) + compute_id = (known after apply) + compute_name = (known after apply) + created_time = (known after apply) + deleted_time = (known after apply) + desc = (known after apply) + destruction_time = (known after apply) + detach = false + devicename = (known after apply) + disk_id = (known after apply) + disk_name = "disk-1" + disk_path = (known after apply) + gid = 212 + guid = (known after apply) + id = (known after apply) + image_id = (known after apply) + images = (known after apply) + iotune = (known after apply) + iqn = (known after apply) + login = (known after apply) + milestones = (known after apply) + order = (known after apply) + params = (known after apply) + parent_id = (known after apply) + passwd = (known after apply) + pci_slot = (known after apply) + permanently = false + pool = (known after apply) + purge_attempts = (known after apply) + purge_time = (known after apply) + reality_device_number = (known after apply) + reference_id = (known after apply) + res_id = (known after apply) + res_name = (known after apply) + restore = false + role = (known after apply) + sep_id = (known after apply) + sep_type = (known after apply) + size_max = 10 + size_used = (known after apply) + snapshots = (known after apply) + status = (known after apply) + tech_status = (known after apply) + timeouts = null + type = (known after apply) + vmid = (known after apply) }, + { + account_id = 777 + account_name = (known after apply) + acl = (known after apply) + boot_partition = (known after apply) + compute_id = (known after apply) + compute_name = (known after apply) + created_time = (known after apply) + deleted_time = (known after apply) + desc = (known after apply) + destruction_time = (known after apply) + detach = false + devicename = (known after apply) + disk_id = (known after apply) + disk_name = "disk-2" + disk_path = (known after apply) + gid = 212 + guid = (known after apply) + id = (known after apply) + image_id = (known after apply) + images = (known after apply) + iotune = (known after apply) + iqn = (known after apply) + login = (known after apply) + milestones = (known after apply) + order = (known after apply) + params = (known after apply) + parent_id = (known after apply) + passwd = (known after apply) + pci_slot = (known after apply) + permanently = false + pool = (known after apply) + purge_attempts = (known after apply) + purge_time = (known after apply) + reality_device_number = (known after apply) + reference_id = (known after apply) + res_id = (known after apply) + res_name = (known after apply) + restore = false + role = (known after apply) + sep_id = (known after apply) + sep_type = (known after apply) + size_max = 10 + size_used = (known after apply) + snapshots = (known after apply) + status = (known after apply) + tech_status = (known after apply) + timeouts = null + type = (known after apply) + vmid = (known after apply) }, ] ``` ### Обращение к конфигурации, созданной с помощью сount Получить доступ к ресурсам, созданным с помощью count можно по сл. схеме: ``` .[] ``` Пример получения доступа к ресурсу disk-2: ``` dynamix_disk.disks[1] ``` Чтобы получить доступ к полям, которые содержит ресурс: ``` .[]. ``` Например, для получения account_id для disk-2: ``` dynamix_disk.disks[1].account_id ``` ### Использование count для более сложной конфигурации Иногда, необходимо объединить несколько ресурсов с разной конфигурацией в один ресурс, с помощью count. Для того, чтобы это сделать, необходимо воспользоваться функцией length для установления длины входящих параметров. После чего, обращаться к ним, получая значения, используя индекс. Рассмотрим более сложный пример создания нескольких дисков: ```terraform #создание массива из объектов, описывающих инфраструктуру locals { disks = [ { account_id = 777 diskname = "test-disk" disk2_gb = 100 gid = 212 }, { account_id = 778 diskname = "test-disk-1" disk2_gb = 200 gid = 213 } ] } resource "dynamix_disk" "disks" { #получение значения длины входящих параметров count = length(local.disks) #получение идентификатора аккаунта account_id = local.disks[count.index].account_id #получение имени диска disk_name = "${local.disks[count.index].diskname}-data" #получение размера диска size_max = local.disks[count.index].disk2_gb #получение gid gid = local.disks[count.index].gid } ``` Таким образом, будут созданы ресурсы, с разной конфигурацией.