
Terraform — это Open source решение для управления IaC от компании Hashicorp, вышедшее в 2014 году. Terraform придерживается декларативного стиля управления инфраструктурой. Это значит, что вы описываете финальное состояние инфраструктуры в конфигурационном файле, а Terraform приводит её к нему. Достаточно написать конфигурацию, в которой будет изложено, как вы видите вашу будущую инфраструктуру, а главное, если описывать конфигурацию инфраструктуры в человеко-читаемом текстовом формате, то после применения данной конфигурации начинаются создаваться ресурсы в заранее определённых зависимостях.

Данный метод не позволяет использовать заранее определённую статическую конфигурацию разметки и подключения дисков.
Необходимо настроить подключение дисков в определённой последовательности, чтобы в дальнейшем с помощью Ansible, на дисках создать разделы и подмонтировать их в нужные папки.
Вариант без зависимостей
resource "vcd_vm_internal_disk" "server_disk_swap" { vapp_name = vcd_vm.server.vapp_name vm_name = vcd_vm.server.name vdc = vcd_vm.server.vdc bus_type = "paravirtual" size_in_mb = 51200 bus_number = 0 unit_number = 1 storage_profile = "VC7-SSD" } resource "vcd_vm_internal_disk" "server_disk_app" { vapp_name = vcd_vm.server.vapp_name vm_name = vcd_vm.server.name vdc = vcd_vm.server.vdc bus_type = "paravirtual" size_in_mb = 102500 bus_number = 0 unit_number = 2 storage_profile = "VC7-SSD" } resource "vcd_vm_internal_disk" "server_disk_db" { vapp_name = vcd_vm.server.vapp_name vm_name = vcd_vm.server.name vdc = vcd_vm.server.vdc bus_type = "paravirtual" size_in_mb = 204800 bus_number = 0 unit_number = 3 storage_profile = "VC7-SSD" }
Код для создания дисков без зависимостей
resource "vcd_vm_internal_disk" "disk_1" { unit_number = 1 } resource "vcd_vm_internal_disk" "disk_2" { unit_number = 2 } resource "vcd_vm_internal_disk" "disk_3" { unit_number = 3 }
Если использовать подобную конструкцию, тогда диски будут создаваться в случайной последовательности. В свойствах виртуальной машины у дисков будут правильные Unit Number, но не правильный Index. На хосте так же имена дисков будут не в той последовательности, которая необходима.
Решение со статическими зависимостями
resource "vcd_vm_internal_disk" "server_disk_swap" { vapp_name = vcd_vm.server.vapp_name vm_name = vcd_vm.server.name vdc = vcd_vm.server.vdc bus_type = "paravirtual" size_in_mb = 51200 bus_number = 0 unit_number = 1 storage_profile = "VC7-SSD" depends_on = [vcd_vm.server] } resource "vcd_vm_internal_disk" "server_disk_app" { vapp_name = vcd_vm.server.vapp_name vm_name = vcd_vm.server.name vdc = vcd_vm.server.vdc bus_type = "paravirtual" size_in_mb = 102500 bus_number = 0 unit_number = 2 storage_profile = "VC7-SSD" depends_on = [vcd_vm_internal_disk.server_disk_swap] } resource "vcd_vm_internal_disk" "server_disk_db" { vapp_name = vcd_vm.server.vapp_name vm_name = vcd_vm.server.name vdc = vcd_vm.server.vdc bus_type = "paravirtual" size_in_mb = 204800 bus_number = 0 unit_number = 3 storage_profile = "VC7-SSD" depends_on = [vcd_vm_internal_disk.server_disk_app] }
Решение со статическими зависимостями
resource "vcd_vm_internal_disk" "disk_1" { unit_number = 1 depends_on = [vcd_vm.vm] } resource "vcd_vm_internal_disk" "disk_2" { unit_number = 2 depends_on = [vcd_vm_internal_disk.disk_1] } resource "vcd_vm_internal_disk" "disk_3" { unit_number = 3 depends_on = [vcd_vm_internal_disk.disk_2] }
В данном решении указаны статические объекты, которые ссылаются на предыдущий элемент.
Если в переменную depends_on подставить какую-нибудь переменную, тогда получаем ошибку "A single static variable reference is
required: only attribute access and indexing with constant keys. No
calculations, function calls, template expressions, etc are allowed
here.". Использование
переменных depends_on запрещены из-за особенности построения структуры создания
ресурсов. Как видим на рисунке 2 диски создаются параллельно и ничего друг о
друге они не знают, т.к. находятся в параллельных ветках зависимостей.

depends_on = [vcd_vm.vm] - указывает, что необходимо ждать пока создастся виртуальная машина (можно эту зависимость не указывать, terraform сам распределяет очерёдность создания и он не создаст диск, пока не будет создана виртуальная машина
depends_on = [vcd_vm_internal_disk.disk_1] - указывает, что ждём пока не создастся ресурс vcd_vm_internal_disk.disk_1
depends_on = [vcd_vm_internal_disk.disk_2] - указывает, что ждём пока не создастся ресурс vcd_vm_internal_disk.disk_2

Это рабочий вариант, когда нам нужно создать не большое количество виртуальных машин, но когда их много, тогда код будет очень громоздкий и в нём будет очень сложно разобраться.
Решение с динамическими зависимостями
Для данного решения вынесем создание диска в отдельный модуль modules>disks>main.tf
resource "time_sleep" "wait" { depends_on = [var.vms] create_duration = "${var.sleep}s" } resource "vcd_vm_internal_disk" "disks" { vapp_name = var.vapp_name vm_name = var.vm_name vdc = var.vdc bus_type = var.bus_type size_in_mb = var.size_in_mb bus_number = 0 unit_number = var.unit_number storage_profile = "VC7-SSD" depends_on = [time_sleep.wait] }
Код модуля для создания дисков
Основной код ./main.tf
module "disks" { count = length(var.vcd_host.disks) source = "../disks" vapp_name = vcd_vm.vms.vapp_name vm_name = vcd_vm.vms.name vdc = vcd_vm.vms.vdc vms = vcd_vm.vms bus_type = var.vcd_host.disks[count.index].bus_type size_in_mb = var.vcd_host.disks[count.index].size_in_mb unit_number = count.index + 1 sleep = (30 * count.index) + 1 }
Решение с динамическими интервалами создания
Переменная откуда берётся список дисков (variables.tf)
disks = [ {bus_type = "paravirtual", size_in_mb = 51200}, {bus_type = "paravirtual", size_in_mb = 102400}, {bus_type = "paravirtual", size_in_mb = 204800} ]
Список необходимых дисков в определённой последовательности

Теперь с помощью цикла мы можем создать то количество дисков, которое нам необходимо, и в нужной последовательности. Если последовательность нарушается, тогда можно увеличить время ожидания с 30 до 60 и т.д.
module "disks" { count = length(var.vcd_vm.disks) size_in_mb = var.vcd_vm.disks[count.index] unit_number = count.index + 1 sleep = (30 * count.index) + 1 }
В модуле с помощь переменной sleep мы регулируем, когда начинать создание диска. Для таймера мы так же указываем, чтобы он не начинал отсчёт, пока не будет создана машина, указанная в переменной vcd_vm.
resource "time_sleep" "wait" { depends_on = [var.vcd_vm] create_duration = "${var.sleep}s" }
Заключение
Как видите, при создании ресурсов с помощью terraform есть определённые сложности для организации последовательности. Для разрешения этих сложностей можно использовать несколько вариантов. Для создания инфраструктуры, в которой более 50-ти машин, мне пригодился вариант с динамическими зависимостями, который очень сильно сократил и оптимизировал код. Надеюсь, данное решение пригодится тебе в работе.
Автор: Алексей Цветков.

