Invalid for_each argument: почему ключи ресурсов должны быть известны до apply
Конфигурация создаёт несколько объектов и затем ещё один ресурс для каждого их ID. Plan останавливается на Invalid for_each argument: значения ключей неизвестны до apply. Кажется, что достаточно добавить depends_on, но порядок зависимостей уже понятен. Проблема в другом: инструмент пока не может назвать адреса будущих экземпляров.
For_each создаёт адрес вида resource.name["key"]. Эти адреса нужны во время планирования, чтобы сопоставить конфигурацию со state и показать действия. Вычисляемое свойство может оставаться неизвестным, но набор ключей должен быть определим заранее.
Отделим имя worker от его ID
Следующий самостоятельный main.tf использует встроенный terraform_data, доступный в Terraform 1.4+ и OpenTofu. Он не обращается в облако и показывает тот же принцип: имена primary и backup известны в конфигурации, а ID источника вычисляются при создании.
locals {
workers = {
primary = "queue-a"
backup = "queue-b"
}
}
resource "terraform_data" "worker" {
for_each = local.workers
input = each.value
}
resource "terraform_data" "registration" {
for_each = local.workers
input = {
queue = each.value
worker_id = terraform_data.worker[each.key].id
}
}
output "registration_addresses" {
value = keys(terraform_data.registration)
}
Выберите terraform init и terraform plan либо tofu init и tofu plan в новом учебном каталоге. Ожидаются два worker и две registration. Адрес registration["primary"] известен, хотя worker_id внутри его input ещё будет known after apply. Выражение ссылки само создаёт зависимость, поэтому дополнительный depends_on не нужен.
Почему set из ID не работает
Если вместо local.workers передать toset из ID создаваемых worker, элементы множества одновременно становятся ключами экземпляров. Пока ID неизвестны, неизвестны и адреса registration. Преобразование toset убирает дубликаты и порядок, но не делает значения известными.
Исправление — map с заранее известными логическими именами. Вычисляемые ID помещают в значения этой map или используют в аргументах ресурса, как в примере. Это сохраняет идентичность: primary остаётся primary независимо от того, какой физический ID присвоит провайдер.
Набор ключей определяется не только выражением ключа, но и фильтром. Конструкция for с if по неизвестному после создания свойству тоже может оставить неизвестным сам состав map. В таком случае условие включения надо перенести в заранее известный вход либо изменить модель ресурсов.
Почему depends_on и target не являются общим исправлением
Depends_on говорит, что одну операцию нужно выполнить после другой. Но plan должен определить экземпляры до начала apply, поэтому отложенное вычисление ID не превращается в допустимые неизвестные ключи. Добавление зависимости иногда даже делает больше значений неизвестными на этапе плана.
Двухэтапный запуск с target может временно материализовать ID, после чего следующий plan сработает. Но конфигурация всё ещё не описывает полный первый запуск. При новом окружении или замене источника проблема вернётся. Разделение на независимые состояния оправдано отдельными жизненными циклами и владельцами, а не только желанием обойти неизвестный ключ.
Стабильные ключи должны быть безопасными для отображения
Ключи присутствуют в адресах и пользовательском выводе. Поэтому for_each не принимает sensitive-значения как обычный скрытый список идентификаторов. Не используйте токен или пароль в качестве имени экземпляра. Для адреса подходит несекретное логическое имя, а секрет остаётся свойством, переданным нужному аргументу.
Правила известных ключей и ограничений sensitive совпадают в базовом сценарии Terraform и OpenTofu. Версия провайдера определяет, какие именно свойства остаются неизвестными, поэтому при обновлении проверяйте итоговый plan, а не только тип выражения.
Для проверки добавьте third в local.workers: должны появиться только новые worker и registration с ключом third. Затем измените значение primary: адрес сохранится, а план покажет действия над его свойствами. Это подтверждает, что конфигурация различает логическую идентичность и вычисляемый результат создания.
Ещё по теме
- Удаление элемента списка пересоздаёт ресурсы: count и стабильные ключи for_each
- CI считает terraform plan ошибкой при найденных изменениях: detailed-exitcode
Продолжить изучение
Хотите управлять инфраструктурой через код и понимать последствия изменений? Plan, state, модули и работа с существующими ресурсами — темы программы «Terraform и OpenTofu: инфраструктура как код».
Продолжить на практике
- Terraform и OpenTofu: инфраструктура как код ↗
Описывайте инфраструктуру в коде, проверяйте изменения до применения и работайте со state без сюрпризов. HCL, модули, remote state, импорт, CI и различия Terraform/OpenTofu — на воспроизводимом учебном окружении.
