Строго типизировать переменную.
→Примитивы: `string`, `number`, `bool`. Коллекции: `list(<type>)`, `set(<type>)`, `map(<type>)`. Структурные: `object({...})`, `tuple([...])`. Используйте `any` только когда действительно полиморфно.
Источник↗
Ограничить `environment` до dev/staging/prod.
→`variable "environment" { validation { condition = contains(["dev","staging","prod"], var.environment); error_message = "..." } }`. Допускается несколько блоков `validation`; все должны пройти.
Источник↗
Вывести пароль базы данных так, чтобы он не отображался в `terraform output`.
→`output "db_password" { value = ...; sensitive = true }`. CLI показывает `(sensitive value)`. Все еще читается через `terraform output db_password` или `-json` (намеренно — для скриптов).
Источник↗
Вычислить значение один раз и повторно использовать его в нескольких ресурсах.
→`locals { common_tags = merge(var.tags, { Project = var.project }) }`. Ссылка как `local.common_tags`. Не может быть переопределено извне модуля.
Источник↗
Найти существующий AMI без управления им.
→`data "aws_ami" "ubuntu" { most_recent = true; filter { ... } }`. Read-only. Ссылка на атрибуты как `data.aws_ami.ubuntu.id`.
Источник↗
Создать N похожих ресурсов — выбрать `count` или `for_each`.
→`for_each` (с map или set), когда элементы имеют стабильную идентичность (имена регионов, ключи окружения). `count` для "мне нужно N копий, порядок не имеет значения, идентичность — это просто индекс". Добавление/удаление в середине `count` вызывает destroy/recreate; `for_each` сохраняет идентичность.
Источник↗
Создать один ресурс для каждого элемента в списке строк.
→`for_each = toset(["a", "b", "c"])`. `each.key` и `each.value` оба дают строку. Для maps: `for_each = var.users` — `each.key` = ключ map, `each.value` = значение map.
Источник↗
Генерировать переменное количество вложенных блоков (например, правил ingress).
→`dynamic "ingress" { for_each = var.rules; content { from_port = ingress.value.from; ... } }`. Аргумент `iterator` может переименовать итератор при необходимости.
Источник↗
Получить список атрибутов для всех экземпляров ресурса `count`.
→`aws_instance.web[*].id` возвращает список ID. Работает с `count` и `for_each` (но `for_each` производит неупорядоченную map, поэтому `values(aws_instance.web)[*].id`).
Источник↗
Установить значение на основе условия.
→Тернарный оператор: `var.is_prod ? 5 : 1`. Обе ветви должны производить один и тот же тип.
Источник↗
Объединить две map; значения второй map выигрывают при совпадении ключей.
→`merge(local.defaults, local.overrides)`. Правая map выигрывает. Полезно для композиции тегов.
Источник↗
Прочитать значение map с default-значением, если ключ отсутствует.
→`lookup(var.config, "region", "us-east-1")`. Возвращает default, если ключ отсутствует. Для глубоко опциональных структур предпочтительнее использовать `try()`.
Источник↗
Свернуть вложенные списки в плоский список.
→`flatten([["a","b"], ["c"], [["d","e"]]])` → `["a","b","c","d","e"]`. Рекурсивно сглаживает списки; сохраняет порядок.
Источник↗
Встроить Terraform map в IAM policy document.
→`jsonencode({Version = "2012-10-17", Statement = [...]})`. Производит JSON-строку. Обратное: `jsondecode()`.
Источник↗
Отобразить templated user-data скрипт со значениями из переменных.
→`templatefile("init.sh.tpl", { region = var.region, env = var.env })`. Шаблон использует синтаксис `${region}`. Более новая альтернатива для статической отрисовки: `file()` + `format()`.
Источник↗
Вырезать CIDR подсетей из диапазона VPC.
→`cidrsubnet("10.0.0.0/16", 8, 0)` → `10.0.0.0/24`. Первый аргумент = родительский, второй = биты для расширения, третий = номер подсети.
Источник↗
Считать значение, которое может не существовать; вернуться к default.
→`try(yamldecode(file("config.yaml")), { defaults = true })`. Оценивает слева направо; возвращает первое невызывающее ошибку выражение.
Источник↗
Итерировать по файлам, соответствующим glob.
→`fileset(path.module, "configs/*.json")` возвращает набор путей. Комбинируйте с `for_each` для управления одним ресурсом на файл.
Источник↗
Один и тот же провайдер в двух регионах (например, AWS us-east-1 + us-west-2).
→Два блока `provider "aws" { alias = "..." }`. Ресурсы подключаются через `provider = aws.us_west`. Модули принимают alias через `configuration_aliases`.
Источник↗
Запустить shell-команду на только что созданной VM.
→`remote-exec` provisioner внутри ресурса. Инструмент последней инстанции — предпочтительнее использовать cloud-init, user data или системы управления конфигурацией. Provisioners не отслеживаются в state и не перезапускаются при drift.
Источник↗
Выполнить команду, которая не соответствует облачному ресурсу (например, вызов CLI).
→`resource "null_resource" "trigger" { triggers = { sha = sha1(file(".")) }; provisioner "local-exec" { command = "..." } }`. Перезапускается при изменении `triggers`.
Источник↗
Непрерывная проверка runtime-инварианта (например, health endpoint возвращает 200) без блокировки apply.
→`check "endpoint" { data "http" "h" { url = "..." }; assert { condition = data.http.h.status_code == 200; error_message = "..." } }`. Запускается при plan/apply; сбой является предупреждением, а не жесткой ошибкой.
Почему: `check` позволяет использовать scoped data sources, доступные только внутри проверки. `precondition`/`postcondition` являются жесткими ошибками на этапе plan/apply.
Источник↗
Завершить plan с ошибкой, если AMI слишком стар.
→`lifecycle { precondition { condition = data.aws_ami.x.creation_date > "2024-01-01"; error_message = "..." } }`. Жесткий сбой, оценивается до/после по мере необходимости.
Источник↗
Переменная с позиционным значением фиксированной формы.
→`type = tuple([string, number, bool])` требует ровно три элемента в этом порядке. Отличается от списка (гомогенный, переменная длина).
Источник↗
Строго типизировать структурированный input (например, `database = { instance_class = string, allocated_storage = number }`).
→`type = object({ instance_class = string, allocated_storage = number, multi_az = optional(bool, false) })`. `optional(<type>, <default>)` делает атрибуты необязательными.
Источник↗
Как загружаются файлы `*.tfvars`?
→`terraform.tfvars` и `*.auto.tfvars` загружаются автоматически (лексический порядок для `auto`). Другие имена требуют `-var-file=path.tfvars`.
Источник↗
Написать автоматизированные тесты для модуля Terraform.
→Файлы `.tftest.hcl` с `run "name" { command = plan|apply, assert { condition = ..., error_message = ... } }`. `command = plan` без побочных эффектов; `command = apply` фактически создает ресурсы.
Источник↗
Передавать переменные в тестовые запуски.
→Блок `variables { ... }` на уровне файла применяется ко всем запускам. Блок `variables { ... }` для каждого запуска переопределяет только для этого запуска.
Источник↗