Обратите внимание на то, что у имени "morpheus" теперь индекс 1, а не 2. Terraform воспринимает индекс в качестве идентификатора ресурса, поэтому данное изменение можно перефразировать так: «переименовать элемент с индексом 1 в morpheus и удалить элемент с индексом 2». Иными словами, каждый раз, когда вы удаляете находящийся внутри списка ресурс, Terraform удаляет все ресурсы, которые следуют за ним, и воссоздает их заново, с нуля. Ох. Конечно, итоговым результатом будет именно то, о чем вы просили (то есть два пользователя IAM с именами "morpheus" и "neo"), но вряд ли вам хотелось бы достичь этого за счет удаления и изменения ресурсов.
Чтобы вы могли обойти эти два ограничения, в Terraform 0.12 появились выражения for_each.
Циклы с выражениями for_each
Выражение for_each позволяет выполнять циклический перебор списков, множеств и ассоциативных массивов с последующим созданием множественных копий либо всего ресурса, либо вложенного в него блока. Сначала рассмотрим первый вариант. Синтаксис выглядит так:
resource "
for_each =
[CONFIG ...]
}
PROVIDER — это имя провайдера (например, aws), TYPE — тип ресурса, который нужно создать в этом провайдере (скажем, instance), NAME — идентификатор, с помощью которого можно ссылаться на ресурс на разных участках кода Terraform (вроде my_instance), COLLECTION — множество или ассоциативный массив, который нужно перебрать в цикле (при использовании for_each в сочетании с ресурсом списки не поддерживаются), а CONFIG состоит из одного или нескольких аргументов, предназначенных специально для этого ресурса. Внутри CONFIG можно применять ссылки each.key и each.value для доступа к ключу и значению текущего элемента COLLECTION.
Например, так можно создать тех же трех пользователей IAM с помощью for_each:
resource "aws_iam_user" "example" {
for_each = toset(var.user_names)
name = each.value
}
Обратите внимание на функцию toset, которая превращает список var.user_names во множество. Дело в том, что выражение for_each поддерживает множества и ассоциативные массивы только для ресурсов. При переборе этого множества оно предоставляет имя каждого пользователя в виде each.value. То же самое значение будет доступно и в each.key, хотя эта ссылка обычно используется только в ассоциативных массивах с ключами и значениями.
Ресурс, к которому применяется for_each, становится ассоциативным массивом ресурсов (а не обычным массивом, как в случае с count). Чтобы это продемонстрировать, заменим оригинальные выходные переменные all_arns и neo_arn новой, all_users:
output "all_users" {
value = aws_iam_user.example
}
Вот что произойдет, если выполнить terraformapply:
$ terraform apply
(...)
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
all_users = {
"morpheus" = {
"arn" = "arn:aws:iam::123456789012:user/morpheus"
"force_destroy" = false
"id" = "morpheus"
"name" = "morpheus"
"path" = "/"
"tags" = {}
}
"neo" = {
"arn" = "arn:aws:iam::123456789012:user/neo"
"force_destroy" = false
"id" = "neo"
"name" = "neo"
"path" = "/"
"tags" = {}
}
"trinity" = {
"arn" = "arn:aws:iam::123456789012:user/trinity"
"force_destroy" = false
"id" = "trinity"
"name" = "trinity"
"path" = "/"
"tags" = {}
}
}
Как видите, Terraform создает трех пользователей IAM, а выходная переменная all_users содержит ассоциативный массив, ключи которого (в данном случае имена пользователей) используются в for_each, а значения служат выходными переменными этого ресурса. Если хотите вернуть выходную переменную all_arns, нужно приложить дополнительные усилия, чтобы извлечь соответствующие ARN, добавив встроенную функцию values (которая возвращает только значения ассоциативного массива) и символ *:
output "all_arns" {
value = values(aws_iam_user.example)[*].arn
}
Мы получим нужный нам вывод:
$ terraform apply
(...)
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
all_arns = [
"arn:aws:iam::123456789012:user/morpheus",
"arn:aws:iam::123456789012:user/neo",
"arn:aws:iam::123456789012:user/trinity",
]
Важно, что у вас теперь есть ассоциативный массив ресурсов с for_each вместо обычного массива ресурсов с count, так как теперь вы можете безопасно удалять его элементы. Например, если опять удалить "trinity" из списка var.user_names и выполнить terraformplan, результат будет следующим:
$ terraform plan
Terraform will perform the following actions:
# aws_iam_user.example["trinity"] will be destroyed
- resource "aws_iam_user" "example" {
- arn = "arn:aws:iam::123456789012:user/trinity" -> null
- name = "trinity" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.
Вот так-то лучше! Теперь вы удаляете только тот ресурс, который вам нужен, не смещая все вокруг. Вот почему для создания множественных копий ресурса почти всегда следует выбирать for_each вместо count.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии